source: trunk/src/sh_mounts.c@ 323

Last change on this file since 323 was 252, checked in by katerina, 15 years ago

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

File size: 19.6 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 sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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.