source: trunk/src/sh_mounts.c @ 452

Last change on this file since 452 was 252, checked in by katerina, 12 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.