Bug Summary

File:obj-scan-build/sutils/../../sutils/fstab.c
Location:line 506, column 9
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/* Fstab filesystem frobbing
2
3 Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
4
5 Written by Miles Bader <miles@gnu.ai.mit.edu>
6
7 This file is part of the GNU Hurd.
8
9 The GNU Hurd is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2, or (at
12 your option) any later version.
13
14 The GNU Hurd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 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 <stdlib.h>
24#include <unistd.h>
25#include <stdio.h>
26#include <errno(*__errno_location ()).h>
27#include <fcntl.h>
28#include <error.h>
29#include <argz.h>
30#include <argp.h>
31#include <fnmatch.h>
32
33#include <hurd/fsys.h>
34
35#include "fstab.h"
36
37extern error_t fsys_set_readonly (fsys_t fsys, int readonly);
38extern error_t fsys_get_readonly (fsys_t fsys, int *readonly);
39extern error_t fsys_update (fsys_t fsys);
40
41extern file_t file_name_lookup_carefully (const char *file,
42 int flags, mode_t mode);
43
44/* Return a new fstab in FSTAB. */
45error_t
46fstab_create (struct fstypes *types, struct fstab **fstab)
47{
48 struct fstab *new = malloc (sizeof (struct fstab));
49 if (new)
50 {
51 new->entries = 0;
52 new->types = types;
53 *fstab = new;
54 return 0;
55 }
56 else
57 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
58}
59
60/* Free FSTAB and all of its entries. */
61void
62fstab_free (struct fstab *fstab)
63{
64 while (fstab->entries)
65 fs_free (fstab->entries);
66 free (fstab);
67}
68
69/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */
70error_t
71fstypes_create (const char *search_fmts, size_t search_fmts_len,
72 struct fstypes **types)
73{
74 struct fstypes *new = malloc (sizeof (struct fstypes));
75 if (new)
76 {
77 new->entries = 0;
78 new->program_search_fmts = malloc (search_fmts_len);
79 new->program_search_fmts_len = search_fmts_len;
80 if (! new->program_search_fmts)
81 {
82 free (types);
83 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
84 }
85 bcopy (search_fmts, new->program_search_fmts, search_fmts_len);
86 *types = new;
87 return 0;
88 }
89 else
90 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
91}
92
93/* Return an fstype entry in TYPES called NAME, in FSTYPE. If there is no
94 existing entry, an attempt to find a fsck program with the given type,
95 using the alternatives in the FSCK_SEARCH_FMTS field in TYPES. If
96 one is found, it is added to TYPES, otherwise an new entry is created
97 with a NULL PROGRAM field. */
98error_t
99fstypes_get (struct fstypes *types, const char *name, struct fstype **fstype)
100{
101 char *fmts, *fmt;
102 size_t fmts_len;
103 struct fstype *type;
104 char *program = 0;
105
106 for (type = types->entries; type; type = type->next)
107 if (strcasecmp (type->name, name) == 0)
108 {
109 *fstype = type;
110 return 0;
111 }
112
113 /* No existing entry, make a new one. */
114
115 fmts = types->program_search_fmts;
116 fmts_len = types->program_search_fmts_len;
117
118 for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
119 {
120 int fd;
121
122 asprintf (&program, fmt, name);
123 fd = open (program, O_EXEC0x0004);
124 if (fd < 0)
125 {
126 free (program); /* Failed. */
127 if (errno(*__errno_location ()) != ENOENT((0x10 << 26) | ((2) & 0x3fff)) && errno(*__errno_location ()) != EACCES((0x10 << 26) | ((13) & 0x3fff)))
128 /* The program's there but something went wrong; fail. */
129 return errno(*__errno_location ());
130 }
131 else
132 /* We can open for exec, but check the stat info too (e.g. root can
133 open everything). */
134 {
135 struct stat stat;
136 int rv = fstat (fd, &stat);
137
138 close (fd);
139
140 if (rv < 0)
141 {
142 free (program);
143 return errno(*__errno_location ());
144 }
145
146 if (stat.st_mode & S_IXUSR00100)
147 /* Yup execute bit is set. This must be a program... */
148 break;
149
150 free (program);
151 }
152
153 program = 0;
154 }
155
156 type = malloc (sizeof (struct fstype));
157 if (! type)
158 {
159 free (program);
160 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
161 }
162
163 type->name = strdup (name);
164 if (type->name == 0)
165 {
166 free (type);
167 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
168 }
169 type->program = program;
170 type->next = types->entries;
171 types->entries = type;
172
173 *fstype = type;
174
175 return 0;
176}
177
178#if 0
179/* XXX nice idea, but not that useful since scanf's %s always eats all
180 non-ws, and it seems a bit overkill to convert it to a .+ regexp match */
181error_t
182fstypes_find_program (struct fstypes *types, const char *program,
183 struct fstype **fstype)
184{
185 char *fmts, *fmt;
186 size_t fmts_len;
187 struct fstype *type;
188 char *typename;
189
190 /* First see if a known type matches this program. */
191 for (type = types->entries; type; type = type->next)
192 if (type->program && !strcmp (type->program, program))
193 {
194 *fstype = type;
195 return 0;
196 }
197
198 /* No existing entry, see if we can make a new one. */
199
200 typename = alloca (strlen (program) + 1)__builtin_alloca (strlen (program) + 1);
201
202 fmts = types->program_search_fmts;
203 fmts_len = types->program_search_fmts_len;
204 for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
205 /* XXX this only works for trailing %s */
206 if (sscanf (program, fmt, typename) == 1)
207 {
208 /* This format matches the program and yields the type name.
209 Create a new entry for this type. */
210
211 type = malloc (sizeof (struct fstype));
212 if (! type)
213 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
214 type->name = strdup (typename);
215 if (type->name == 0)
216 {
217 free (type);
218 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
219 }
220 type->program = strdup (program);
221 if (type->program == 0)
222 {
223 free (type->name);
224 free (type);
225 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
226 }
227 type->next = types->entries;
228 types->entries = type;
229
230 *fstype = type;
231 return 0;
232 }
233
234 /* We could find no program search format that could have yielded this
235 program name. */
236 *fstype = 0;
237 return 0;
238}
239#endif
240
241/* Copy MNTENT into FS, copying component strings as well. */
242error_t
243fs_set_mntent (struct fs *fs, const struct mntent *provided_mntent)
244{
245 char *end;
246 size_t needed = 0;
247 struct mntent mntent = *provided_mntent;
248 char *real_fsname = NULL((void*)0);
249 char *real_dir = NULL((void*)0);
250
251 if (fs->storage)
252 free (fs->storage);
253
254 if (mntent.mnt_fsname)
255 {
256 real_fsname = realpath (mntent.mnt_fsname, NULL((void*)0));
257 if (real_fsname)
258 mntent.mnt_fsname = real_fsname;
259 }
260 if (mntent.mnt_dir)
261 {
262 real_dir = realpath (mntent.mnt_dir, NULL((void*)0));
263 if (real_dir)
264 mntent.mnt_dir = real_dir;
265 }
266
267 /* Allocate space for all string mntent fields in FS. */
268#define COUNT(field) if (mntent.field) needed += strlen (mntent.field) + 1;
269 COUNT (mnt_fsname);
270 COUNT (mnt_dir);
271 COUNT (mnt_type);
272 COUNT (mnt_opts);
273#undef COUNT
274
275 fs->storage = malloc (needed);
276 if (! fs->storage)
277 {
278 free (real_fsname);
279 free (real_dir);
280 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
281 }
282
283 if (!fs->mntent.mnt_dir || !mntent.mnt_dir
284 || strcmp (fs->mntent.mnt_dir, mntent.mnt_dir) != 0)
285 {
286 fs->mounted = fs->readonly = -1;
287 if (fs->fsys != MACH_PORT_NULL((mach_port_t) 0))
288 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fs->fsys);
289 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
290 }
291
292 /* Copy MNTENT into FS; string-valued fields will be fixed up next. */
293 fs->mntent = mntent;
294
295 /* Copy each mntent field from MNTENT into FS's version. */
296 end = fs->storage;
297#define STORE(field) \
298 if (mntent.field) \
299 { \
300 fs->mntent.field = end; \
301 end = stpcpy (end, mntent.field) + 1; \
302 } \
303 else \
304 fs->mntent.field = 0;
305 STORE (mnt_fsname);
306 STORE (mnt_dir);
307 STORE (mnt_type);
308 STORE (mnt_opts);
309#undef STORE
310
311 if (fs->type
312 && (!mntent.mnt_type
313 || strcasecmp (fs->type->name, mntent.mnt_type) != 0))
314 fs->type = 0; /* Type is different. */
315
316 free (real_fsname);
317 free (real_dir);
318
319 return 0;
320}
321
322/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
323 necessary. */
324error_t
325fs_type (struct fs *fs, struct fstype **type)
326{
327 error_t err = 0;
328 if (! fs->type)
329 err = fstypes_get (fs->fstab->types, fs->mntent.mnt_type, &fs->type);
330 if (! err)
331 *type = fs->type;
332 return err;
333}
334
335/* Looks to see if FS is currently mounted, being very careful to avoid
336 mounting anything that's not already, and fills in the fsys & mounted
337 fields in FS. */
338static error_t
339_fs_check_mounted (struct fs *fs)
340{
341 error_t err = 0;
342
343 if (fs->mounted < 0)
344 /* The mounted field in FS is -1 if we're not sure. */
345 {
346 if (fs->fsys != MACH_PORT_NULL((mach_port_t) 0))
347 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fs->fsys);
348
349 if (strcmp (fs->mntent.mnt_dir, "/") == 0)
350 /* The root is always mounted. Get its control port. */
351 {
352 file_t root = getcrdir ();
353 if (root == MACH_PORT_NULL((mach_port_t) 0))
354 err = errno(*__errno_location ());
355 else
356 {
357 err = file_getcontrol (root, &fs->fsys);
358 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), root);
359 }
360 }
361 else
362 {
363 file_t mount_point =
364 file_name_lookup_carefully (fs->mntent.mnt_dir, O_NOTRANS0x0080, 0);
365
366 if (mount_point != MACH_PORT_NULL((mach_port_t) 0))
367 /* The node exists. Is it the root of an active translator?
368 [Note that it could be a different translator than the one in
369 the mntent, but oh well, nothing we can do about that.] */
370 {
371 err = file_get_translator_cntl (mount_point, &fs->fsys);
372 if (err == EINVAL((0x10 << 26) | ((22) & 0x3fff)) || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)) || err == ENXIO((0x10 << 26) | ((6) & 0x3fff)))
373 /* Either the mount point doesn't exist, or wasn't mounted. */
374 {
375 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
376 err = 0;
377 }
378 }
379 else if (errno(*__errno_location ()) == ENXIO((0x10 << 26) | ((6) & 0x3fff)))
380 /* Ran into an inactive passive translator. FS can't be mounted. */
381 {
382 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
383 err = 0;
384 }
385 }
386
387 if (! err)
388 fs->mounted = (fs->fsys != MACH_PORT_NULL((mach_port_t) 0));
389 }
390
391 return err;
392}
393
394/* Looks to see if FS is currently mounted, being very careful to avoid
395 mounting anything that's not already, and returns the control port for the
396 mounted filesystem (MACH_PORT_NULL if not mounted). */
397error_t
398fs_fsys (struct fs *fs, fsys_t *fsys)
399{
400 error_t err = _fs_check_mounted (fs);
401 if (!err && fsys)
402 *fsys = fs->fsys;
403 return err;
404}
405
406/* Looks to see if FS is currently mounted, being very careful to avoid
407 mounting anything that's not already, and returns the boolean MOUNTED. */
408error_t
409fs_mounted (struct fs *fs, int *mounted)
410{
411 error_t err = _fs_check_mounted (fs);
412 if (!err && mounted)
413 *mounted = fs->mounted;
414 return err;
415}
416
417/* Looks to see if FS is currently mounted readonly, being very careful to
418 avoid mounting anything that's not already, and returns the boolean
419 READONLY. If FS isn't mounted at all, READONLY is set to 1 (it's not
420 going to write anything!). */
421error_t
422fs_readonly (struct fs *fs, int *readonly)
423{
424 error_t err = 0;
425
426 if (fs->readonly < 0)
427 /* Unknown. */
428 {
429 fsys_t fsys;
430
431 err = fs_fsys (fs, &fsys);
432 if (! err)
433 {
434 if (fsys == MACH_PORT_NULL((mach_port_t) 0))
435 fs->readonly = 1;
436 else
437 err = fsys_get_readonly (fsys, &fs->readonly);
438 }
439 }
440
441 if (!err && readonly)
442 *readonly = fs->readonly;
443
444 return err;
445}
446
447/* If FS is currently mounted writable, try to make it readonly. XXX If FS
448 is not mounted at all, then nothing is done. */
449error_t
450fs_set_readonly (struct fs *fs, int readonly)
451{
452 int currently_readonly;
453 error_t err = fs_readonly (fs, &currently_readonly);
454
455 readonly = !!readonly;
456
457 if (!err && readonly != currently_readonly)
458 /* We have to try and change the readonly state. */
459 {
460 fsys_t fsys;
461 err = fs_fsys (fs, &fsys);
462 if (!err && fsys != MACH_PORT_NULL((mach_port_t) 0)) /* XXX What to do if not mounted? */
463 err = fsys_set_readonly (fsys, readonly);
464 if (! err)
465 fs->readonly = readonly;
466 }
467
468 return err;
469}
470
471/* If FS is currently mounted tell it to remount the device. XXX If FS is
472 not mounted at all, then nothing is done. */
473error_t
474fs_remount (struct fs *fs)
475{
476 fsys_t fsys;
477 error_t err = fs_fsys (fs, &fsys);
478 if (!err && fsys != MACH_PORT_NULL((mach_port_t) 0)) /* XXX What to do if not mounted? */
479 err = fsys_update (fsys);
480 return err;
481}
482
483/* Returns the FS entry in FSTAB with the device field NAME.
484
485 In general there can only be one such entry. This holds not true
486 for virtual file systems that use "none" as device name.
487
488 If name is "none", NULL is returned. This also makes it possible to
489 add more than one entry for the device "none". */
490inline struct fs *
491fstab_find_device (const struct fstab *fstab, const char *name)
492{
493 if (strcmp (name, "none") == 0)
20
Taking false branch
494 return NULL((void*)0);
495
496 char *real_name = realpath (name, NULL((void*)0));
497 const char *lookup_name;
498
499 if (real_name)
21
Assuming 'real_name' is null
22
Taking false branch
500 lookup_name = real_name;
501 else
502 lookup_name = name;
503
504 struct fs *fs;
505 for (fs = fstab->entries; fs; fs = fs->next)
23
Loop condition is true. Entering loop body
506 if (strcmp (fs->mntent.mnt_fsname, lookup_name) == 0)
24
Null pointer passed as an argument to a 'nonnull' parameter
507 break;
508
509 free (real_name);
510 return fs;
511}
512
513/* Returns the FS entry in FSTAB with the mount point NAME (there can only
514 be one such entry). */
515inline struct fs *
516fstab_find_mount (const struct fstab *fstab, const char *name)
517{
518 /* Don't count "none" or "-" as matching any other mount point.
519 It is canonical to use "none" for swap partitions, and multiple
520 such do not in fact conflict with each other. Likewise, the
521 special device name "ignore" is used for things that should not
522 be processed automatically. */
523 if (!strcmp (name, "-")
524 || !strcmp (name, "none")
525 || !strcmp (name, "ignore"))
526 return 0;
527
528 char *real_name = realpath (name, NULL((void*)0));
529 const char *lookup_name;
530
531 if (real_name)
532 lookup_name = real_name;
533 else
534 lookup_name = name;
535
536 struct fs *fs;
537 for (fs = fstab->entries; fs; fs = fs->next)
538 if (strcmp (fs->mntent.mnt_dir, lookup_name) == 0)
539 break;
540
541 free (real_name);
542 return fs;
543}
544
545/* Returns the FS entry in FSTAB with the device or mount point NAME (there
546 can only be one such entry). */
547inline struct fs *
548fstab_find (const struct fstab *fstab, const char *name)
549{
550 return fstab_find_device (fstab, name) ?: fstab_find_mount (fstab, name);
551}
552
553/* Cons FS onto the beginning of FSTAB's entry list. */
554static void
555_fstab_add (struct fstab *fstab, struct fs *fs)
556{
557 fs->fstab = fstab;
558 fs->next = fstab->entries;
559 fs->self = &fstab->entries;
560 if (fstab->entries)
561 fstab->entries->self = &fs->next;
562 fstab->entries = fs;
563}
564
565/* Destroy FS, removing it from its containing FSTAB. */
566void
567fs_free (struct fs *fs)
568{
569 *fs->self = fs->next; /* unlink from chain */
570 if (fs->storage)
571 free (fs->storage);
572 if (fs->fsys != MACH_PORT_NULL((mach_port_t) 0))
573 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fs->fsys);
574 free (fs);
575}
576
577/* Add an entry for MNTENT to FSTAB, removing any existing entries that
578 conflict (in either the device or mount point). If RESULT is non-zero, the
579 new entry is returne in it. */
580error_t
581fstab_add_mntent (struct fstab *const fstab, const struct mntent *mntent,
582 struct fs **result)
583{
584 int new = 0; /* True if we didn't overwrite an old entry. */
585 error_t err = 0;
586 struct fs *fs = fstab_find_device (fstab, mntent->mnt_fsname);
587 struct fs *mounted_fs = fstab_find_mount (fstab, mntent->mnt_dir);
588
589 if (! fs)
590 /* No old entry with the same device; see if there's one with the same
591 mount point. */
592 {
593 fs = mounted_fs;
594 mounted_fs = 0;
595 }
596
597 if (! fs)
598 /* No old entry, make a new one. */
599 {
600 fs = malloc (sizeof (struct fs));
601 if (fs)
602 {
603 memset (fs, 0, sizeof(struct fs));
604 fs->mounted = fs->readonly = -1;
605 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
606 new = 1;
607 }
608 else
609 err = ENOMEM((0x10 << 26) | ((12) & 0x3fff));
610 }
611
612 if (! err)
613 /* Try and fill in FS's mntent. */
614 err = fs_set_mntent (fs, mntent);
615
616 if (new)
617 {
618 if (! err)
619 _fstab_add (fstab, fs);
620 else if (fs)
621 free (fs);
622 }
623
624 if (!err && mounted_fs && mounted_fs != fs)
625 /* Get rid of the conflicting entry MOUNTED_FS. */
626 fs_free (mounted_fs);
627
628 if (!err && result)
629 *result = fs;
630
631 return err;
632}
633
634/* Copy the entry FS (which should belong to another fstab than DST) into
635 DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
636 COPY is non-zero, the copy is returned in it. */
637error_t
638fstab_add_fs (struct fstab *dst, const struct fs *fs, struct fs **copy)
639{
640 error_t err;
641 struct fs *new;
642 struct fstab *src = fs->fstab;
643
644 if (dst->types != src->types)
645 return EINVAL((0x10 << 26) | ((22) & 0x3fff));
646
647 err = fstab_add_mntent (dst, &fs->mntent, &new);
648 if (err)
649 return err;
650
651 new->type = fs->type;
652
653 if (copy)
654 *copy = new;
655
656 return 0;
657}
658
659/* Merge SRC into DST, as if by calling fstab_add_fs on DST with every
660 entry in SRC, and then deallocating SRC. If DST & SRC have different
661 TYPES fields, EINVAL is returned. */
662error_t
663fstab_merge (struct fstab *dst, struct fstab *src)
664{
665 struct fs *fs;
666
667 if (dst->types != src->types)
668 return EINVAL((0x10 << 26) | ((22) & 0x3fff));
669
670 /* Remove entries in DST which conflict with those in SRC. */
671 for (fs = src->entries; fs; fs = fs->next)
672 {
673 struct fs *old_fs;
674
675 old_fs = fstab_find_device (dst, fs->mntent.mnt_fsname);
676 if (old_fs)
677 fs_free (old_fs);
678 old_fs = fstab_find_mount (dst, fs->mntent.mnt_dir);
679 if (old_fs)
680 fs_free (old_fs);
681 }
682
683 /* Now that we know there are no conflicts, steal all SRC's entries and
684 cons them onto DST. */
685 for (fs = src->entries; fs; fs = fs->next)
686 _fstab_add (dst, fs);
687
688 /* Now all entries from SRC should be in DST, so just deallocate SRC. */
689 free (src);
690
691 return 0;
692}
693
694/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
695 duplicating one already in FS_LIST supersede the existing entry. */
696error_t
697fstab_read (struct fstab *fstab, const char *name)
698{
699 error_t err;
700 /* Used to hold entries from the file, before merging with FSTAB at the
701 end. */
702 struct fstab *contents;
703 FILE *stream = setmntent (name, "r");
704
705 if (! stream)
8
Assuming 'stream' is non-null
9
Taking false branch
706 return errno(*__errno_location ());
707
708 err = fstab_create (fstab->types, &contents);
709 if (! err)
10
Taking true branch
710 {
711 while (!err && !feof (stream))
11
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
712 {
713 errno(*__errno_location ()) = 0;
714 struct mntent *mntent = getmntent (stream);
715
716 if (! mntent)
12
Assuming 'mntent' is non-null
13
Taking false branch
17
Assuming 'mntent' is non-null
18
Taking false branch
717 err = errno(*__errno_location ());
718 else if (fstab_find_device (fstab, mntent->mnt_fsname))
14
Taking false branch
19
Calling 'fstab_find_device'
719 error (0, 0, "%s: Warning: duplicate entry for device %s (%s)",
720 name, mntent->mnt_fsname, mntent->mnt_dir);
721 else if (fstab_find_mount (fstab, mntent->mnt_dir))
15
Taking false branch
722 error (0, 0, "%s: Warning: duplicate entry for mount point %s (%s)",
723 name, mntent->mnt_dir, mntent->mnt_fsname);
724 else
725 err = fstab_add_mntent (fstab, mntent, 0);
726 }
727
728 if (! err)
729 fstab_merge (fstab, contents);
730 else
731 fstab_free (contents);
732 }
733
734 endmntent (stream);
735
736 return err;
737}
738
739/* Return the next pass number that applies to any filesystem in FSTAB that
740 is greater than PASS, or -1 if there isn't any. */
741int fstab_next_pass (const struct fstab *fstab, int pass)
742{
743 int next_pass = -1;
744 struct fs *fs;
745 for (fs = fstab->entries; fs; fs = fs->next)
746 if (fs->mntent.mnt_passno > pass)
747 if (next_pass < 0 || fs->mntent.mnt_passno < next_pass)
748 {
749 next_pass = fs->mntent.mnt_passno;
750 if (next_pass == pass + 1)
751 break; /* Only possible answer. */
752 }
753 return next_pass;
754}
755
756
757static const struct argp_option options[] =
758{
759 {"all", 'a', 0, 0, "Do all filesystems in " _PATH_MNTTAB"/etc/fstab"},
760 {0, 'A', 0, OPTION_ALIAS0x4 },
761 {"fstab", 'F', "FILE", 0, "File to use instead of " _PATH_MNTTAB"/etc/fstab"},
762 {"fstype", 't', "TYPE", 0, "Do only filesystems of given type(s)"},
763 {"exclude-root",'R',0, 0,
764 "Exclude root (/) filesystem from " _PATH_MNTTAB"/etc/fstab" " list"},
765 {"exclude", 'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
766
767 {"search-fmts",'S', "FMTS", 0,
768 "`:' separated list of formats to use for finding"
769 " filesystem-specific programs"},
770
771 {0, 0}
772};
773
774static error_t
775parse_opt (int key, char *arg, struct argp_state *state)
776{
777 error_t err;
778 struct fstab_argp_params *params = state->input;
779
780 switch (key)
781 {
782 case ARGP_KEY_INIT0x1000003:
783 /* Initialize our parsing state. */
784 if (! params)
785 return EINVAL((0x10 << 26) | ((22) & 0x3fff)); /* Need at least a way to return a result. */
786 memset (params, 0, sizeof *params);
787 break;
788
789 case 'A':
790 case 'a':
791 params->do_all = 1;
792 break;
793
794 case 'F':
795 params->fstab_path = arg;
796 break;
797
798 case 'S':
799 argz_create_sep (arg, ':',
800 &params->program_search_fmts,
801 &params->program_search_fmts_len);
802 break;
803
804 case 'R':
805 arg = "/";
806 /* FALLTHROUGH */
807 case 'X':
808 err = argz_add (&params->exclude, &params->exclude_len, arg);
809 if (err)
810 argp_failure (state, 100, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
811 break;
812 case 't':
813 err = argz_add_sep (&params->types, &params->types_len, arg, ',');
814 if (err)
815 argp_failure (state, 100, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
816 break;
817
818 case ARGP_KEY_ARG0:
819 err = argz_add (&params->names, &params->names_len, arg);
820 if (err)
821 argp_failure (state, 100, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
822 break;
823
824 case ARGP_KEY_END0x1000001:
825 /* Check for bogus combinations of arguments. */
826 if (params->names)
827 {
828 if (params->do_all)
829 argp_error (state, "filesystem arguments not allowed with --all");
830 if (params->exclude)
831 argp_error (state,
832 "--exclude not allowed with filesystem arguments");
833 if (params->types)
834 argp_error (state,
835 "--fstype not allowed with filesystem arguments");
836 }
837 break;
838
839 default:
840 return ARGP_ERR_UNKNOWN((0x10 << 26) | ((7) & 0x3fff));
841 }
842
843 return 0;
844}
845
846const struct argp fstab_argp = {options, parse_opt, 0, 0};
847
848struct fstab *
849fstab_argp_create (struct fstab_argp_params *params,
850 const char *default_search_fmts,
851 size_t default_search_fmts_len)
852{
853 error_t err;
854 struct fstab *fstab, *check;
855 struct fstypes *types;
856
857 if (params->fstab_path == 0)
1
Taking false branch
858 params->fstab_path = _PATH_MNTTAB"/etc/fstab";
859 if (params->program_search_fmts == 0)
2
Taking false branch
860 {
861 params->program_search_fmts = (char *) default_search_fmts;
862 params->program_search_fmts_len = default_search_fmts_len;
863 }
864
865 err = fstypes_create (params->program_search_fmts,
866 params->program_search_fmts_len,
867 &types);
868 if (err)
3
Taking false branch
869 error (102, err, "fstypes_create");
870
871 err = fstab_create (types, &fstab);
872 if (err)
4
Taking false branch
873 error (101, err, "fstab_create");
874
875 err = fstab_read (fstab, params->fstab_path);
876 if (err)
5
Taking false branch
877 error (103, err, "%s", params->fstab_path);
878
879 if (params->names)
6
Taking true branch
880 {
881 /* Process specified filesystems; also look at /var/run/mtab. */
882 const char *name;
883
884 err = fstab_read (fstab, _PATH_MOUNTED"/etc/mtab");
7
Calling 'fstab_read'
885 if (err && err != ENOENT((0x10 << 26) | ((2) & 0x3fff)))
886 error (104, err, "%s", _PATH_MOUNTED"/etc/mtab");
887
888 err = fstab_create (types, &check);
889 if (err)
890 error (105, err, "fstab_create");
891
892 for (name = params->names; name; name = argz_next (params->names,
893 params->names_len,
894 name))
895 {
896 struct fs *fs = fstab_find (fstab, name);
897 if (! fs)
898 error (106, 0, "%s: Unknown device or filesystem", name);
899 fstab_add_fs (check, fs, 0);
900 }
901
902 /* fstab_free (fstab); XXX */
903 }
904 else
905 {
906 /* Process everything in /etc/fstab. */
907
908 if (params->exclude == 0 && params->types == 0)
909 check = fstab;
910 else
911 {
912 err = fstab_create (types, &check);
913 if (err)
914 error (105, err, "fstab_create");
915
916 int blacklist = strncasecmp (params->types, "no", 2) == 0;
917 if (blacklist)
918 params->types += 2; /* Skip no. */
919
920 struct fs *fs;
921 for (fs = fstab->entries; fs; fs = fs->next)
922 {
923 if (strcmp (fs->mntent.mnt_type, MNTTYPE_SWAP"swap") == 0)
924 continue; /* Ignore swap entries. */
925
926 const char *tn;
927 int matched = 0;
928 for (tn = params->types; tn;
929 tn = argz_next (params->types, params->types_len, tn))
930 {
931 const char *type = fs->mntent.mnt_type;
932 if (strcmp (type, tn) == 0
933 /* Skip no for compatibility. */
934 || ((strncasecmp (type, "no", 2) == 0)
935 && strcmp (type, tn) == 0))
936 {
937 matched = 1;
938 break;
939 }
940 }
941
942 if (matched == blacklist)
943 continue; /* Either matched and types is a blacklist
944 or not matched and types is a whitelist */
945
946 const char *ptn;
947 for (ptn = params->exclude; ptn;
948 ptn = argz_next (params->exclude, params->exclude_len, ptn))
949 if (fnmatch (ptn, fs->mntent.mnt_dir, 0) == 0)
950 break;
951 if (ptn) /* An exclude pattern matched. */
952 continue;
953
954 err = fstab_add_fs (check, fs, 0);
955 if (err)
956 error (107, err, "fstab_add_fs");
957 }
958
959 /* fstab_free (fstab); XXX */
960 }
961 }
962
963 return check;
964}