source: trunk/src/sh_mounts.c@ 149

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

Make sh_hash.c thread-safe, remove plenty of tiny allocations, improve sh_mem_dump, modify port check to run as thread, and fix unsetting of sh_thread_pause_flag (was too early).

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