source: trunk/src/sh_mounts.c@ 201

Last change on this file since 201 was 184, checked in by katerina, 16 years ago

Fix compiling with --enable-mounts-check on FreeBSD 7.0 (ticket #123).

File size: 19.5 KB
Line 
1/*
2 * File: sh_mounts.c
3 * Desc: A module for Samhain; checks for mounts present and options on them.
4 * Auth: Cian Synnott <cian.synnott@eircom.net>
5 *
6 */
7/* This program is free software; you can redistribute it */
8/* and/or modify */
9/* it under the terms of the GNU General Public License as */
10/* published by */
11/* the Free Software Foundation; either version 2 of the License, or */
12/* (at your option) any later version. */
13/* */
14/* This program is distributed in the hope that it will be useful, */
15/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
16/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
17/* GNU General Public License for more details. */
18/* */
19/* You should have received a copy of the GNU General Public License */
20/* along with this program; if not, write to the Free Software */
21/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22
23#include "config_xor.h"
24
25
26/* Used in the call tracing macros to keep track of where we are in the code */
27#undef FIL__
28#define FIL__ _("sh_mounts.c")
29
30
31#include "samhain.h"
32#include "sh_utils.h"
33#include "sh_error.h"
34#include "sh_modules.h"
35#include "sh_mounts.h"
36
37#ifdef SH_USE_MOUNTS
38#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
39
40/*
41 * #ifdef HAVE_STRING_H
42 * #include <string.h>
43 * #endif
44 */
45
46#ifdef TM_IN_SYS_TIME
47#include <sys/time.h>
48#else
49#include <time.h>
50#endif
51
52/* Prototypes for configuration functions */
53int sh_mounts_config_activate (const char * opt);
54int sh_mounts_config_timer (const char * opt);
55int sh_mounts_config_mount (const char * opt);
56int sh_mounts_config_sevmnt (const char * opt);
57int sh_mounts_config_sevopt (const char * opt);
58
59/* Prototype for the function to read info on mounted filesystems */
60static struct sh_mounts_mnt *readmounts(void);
61
62/* Table for configuration options, and pointers to the functions that will
63 * configure them. Each function is passed the string resulting from stripping
64 * the option and the "equals" from the config file; e.g. MountCheckActive=1 in
65 * the configuration file will result in the string "1" being passed to
66 * sh_mounts_config_activate() */
67sh_rconf sh_mounts_table[] = {
68 {
69 N_("mountcheckactive"),
70 sh_mounts_config_activate
71 },
72 {
73 N_("mountcheckinterval"),
74 sh_mounts_config_timer
75 },
76 {
77 N_("checkmount"),
78 sh_mounts_config_mount
79 },
80 {
81 N_("severitymountmissing"),
82 sh_mounts_config_sevmnt
83 },
84 {
85 N_("severityoptionmissing"),
86 sh_mounts_config_sevopt
87 },
88 {
89 NULL,
90 NULL
91 },
92};
93
94/* Structures for storing my configuration information, and functions for
95 * manipulating them */
96struct sh_mounts_mnt {
97 char * path;
98 struct sh_mounts_opt * opts;
99 struct sh_mounts_mnt * next;
100};
101
102struct sh_mounts_opt {
103 char * opt;
104 struct sh_mounts_opt * next;
105};
106
107/* Return the mount structure whose path matches 'mnt' or NULL if not found */
108static
109struct sh_mounts_mnt *sh_mounts_mnt_member(struct sh_mounts_mnt *m, char *mnt)
110{
111 struct sh_mounts_mnt *it;
112
113 for (it = m; it != NULL; it = it->next) {
114 if (0 == sl_strcmp(it->path, mnt)) {
115 return it;
116 }
117 }
118 return NULL;
119}
120
121/* Return the opt structure whose option matches 'opt' or NULL if not found */
122static
123struct sh_mounts_opt *sh_mounts_opt_member(struct sh_mounts_opt *o, char *opt)
124{
125 struct sh_mounts_opt *it;
126
127 for (it = o; it != NULL; it = it->next) {
128 /* if (!strcmp(it->opt, opt)) { */
129 if (0 == sl_strcmp(it->opt, opt)) {
130 return it;
131 }
132 }
133 return NULL;
134}
135
136static
137void sh_mounts_opt_free(struct sh_mounts_opt *o) {
138 if (o != NULL) {
139 sh_mounts_opt_free(o->next);
140 SH_FREE(o->opt);
141 SH_FREE(o);
142 }
143}
144
145static
146void sh_mounts_mnt_free(struct sh_mounts_mnt *m) {
147 if (m != NULL) {
148 sh_mounts_mnt_free(m->next);
149 sh_mounts_opt_free(m->opts);
150 SH_FREE(m->path);
151 SH_FREE(m);
152 }
153}
154
155/* Some configuration variables I'll be using */
156static time_t lastcheck = (time_t) 0;
157static int ShMountsActive = S_FALSE;
158static time_t ShMountsInterval = 86400;
159static int ShMountsSevMnt = 7;
160static int ShMountsSevOpt = 7;
161
162static struct sh_mounts_mnt *mountlist = NULL;
163
164/* Module initialisation
165 * This is called once at the start of each samhain run.
166 * Non-configuration setup code should be placed here. */
167int sh_mounts_init (struct mod_type * arg)
168{
169 (void) arg;
170 SL_ENTER(_("sh_mounts_init"));
171
172 /* This is a little odd. Because we've built the configured mount list at
173 * this point, if we've set the module inactive, we need to free the list -
174 * otherwise when we reconf() with it set active, we'll end up with a
175 * duplicated list. Interesting. */
176 if (ShMountsActive == S_FALSE) {
177 sh_mounts_mnt_free(mountlist);
178 mountlist = NULL;
179 SL_RETURN(-1, _("sh_mounts_init"));
180 }
181
182 SL_RETURN(0, _("sh_mounts_init"));
183}
184
185/* Module timer
186 * This timer function is called periodically with the current time to see if
187 * it is time to run the module's "check" function. On nonzero return, the
188 * check is run. */
189int sh_mounts_timer (time_t tcurrent)
190{
191 SL_ENTER(_("sh_mounts_timer"));
192
193 if ((time_t) (tcurrent - lastcheck) >= ShMountsInterval) {
194 lastcheck = tcurrent;
195 SL_RETURN(-1, _("sh_mounts_timer"));
196 }
197
198 SL_RETURN(0, _("sh_mounts_timer"));
199}
200
201/* Module check
202 * The business end of things. This is the actual check code for this module.
203 * Everything you want to do periodically should go here. */
204int sh_mounts_check ()
205{
206 struct sh_mounts_mnt *memlist;
207 struct sh_mounts_mnt *cfgmnt, *mnt;
208 struct sh_mounts_opt *cfgopt, *opt;
209
210 SL_ENTER(_("sh_mounts_check"));
211
212 /* Log the check run. For each message type you want, you need to define it
213 * as an enum in sh_cat.h, and then set it up in terms of priority and format
214 * string in sh_cat.c */
215 sh_error_handle(-1, FIL__, __LINE__, 0, MSG_MNT_CHECK);
216
217 /* Read the list of mounts from memory */
218 memlist = readmounts();
219
220 if (memlist == NULL) {
221 sh_error_handle(-1, FIL__, __LINE__, 0, MSG_MNT_MEMLIST);
222 }
223
224 /* For each mount we are configured to check, run through the list of mounted
225 * filesystems and compare the pathnames */
226 for (cfgmnt = mountlist; cfgmnt != NULL; cfgmnt = cfgmnt->next) {
227 mnt = sh_mounts_mnt_member(memlist, cfgmnt->path);
228
229 if (mnt) {
230 for (cfgopt = cfgmnt->opts; cfgopt != NULL; cfgopt = cfgopt->next) {
231 opt = sh_mounts_opt_member(mnt->opts, cfgopt->opt);
232
233 if (!opt) {
234 sh_error_handle(ShMountsSevOpt, FIL__, __LINE__, 0, MSG_MNT_OPTMISS,
235 cfgmnt->path, cfgopt->opt);
236 }
237 }
238 }
239
240 else {
241 sh_error_handle(ShMountsSevMnt, FIL__, __LINE__, 0, MSG_MNT_MNTMISS,
242 cfgmnt->path);
243 }
244 }
245
246 /* Make sure to clean up after ourselves */
247 sh_mounts_mnt_free(memlist);
248
249 SL_RETURN(0, _("sh_mounts_check"));
250}
251
252/* Module cleanup
253 * The end of the tour - when samhain is shutting down, this is run. */
254int sh_mounts_cleanup ()
255{
256 SL_ENTER(_("sh_mounts_cleanup"));
257 sh_mounts_mnt_free(mountlist);
258 mountlist = NULL;
259 SL_RETURN( (0), _("sh_mounts_cleanup"));
260}
261
262/* Module reconfiguration
263 * Run on receipt of a HUP.
264 */
265int sh_mounts_reconf()
266{
267 SL_ENTER(_("sh_mounts_null"));
268 sh_mounts_mnt_free(mountlist);
269 mountlist = NULL;
270
271 /* re-set defaults
272 */
273 ShMountsActive = S_FALSE;
274 ShMountsInterval = 86400;
275 ShMountsSevMnt = 7;
276 ShMountsSevOpt = 7;
277
278 SL_RETURN( (0), _("sh_mounts_null"));
279}
280
281/* Module configuration
282 * These functions are called when the configuration file is being parsed. */
283
284/* Configure to check a particular mount */
285int sh_mounts_config_mount (const char * opt_in)
286{
287 struct sh_mounts_mnt *m;
288 struct sh_mounts_opt *o;
289 char *sp, *temp, *opt;
290
291 SL_ENTER(_("sh_mounts_config_mount"));
292
293 /* It's probably best to make a copy of opt before messing about with it
294 * via string functions. Good practice and all that. */
295 temp = sh_util_strdup(opt_in);
296
297 /* Since we're going to "consume" this new buffer, it'll be good to have a
298 * reference to it's allocated memory so we can free it later. Let's use
299 * temp for that, and "opt" for consumption */
300 opt = temp;
301
302 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof(struct sh_mounts_mnt));
303
304 /* First, strip out the mount path. */
305 m->path = sh_util_strdup(sh_util_strsep(&opt, " \t"));
306 m->opts = NULL;
307
308 /* Now get all of the mount options - they can be delimited by comma or
309 * whitespace */
310 while (opt != NULL) {
311 sp = sh_util_strsep(&opt, ", \t");
312
313 /* This just catches multiple separators appearing together */
314 if (*sp == '\0') {
315 continue;
316 }
317
318 o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
319 o->next = m->opts;
320 m->opts = o;
321
322 o->opt = sh_util_strdup(sp);
323 }
324
325 /* Add to the list of configured mounts */
326 m->next = mountlist;
327 mountlist = m;
328
329 /* Free the string buffer we allocated earlier */
330 SH_FREE(temp);
331
332 SL_RETURN(0, _("sh_mounts_config_mount"));
333}
334
335/* Simply sets our boolean as to whether this module is active */
336int sh_mounts_config_activate (const char * opt)
337{
338 int i;
339 SL_ENTER(_("sh_mounts_config_activate"));
340 i = sh_util_flagval(opt, &ShMountsActive);
341 SL_RETURN(i, _("sh_mounts_config_activate"));
342}
343
344/* Sets up our timer */
345int sh_mounts_config_timer (const char * opt)
346{
347 long val;
348 int retval = 0;
349
350 SL_ENTER(_("sh_mounts_config_timer"));
351 val = strtol (opt, (char **)NULL, 10);
352 if (val <= 0)
353 {
354 sh_error_handle (-1, FIL__, __LINE__, EINVAL, MSG_EINVALS,
355 _("mounts timer"), opt);
356 retval = -1;
357 }
358 val = (val <= 0 ? 86400 : val);
359
360 ShMountsInterval = (time_t) val;
361
362 SL_RETURN(retval, _("sh_mounts_config_timer"));
363}
364
365/* Configure severity for "mount missing" messages */
366int sh_mounts_config_sevmnt (const char * opt)
367{
368 int retval = 0;
369 char tmp[32];
370
371
372 SL_ENTER(_("sh_mounts_config_sevmnt"));
373 tmp[0] = '='; tmp[1] = '\0';
374 (void) sl_strlcat (tmp, opt, 32);
375 retval = sh_error_set_level (tmp, &ShMountsSevMnt);
376 SL_RETURN(retval, _("sh_mounts_config_sevmnt"));
377}
378
379int sh_mounts_config_sevopt (const char * opt)
380{
381 int retval = 0;
382 char tmp[32];
383
384 SL_ENTER(_("sh_mounts_config_sevopt"));
385 tmp[0] = '='; tmp[1] = '\0';
386 (void) sl_strlcat (tmp, opt, 32);
387 retval = sh_error_set_level (tmp, &ShMountsSevOpt);
388 SL_RETURN(retval, _("sh_mounts_config_sevopt"));
389}
390
391
392/*
393 * Below here we have the code for actually reading options on mounted fs's
394 * I've just got code here to work on FreeBSD, Linux and Solaris. I'm sure
395 * others could be added. Note that some small bits of the OS-specific code
396 * are from mountlist.c in GNU fileutils.
397 */
398
399/* FreeBSD includes */
400#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
401#include <sys/param.h>
402#include <sys/ucred.h>
403#include <sys/mount.h>
404#endif
405
406/* Linux includes */
407#ifdef HOST_IS_LINUX
408#include <stdio.h>
409#include <mntent.h>
410#endif
411
412/* Solaris includes */
413#ifdef HOST_IS_SOLARIS
414#include <stdio.h>
415#include <sys/mnttab.h>
416#endif
417
418/* HP_UX includes */
419#ifdef HOST_IS_HPUX
420#include <stdio.h>
421#include <mntent.h>
422#endif
423
424/* AIX includes and helper routines (from gnome-vfs-unix-mounts.c */
425#if 0
426#ifdef HOST_IS_AIX
427#include <stdio.h>
428#include <string.h>
429#include <ctype.h>
430
431/* gnome-vfs-unix-mounts.c - read and monitor fstab/mtab
432
433 Copyright (C) 2003 Red Hat, Inc
434
435 The Gnome Library is free software; you can redistribute it and/or
436 modify it under the terms of the GNU Library General Public License as
437 published by the Free Software Foundation; either version 2 of the
438 License, or (at your option) any later version.
439
440 The Gnome Library is distributed in the hope that it will be useful,
441 but WITHOUT ANY WARRANTY; without even the implied warranty of
442 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
443 Library General Public License for more details.
444
445 You should have received a copy of the GNU Library General Public
446 License along with the Gnome Library; see the file COPYING.LIB. If not,
447 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
448 Boston, MA 02111-1307, USA.
449
450 Author: Alexander Larsson <alexl@redhat.com>
451*/
452
453/* read character, ignoring comments (begin with '*', end with '\n' */
454static int aix_fs_getc (FILE *fd)
455{
456 int c;
457
458 while ((c = getc (fd)) == '*') {
459 while (((c = getc (fd)) != '\n') && (c != EOF)) {} /* do nothing */
460 }
461}
462
463/* eat all continuous spaces in a file */
464static int aix_fs_ignorespace (FILE *fd)
465{
466 int c;
467
468 while ((c = aix_fs_getc (fd)) != EOF) {
469 if (! (isascii(c) && isspace (c)) ) {
470 ungetc (c,fd);
471 return c;
472 }
473 }
474
475 return EOF;
476}
477
478/* read one word from file */
479static int aix_fs_getword (FILE *fd, char *word, int len)
480{
481 int c;
482 int i = 0;
483
484 --len;
485
486 aix_fs_ignorespace (fd);
487
488 while (((c = aix_fs_getc (fd)) != EOF) && !( isascii(c) && isspace(c) ))
489 {
490 if (c == '"')
491 {
492 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
493 {
494 *word++ = c; ++i;
495 if (i == len)
496 break;
497 }
498 }
499 else
500 {
501 *word++ = c; ++i;
502 }
503 if (i == len)
504 break;
505 }
506 *word = 0;
507
508 return c;
509}
510
511/* PATH_MAX is in sys/limits.h, included via stdio.h
512 */
513typedef struct {
514 char mnt_mount[PATH_MAX];
515 char mnt_special[PATH_MAX];
516 char mnt_fstype[16];
517 char mnt_options[128];
518} AixMountTableEntry;
519
520/* read mount points properties */
521static int aix_fs_get (FILE *fd, AixMountTableEntry *prop)
522{
523 /* Need space for PATH_MAX + ':' (terminating '\0' is in PATH_MAX; SUSv3)
524 */
525 static char word[PATH_MAX+1] = { 0 };
526 char value[PATH_MAX];
527
528 /* reset */
529
530 if (fd == NULL)
531 {
532 word[0] = '\0';
533 return 0;
534 }
535
536 /* read stanza */
537
538 if (word[0] == 0) {
539 if (aix_fs_getword (fd, word, (PATH_MAX+1)) == EOF)
540 return EOF;
541 }
542
543 word[strlen(word) - 1] = 0;
544 sl_strlcpy (prop->mnt_mount, word, PATH_MAX);
545
546 /* read attributes and value */
547
548 while (aix_fs_getword (fd, word, (PATH_MAX+1)) != EOF) {
549 /* test if is attribute or new stanza */
550
551 if (word[strlen(word) - 1] == ':') {
552 return 0;
553 }
554
555 /* read "=" */
556 aix_fs_getword (fd, value, PATH_MAX);
557
558 /* read value */
559 aix_fs_getword (fd, value, PATH_MAX);
560
561 if (strcmp (word, "dev") == 0) {
562 sl_strlcpy (prop->mnt_special, value, PATH_MAX);
563 } else if (strcmp (word, "vfs") == 0) {
564 sl_strlcpy (prop->mnt_fstype, value, 16);
565 } else if (strcmp (word, "options") == 0) {
566 sl_strlcpy(prop->mnt_options, value, 128);
567 }
568 }
569
570 return 0;
571}
572
573/* end AIX helper routines */
574#endif
575#endif
576
577#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
578
579/* FreeBSD returns flags instead of strings as mount options, so we'll convert
580 * them here. */
581static
582struct sh_mounts_opt * getoptlist(int flags) {
583 struct sh_mounts_opt *list, *o;
584 int i;
585
586 struct {char *opt; int flag;} table[] = {
587#ifdef MNT_RDONLY
588 {"ro", MNT_RDONLY},
589#endif
590#ifdef MNT_NOEXEC
591 {"noexec", MNT_NOEXEC},
592#endif
593#ifdef MNT_NOSUID
594 {"nosuid", MNT_NOSUID},
595#endif
596#ifdef MNT_NODEV
597 {"nodev", MNT_NODEV},
598#endif
599#ifdef MNT_SYNCHRONOUS
600 {"sync", MNT_SYNCHRONOUS},
601#endif
602#ifdef MNT_ASYNC
603 {"async", MNT_ASYNC},
604#endif
605#ifdef MNT_LOCAL
606 {"local", MNT_LOCAL},
607#endif
608#ifdef MNT_QUOTA
609 {"quota", MNT_QUOTA},
610#endif
611#ifdef MNT_NOATIME
612 {"noatime", MNT_NOATIME},
613#endif
614 {"bound", -1}
615 };
616
617 SL_ENTER(_("getoptlist"));
618
619 list = NULL;
620
621 /* Add any flags found to the list */
622 for (i = 0; table[i].flag != -1; i++) {
623 if (flags & table[i].flag) {
624 o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
625 o->opt = sh_util_strdup(table[i].opt);
626 o->next = list;
627 list = o;
628 }
629 }
630
631 SL_RETURN(list, _("getoptlist"));
632}
633
634/* Solaris & Linux return identical option string formats */
635#else
636
637/* We just separate the options out by parsing for commas */
638static
639struct sh_mounts_opt * getoptlist(char *opt)
640{
641 struct sh_mounts_opt *list, *o;
642 char *sp, *temp;
643
644 SL_ENTER(_("getoptlist"));
645
646 /* See the comments in sh_mounts_config_mount() above for the reasons for
647 * this arcane little zig-zag */
648 temp = sh_util_strdup(opt);
649 opt = temp;
650
651 list = NULL;
652
653 /* For each option, add to the list */
654 while (opt != NULL) {
655 sp = sh_util_strsep(&opt, ", \t");
656
657 if (*sp == '\0') {
658 continue;
659 }
660
661 o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
662 o->next = list;
663 list = o;
664
665 o->opt = sh_util_strdup(sp);
666 }
667
668 SH_FREE(temp);
669
670 SL_RETURN(list, _("getoptlist"));
671}
672
673#endif
674
675/* Read the list of mounts from whereever is appropriate to the OS and return
676 * it. Return NULL on error. */
677static struct sh_mounts_mnt * readmounts(void) {
678 struct sh_mounts_mnt *list, *m;
679
680 SL_ENTER(_("readmounts"));
681 m = NULL; /* use it to avoid compiler warning */
682 list = m;
683
684/* The Open/FreeBSD way */
685#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
686{
687 struct statfs *fsp;
688 int entries;
689
690 entries = getmntinfo(&fsp, MNT_NOWAIT);
691 if (entries < 0) {
692 SL_RETURN((NULL), _("readmounts"));
693 }
694
695 for (; entries-- > 0; fsp++) {
696 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
697 m->path = sh_util_strdup(fsp->f_mntonname);
698 m->opts = getoptlist(fsp->f_flags);
699
700 m->next = list;
701 list = m;
702 }
703}
704#endif
705
706/* The Linux way */
707#ifdef HOST_IS_LINUX
708{
709 struct mntent *mp;
710 FILE *tab = setmntent(_PATH_MOUNTED, "r");
711
712 if (tab == NULL) {
713 SL_RETURN((NULL), _("readmounts"));
714 }
715
716 mp = getmntent(tab);
717 while (mp != NULL) {
718 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
719 m->path = sh_util_strdup(mp->mnt_dir);
720 m->opts = getoptlist(mp->mnt_opts);
721
722 m->next = list;
723 list = m;
724
725 mp = getmntent(tab);
726 }
727
728 (void) endmntent(tab);
729}
730#endif
731
732/* The Solaris way */
733#ifdef HOST_IS_SOLARIS
734{
735 struct mnttab mp;
736 FILE *tab = fopen(MNTTAB, "r");
737
738 if (tab == NULL) {
739 SL_RETURN((NULL), _("readmounts"));
740 }
741
742 while (!getmntent(tab, &mp)) {
743 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
744 m->path = sh_util_strdup(mp.mnt_mountp);
745 m->opts = getoptlist(mp.mnt_mntopts);
746
747 m->next = list;
748 list = m;
749 }
750
751 fclose(tab);
752}
753#endif
754
755
756/* The HP-UX way */
757#ifdef HOST_IS_HPUX
758{
759 struct mntent *mp;
760 FILE *tab = setmntent(MNT_MNTTAB, "r");
761
762 if (tab == NULL) {
763 SL_RETURN((NULL), _("readmounts"));
764 }
765
766 mp = getmntent(tab);
767 while (mp != NULL) {
768 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
769 m->path = sh_util_strdup(mp->mnt_dir);
770 m->opts = getoptlist(mp->mnt_opts);
771
772 m->next = list;
773 list = m;
774
775 mp = getmntent(tab);
776 }
777
778 (void) endmntent(tab);
779}
780#endif
781
782/* The AIX way */
783#if 0
784#ifdef HOST_IS_AIX
785{
786 AixMountTableEntry mntent;
787 FILE *tab = fopen("/etc/filesystems", "r");
788
789 if (tab == NULL) {
790 SL_RETURN((NULL), _("readmounts"));
791 }
792
793 while (!aix_fs_get (tab, &mntent))
794 {
795 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
796 m->path = sh_util_strdup(mntent.mnt_mount);
797 m->opts = getoptlist(mntent.mnt_options);
798
799 m->next = list;
800 list = m;
801
802 mntent.mnt_mount[0] = '\0';
803 mntent.mnt_special[0] = '\0';
804 mntent.mnt_fstype[0] = '\0';
805 mntent.mnt_options[0] = '\0';
806 }
807
808 (void) fclose(tab);
809 aix_fs_get (NULL, NULL); /* reset */
810}
811#endif
812#endif
813
814 SL_RETURN((list), _("readmounts"));
815
816}
817
818
819/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
820#endif
821
822/* #ifdef SH_USE_MOUNTS */
823#endif
824
Note: See TracBrowser for help on using the repository browser.