source: trunk/src/sh_mounts.c@ 183

Last change on this file since 183 was 169, checked in by katerina, 17 years ago

Fixes for tickes #93 to #104 (yes, big commit, bad, bad,...).

File size: 19.3 KB
RevLine 
[1]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 */
[68]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);
[1]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. */
[140]167int sh_mounts_init (struct mod_type * arg)
[1]168{
[140]169 (void) arg;
[1]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 }
[169]197
[1]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
[149]263 * Run on receipt of a HUP.
264 */
[1]265int sh_mounts_reconf()
266{
267 SL_ENTER(_("sh_mounts_null"));
268 sh_mounts_mnt_free(mountlist);
269 mountlist = NULL;
[149]270
271 /* re-set defaults
272 */
273 ShMountsActive = S_FALSE;
274 ShMountsInterval = 86400;
275 ShMountsSevMnt = 7;
276 ShMountsSevOpt = 7;
277
[1]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 */
[68]285int sh_mounts_config_mount (const char * opt_in)
[1]286{
287 struct sh_mounts_mnt *m;
288 struct sh_mounts_opt *o;
[68]289 char *sp, *temp, *opt;
[1]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. */
[68]295 temp = sh_util_strdup(opt_in);
[1]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
[68]299 * temp for that, and "opt" for consumption */
[1]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 */
[68]336int sh_mounts_config_activate (const char * opt)
[1]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 */
[68]345int sh_mounts_config_timer (const char * opt)
[1]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 */
[68]366int sh_mounts_config_sevmnt (const char * opt)
[1]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
[68]379int sh_mounts_config_sevopt (const char * opt)
[1]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 */
[169]400#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
[1]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)) == '*') {
[34]459 while (((c = getc (fd)) != '\n') && (c != EOF)) {} /* do nothing */
[1]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
[169]577#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
[1]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 {"ro", MNT_RDONLY},
588 {"noexec", MNT_NOEXEC},
589 {"nosuid", MNT_NOSUID},
590 {"nodev", MNT_NODEV},
591 {"sync", MNT_SYNCHRONOUS},
592 {"async", MNT_ASYNC},
593 {"local", MNT_LOCAL},
594 {"quota", MNT_QUOTA},
[169]595#ifdef MNT_NOATIME
596 {"noatime", MNT_NOATIME},
597#endif
[1]598 {"bound", -1}
599 };
600
601 SL_ENTER(_("getoptlist"));
602
603 list = NULL;
604
605 /* Add any flags found to the list */
606 for (i = 0; table[i].flag != -1; i++) {
607 if (flags & table[i].flag) {
608 o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
609 o->opt = sh_util_strdup(table[i].opt);
610 o->next = list;
611 list = o;
612 }
613 }
614
615 SL_RETURN(list, _("getoptlist"));
616}
617
618/* Solaris & Linux return identical option string formats */
619#else
620
621/* We just separate the options out by parsing for commas */
622static
623struct sh_mounts_opt * getoptlist(char *opt)
624{
625 struct sh_mounts_opt *list, *o;
626 char *sp, *temp;
627
628 SL_ENTER(_("getoptlist"));
629
630 /* See the comments in sh_mounts_config_mount() above for the reasons for
631 * this arcane little zig-zag */
632 temp = sh_util_strdup(opt);
633 opt = temp;
634
635 list = NULL;
636
637 /* For each option, add to the list */
638 while (opt != NULL) {
639 sp = sh_util_strsep(&opt, ", \t");
640
641 if (*sp == '\0') {
642 continue;
643 }
644
645 o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
646 o->next = list;
647 list = o;
648
649 o->opt = sh_util_strdup(sp);
650 }
651
652 SH_FREE(temp);
653
654 SL_RETURN(list, _("getoptlist"));
655}
656
657#endif
658
659/* Read the list of mounts from whereever is appropriate to the OS and return
660 * it. Return NULL on error. */
661static struct sh_mounts_mnt * readmounts(void) {
662 struct sh_mounts_mnt *list, *m;
663
664 SL_ENTER(_("readmounts"));
665 m = NULL; /* use it to avoid compiler warning */
666 list = m;
667
[169]668/* The Open/FreeBSD way */
669#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
[1]670{
671 struct statfs *fsp;
672 int entries;
673
674 entries = getmntinfo(&fsp, MNT_NOWAIT);
675 if (entries < 0) {
676 SL_RETURN((NULL), _("readmounts"));
677 }
678
679 for (; entries-- > 0; fsp++) {
680 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
681 m->path = sh_util_strdup(fsp->f_mntonname);
682 m->opts = getoptlist(fsp->f_flags);
683
684 m->next = list;
685 list = m;
686 }
687}
688#endif
689
690/* The Linux way */
691#ifdef HOST_IS_LINUX
692{
693 struct mntent *mp;
694 FILE *tab = setmntent(_PATH_MOUNTED, "r");
695
696 if (tab == NULL) {
697 SL_RETURN((NULL), _("readmounts"));
698 }
699
700 mp = getmntent(tab);
701 while (mp != NULL) {
702 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
703 m->path = sh_util_strdup(mp->mnt_dir);
704 m->opts = getoptlist(mp->mnt_opts);
705
706 m->next = list;
707 list = m;
708
709 mp = getmntent(tab);
710 }
711
712 (void) endmntent(tab);
713}
714#endif
715
716/* The Solaris way */
717#ifdef HOST_IS_SOLARIS
718{
719 struct mnttab mp;
720 FILE *tab = fopen(MNTTAB, "r");
721
722 if (tab == NULL) {
723 SL_RETURN((NULL), _("readmounts"));
724 }
725
726 while (!getmntent(tab, &mp)) {
727 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
728 m->path = sh_util_strdup(mp.mnt_mountp);
729 m->opts = getoptlist(mp.mnt_mntopts);
730
731 m->next = list;
732 list = m;
733 }
734
735 fclose(tab);
736}
737#endif
738
739
740/* The HP-UX way */
741#ifdef HOST_IS_HPUX
742{
743 struct mntent *mp;
744 FILE *tab = setmntent(MNT_MNTTAB, "r");
745
746 if (tab == NULL) {
747 SL_RETURN((NULL), _("readmounts"));
748 }
749
750 mp = getmntent(tab);
751 while (mp != NULL) {
752 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
753 m->path = sh_util_strdup(mp->mnt_dir);
754 m->opts = getoptlist(mp->mnt_opts);
755
756 m->next = list;
757 list = m;
758
759 mp = getmntent(tab);
760 }
761
762 (void) endmntent(tab);
763}
764#endif
765
766/* The AIX way */
767#if 0
768#ifdef HOST_IS_AIX
769{
770 AixMountTableEntry mntent;
771 FILE *tab = fopen("/etc/filesystems", "r");
772
773 if (tab == NULL) {
774 SL_RETURN((NULL), _("readmounts"));
775 }
776
777 while (!aix_fs_get (tab, &mntent))
778 {
779 m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
780 m->path = sh_util_strdup(mntent.mnt_mount);
781 m->opts = getoptlist(mntent.mnt_options);
782
783 m->next = list;
784 list = m;
785
786 mntent.mnt_mount[0] = '\0';
787 mntent.mnt_special[0] = '\0';
788 mntent.mnt_fstype[0] = '\0';
789 mntent.mnt_options[0] = '\0';
790 }
791
792 (void) fclose(tab);
793 aix_fs_get (NULL, NULL); /* reset */
794}
795#endif
796#endif
797
798 SL_RETURN((list), _("readmounts"));
799
800}
801
802
803/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
804#endif
805
806/* #ifdef SH_USE_MOUNTS */
807#endif
808
Note: See TracBrowser for help on using the repository browser.