Bug Summary

File:obj-scan-build/sutils/../../sutils/fstab.c
Location:line 900, column 9
Description:Memory is never released; potential leak of memory pointed to by 'fstab'

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));
5
Memory is allocated
49 if (new)
6
Assuming 'new' is non-null
7
Taking true branch
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 *mntent)
244{
245 char *end;
246 size_t needed = 0;
247
248 if (fs->storage)
249 free (fs->storage);
250
251 /* Allocate space for all string mntent fields in FS. */
252#define COUNT(field) if (mntent->field) needed += strlen (mntent->field) + 1;
253 COUNT (mnt_fsname);
254 COUNT (mnt_dir);
255 COUNT (mnt_type);
256 COUNT (mnt_opts);
257#undef COUNT
258
259 fs->storage = malloc (needed);
260 if (! fs->storage)
261 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
262
263 if (!fs->mntent.mnt_dir || !mntent->mnt_dir
264 || strcmp (fs->mntent.mnt_dir, mntent->mnt_dir) != 0)
265 {
266 fs->mounted = fs->readonly = -1;
267 if (fs->fsys != MACH_PORT_NULL((mach_port_t) 0))
268 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fs->fsys);
269 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
270 }
271
272 /* Copy MNTENT into FS; string-valued fields will be fixed up next. */
273 fs->mntent = *mntent;
274
275 /* Copy each mntent field from MNTENT into FS's version. */
276 end = fs->storage;
277#define STORE(field) \
278 if (mntent->field) \
279 { \
280 fs->mntent.field = end; \
281 end = stpcpy (end, mntent->field) + 1; \
282 } \
283 else \
284 fs->mntent.field = 0;
285 STORE (mnt_fsname);
286 STORE (mnt_dir);
287 STORE (mnt_type);
288 STORE (mnt_opts);
289#undef STORE
290
291 if (fs->type
292 && (!mntent->mnt_type
293 || strcasecmp (fs->type->name, mntent->mnt_type) != 0))
294 fs->type = 0; /* Type is different. */
295
296 return 0;
297}
298
299/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
300 necessary. */
301error_t
302fs_type (struct fs *fs, struct fstype **type)
303{
304 error_t err = 0;
305 if (! fs->type)
306 err = fstypes_get (fs->fstab->types, fs->mntent.mnt_type, &fs->type);
307 if (! err)
308 *type = fs->type;
309 return err;
310}
311
312/* Looks to see if FS is currently mounted, being very careful to avoid
313 mounting anything that's not already, and fills in the fsys & mounted
314 fields in FS. */
315static error_t
316_fs_check_mounted (struct fs *fs)
317{
318 error_t err = 0;
319
320 if (fs->mounted < 0)
321 /* The mounted field in FS is -1 if we're not sure. */
322 {
323 if (fs->fsys != MACH_PORT_NULL((mach_port_t) 0))
324 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fs->fsys);
325
326 if (strcmp (fs->mntent.mnt_dir, "/") == 0)
327 /* The root is always mounted. Get its control port. */
328 {
329 file_t root = getcrdir ();
330 if (root == MACH_PORT_NULL((mach_port_t) 0))
331 err = errno(*__errno_location ());
332 else
333 {
334 err = file_getcontrol (root, &fs->fsys);
335 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), root);
336 }
337 }
338 else
339 {
340 file_t mount_point =
341 file_name_lookup_carefully (fs->mntent.mnt_dir, O_NOTRANS0x0080, 0);
342
343 if (mount_point != MACH_PORT_NULL((mach_port_t) 0))
344 /* The node exists. Is it the root of an active translator?
345 [Note that it could be a different translator than the one in
346 the mntent, but oh well, nothing we can do about that.] */
347 {
348 err = file_get_translator_cntl (mount_point, &fs->fsys);
349 if (err == EINVAL((0x10 << 26) | ((22) & 0x3fff)) || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)) || err == ENXIO((0x10 << 26) | ((6) & 0x3fff)))
350 /* Either the mount point doesn't exist, or wasn't mounted. */
351 {
352 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
353 err = 0;
354 }
355 }
356 else if (errno(*__errno_location ()) == ENXIO((0x10 << 26) | ((6) & 0x3fff)))
357 /* Ran into an inactive passive translator. FS can't be mounted. */
358 {
359 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
360 err = 0;
361 }
362 }
363
364 if (! err)
365 fs->mounted = (fs->fsys != MACH_PORT_NULL((mach_port_t) 0));
366 }
367
368 return err;
369}
370
371/* Looks to see if FS is currently mounted, being very careful to avoid
372 mounting anything that's not already, and returns the control port for the
373 mounted filesystem (MACH_PORT_NULL if not mounted). */
374error_t
375fs_fsys (struct fs *fs, fsys_t *fsys)
376{
377 error_t err = _fs_check_mounted (fs);
378 if (!err && fsys)
379 *fsys = fs->fsys;
380 return err;
381}
382
383/* Looks to see if FS is currently mounted, being very careful to avoid
384 mounting anything that's not already, and returns the boolean MOUNTED. */
385error_t
386fs_mounted (struct fs *fs, int *mounted)
387{
388 error_t err = _fs_check_mounted (fs);
389 if (!err && mounted)
390 *mounted = fs->mounted;
391 return err;
392}
393
394/* Looks to see if FS is currently mounted readonly, being very careful to
395 avoid mounting anything that's not already, and returns the boolean
396 READONLY. If FS isn't mounted at all, READONLY is set to 1 (it's not
397 going to write anything!). */
398error_t
399fs_readonly (struct fs *fs, int *readonly)
400{
401 error_t err = 0;
402
403 if (fs->readonly < 0)
404 /* Unknown. */
405 {
406 fsys_t fsys;
407
408 err = fs_fsys (fs, &fsys);
409 if (! err)
410 {
411 if (fsys == MACH_PORT_NULL((mach_port_t) 0))
412 fs->readonly = 1;
413 else
414 err = fsys_get_readonly (fsys, &fs->readonly);
415 }
416 }
417
418 if (!err && readonly)
419 *readonly = fs->readonly;
420
421 return err;
422}
423
424/* If FS is currently mounted writable, try to make it readonly. XXX If FS
425 is not mounted at all, then nothing is done. */
426error_t
427fs_set_readonly (struct fs *fs, int readonly)
428{
429 int currently_readonly;
430 error_t err = fs_readonly (fs, &currently_readonly);
431
432 readonly = !!readonly;
433
434 if (!err && readonly != currently_readonly)
435 /* We have to try and change the readonly state. */
436 {
437 fsys_t fsys;
438 err = fs_fsys (fs, &fsys);
439 if (!err && fsys != MACH_PORT_NULL((mach_port_t) 0)) /* XXX What to do if not mounted? */
440 err = fsys_set_readonly (fsys, readonly);
441 if (! err)
442 fs->readonly = readonly;
443 }
444
445 return err;
446}
447
448/* If FS is currently mounted tell it to remount the device. XXX If FS is
449 not mounted at all, then nothing is done. */
450error_t
451fs_remount (struct fs *fs)
452{
453 fsys_t fsys;
454 error_t err = fs_fsys (fs, &fsys);
455 if (!err && fsys != MACH_PORT_NULL((mach_port_t) 0)) /* XXX What to do if not mounted? */
456 err = fsys_update (fsys);
457 return err;
458}
459
460/* Returns the FS entry in FSTAB with the device field NAME.
461
462 In general there can only be one such entry. This holds not true
463 for virtual file systems that use "none" as device name.
464
465 If name is "none", NULL is returned. This also makes it possible to
466 add more than one entry for the device "none". */
467inline struct fs *
468fstab_find_device (const struct fstab *fstab, const char *name)
469{
470 if (strcmp (name, "none") == 0)
471 return NULL((void*)0);
472
473 struct fs *fs;
474 for (fs = fstab->entries; fs; fs = fs->next)
475 if (strcmp (fs->mntent.mnt_fsname, name) == 0)
476 return fs;
477 return 0;
478}
479
480/* Returns the FS entry in FSTAB with the mount point NAME (there can only
481 be one such entry). */
482inline struct fs *
483fstab_find_mount (const struct fstab *fstab, const char *name)
484{
485 struct fs *fs;
486
487 /* Don't count "none" or "-" as matching any other mount point.
488 It is canonical to use "none" for swap partitions, and multiple
489 such do not in fact conflict with each other. Likewise, the
490 special device name "ignore" is used for things that should not
491 be processed automatically. */
492 if (!strcmp (name, "-")
493 || !strcmp (name, "none")
494 || !strcmp (name, "ignore"))
495 return 0;
496
497 for (fs = fstab->entries; fs; fs = fs->next)
498 if (strcmp (fs->mntent.mnt_dir, name) == 0)
499 return fs;
500 return 0;
501}
502
503/* Returns the FS entry in FSTAB with the device or mount point NAME (there
504 can only be one such entry). */
505inline struct fs *
506fstab_find (const struct fstab *fstab, const char *name)
507{
508 struct fs *ret;
509 char *real_name;
510
511 ret = fstab_find_device (fstab, name);
512 if (ret)
513 return ret;
514
515 ret = fstab_find_mount (fstab, name);
516 if (ret)
517 return ret;
518
519 real_name = realpath (name, NULL((void*)0));
520
521 ret = fstab_find_device (fstab, real_name);
522 if (ret) {
523 free (real_name);
524 return ret;
525 }
526
527 ret = fstab_find_mount (fstab, real_name);
528 free (real_name);
529
530 return ret;
531}
532
533/* Cons FS onto the beginning of FSTAB's entry list. */
534static void
535_fstab_add (struct fstab *fstab, struct fs *fs)
536{
537 fs->fstab = fstab;
538 fs->next = fstab->entries;
539 fs->self = &fstab->entries;
540 if (fstab->entries)
541 fstab->entries->self = &fs->next;
542 fstab->entries = fs;
543}
544
545/* Destroy FS, removing it from its containing FSTAB. */
546void
547fs_free (struct fs *fs)
548{
549 *fs->self = fs->next; /* unlink from chain */
550 if (fs->storage)
551 free (fs->storage);
552 if (fs->fsys != MACH_PORT_NULL((mach_port_t) 0))
553 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fs->fsys);
554 free (fs);
555}
556
557/* Add an entry for MNTENT to FSTAB, removing any existing entries that
558 conflict (in either the device or mount point). If RESULT is non-zero, the
559 new entry is returne in it. */
560error_t
561fstab_add_mntent (struct fstab *const fstab, const struct mntent *mntent,
562 struct fs **result)
563{
564 int new = 0; /* True if we didn't overwrite an old entry. */
565 error_t err = 0;
566 struct fs *fs = fstab_find_device (fstab, mntent->mnt_fsname);
567 struct fs *mounted_fs = fstab_find_mount (fstab, mntent->mnt_dir);
568
569 if (! fs)
570 /* No old entry with the same device; see if there's one with the same
571 mount point. */
572 {
573 fs = mounted_fs;
574 mounted_fs = 0;
575 }
576
577 if (! fs)
578 /* No old entry, make a new one. */
579 {
580 fs = malloc (sizeof (struct fs));
581 if (fs)
582 {
583 bzero (fs, sizeof (struct fs));
584 fs->mounted = fs->readonly = -1;
585 fs->fsys = MACH_PORT_NULL((mach_port_t) 0);
586 new = 1;
587 }
588 else
589 err = ENOMEM((0x10 << 26) | ((12) & 0x3fff));
590 }
591
592 if (! err)
593 /* Try and fill in FS's mntent. */
594 err = fs_set_mntent (fs, mntent);
595
596 if (new)
597 {
598 if (! err)
599 _fstab_add (fstab, fs);
600 else if (fs)
601 free (fs);
602 }
603
604 if (!err && mounted_fs && mounted_fs != fs)
605 /* Get rid of the conflicting entry MOUNTED_FS. */
606 fs_free (mounted_fs);
607
608 if (!err && result)
609 *result = fs;
610
611 return err;
612}
613
614/* Copy the entry FS (which should belong to another fstab than DST) into
615 DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
616 COPY is non-zero, the copy is returned in it. */
617error_t
618fstab_add_fs (struct fstab *dst, const struct fs *fs, struct fs **copy)
619{
620 error_t err;
621 struct fs *new;
622 struct fstab *src = fs->fstab;
623
624 if (dst->types != src->types)
625 return EINVAL((0x10 << 26) | ((22) & 0x3fff));
626
627 err = fstab_add_mntent (dst, &fs->mntent, &new);
628 if (err)
629 return err;
630
631 new->type = fs->type;
632
633 if (copy)
634 *copy = new;
635
636 return 0;
637}
638
639/* Merge SRC into DST, as if by calling fstab_add_fs on DST with every
640 entry in SRC, and then deallocating SRC. If DST & SRC have different
641 TYPES fields, EINVAL is returned. */
642error_t
643fstab_merge (struct fstab *dst, struct fstab *src)
644{
645 struct fs *fs;
646
647 if (dst->types != src->types)
648 return EINVAL((0x10 << 26) | ((22) & 0x3fff));
649
650 /* Remove entries in DST which conflict with those in SRC. */
651 for (fs = src->entries; fs; fs = fs->next)
652 {
653 struct fs *old_fs;
654
655 old_fs = fstab_find_device (dst, fs->mntent.mnt_fsname);
656 if (old_fs)
657 fs_free (old_fs);
658 old_fs = fstab_find_mount (dst, fs->mntent.mnt_dir);
659 if (old_fs)
660 fs_free (old_fs);
661 }
662
663 /* Now that we know there are no conflicts, steal all SRC's entries and
664 cons them onto DST. */
665 for (fs = src->entries; fs; fs = fs->next)
666 _fstab_add (dst, fs);
667
668 /* Now all entries from SRC should be in DST, so just deallocate SRC. */
669 free (src);
670
671 return 0;
672}
673
674/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
675 duplicating one already in FS_LIST supersede the existing entry. */
676error_t
677fstab_read (struct fstab *fstab, const char *name)
678{
679 error_t err;
680 /* Used to hold entries from the file, before merging with FSTAB at the
681 end. */
682 struct fstab *contents;
683 FILE *stream = setmntent (name, "r");
684
685 if (! stream)
686 return errno(*__errno_location ());
687
688 err = fstab_create (fstab->types, &contents);
689 if (! err)
690 {
691 while (!err && !feof (stream))
692 {
693 struct mntent *mntent = getmntent (stream);
694
695 if (! mntent)
696 err = errno(*__errno_location ());
697 else if (fstab_find_device (fstab, mntent->mnt_fsname))
698 error (0, 0, "%s: Warning: duplicate entry for device %s (%s)",
699 name, mntent->mnt_fsname, mntent->mnt_dir);
700 else if (fstab_find_mount (fstab, mntent->mnt_dir))
701 error (0, 0, "%s: Warning: duplicate entry for mount point %s (%s)",
702 name, mntent->mnt_dir, mntent->mnt_fsname);
703 else
704 err = fstab_add_mntent (fstab, mntent, 0);
705 }
706
707 if (! err)
708 fstab_merge (fstab, contents);
709 else
710 fstab_free (contents);
711 }
712
713 endmntent (stream);
714
715 return err;
716}
717
718/* Return the next pass number that applies to any filesystem in FSTAB that
719 is greater than PASS, or -1 if there isn't any. */
720int fstab_next_pass (const struct fstab *fstab, int pass)
721{
722 int next_pass = -1;
723 struct fs *fs;
724 for (fs = fstab->entries; fs; fs = fs->next)
725 if (fs->mntent.mnt_passno > pass)
726 if (next_pass < 0 || fs->mntent.mnt_passno < next_pass)
727 {
728 next_pass = fs->mntent.mnt_passno;
729 if (next_pass == pass + 1)
730 break; /* Only possible answer. */
731 }
732 return next_pass;
733}
734
735
736static const struct argp_option options[] =
737{
738 {"all", 'a', 0, 0, "Do all filesystems in " _PATH_MNTTAB"/etc/fstab"},
739 {0, 'A', 0, OPTION_ALIAS0x4 },
740 {"fstab", 'F', "FILE", 0, "File to use instead of " _PATH_MNTTAB"/etc/fstab"},
741 {"fstype", 't', "TYPE", 0, "Do only filesystems of given type(s)"},
742 {"exclude-root",'R',0, 0,
743 "Exclude root (/) filesystem from " _PATH_MNTTAB"/etc/fstab" " list"},
744 {"exclude", 'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
745
746 {"search-fmts",'S', "FMTS", 0,
747 "`:' separated list of formats to use for finding"
748 " filesystem-specific programs"},
749
750 {0, 0}
751};
752
753static error_t
754parse_opt (int key, char *arg, struct argp_state *state)
755{
756 error_t err;
757 struct fstab_argp_params *params = state->input;
758
759 switch (key)
760 {
761 case ARGP_KEY_INIT0x1000003:
762 /* Initialize our parsing state. */
763 if (! params)
764 return EINVAL((0x10 << 26) | ((22) & 0x3fff)); /* Need at least a way to return a result. */
765 bzero (params, sizeof *params);
766 break;
767
768 case 'A':
769 case 'a':
770 params->do_all = 1;
771 break;
772
773 case 'F':
774 params->fstab_path = arg;
775 break;
776
777 case 'S':
778 argz_create_sep (arg, ':',
779 &params->program_search_fmts,
780 &params->program_search_fmts_len);
781 break;
782
783 case 'R':
784 arg = "/";
785 /* FALLTHROUGH */
786 case 'X':
787 err = argz_add (&params->exclude, &params->exclude_len, arg);
788 if (err)
789 argp_failure (state, 100, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
790 break;
791 case 't':
792 err = argz_add_sep (&params->types, &params->types_len, arg, ',');
793 if (err)
794 argp_failure (state, 100, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
795 break;
796
797 case ARGP_KEY_ARG0:
798 err = argz_add (&params->names, &params->names_len, arg);
799 if (err)
800 argp_failure (state, 100, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
801 break;
802
803 case ARGP_KEY_END0x1000001:
804 /* Check for bogus combinations of arguments. */
805 if (params->names)
806 {
807 if (params->do_all)
808 argp_error (state, "filesystem arguments not allowed with --all");
809 if (params->exclude)
810 argp_error (state,
811 "--exclude not allowed with filesystem arguments");
812 if (params->types)
813 argp_error (state,
814 "--fstype not allowed with filesystem arguments");
815 }
816 break;
817
818 default:
819 return ARGP_ERR_UNKNOWN((0x10 << 26) | ((7) & 0x3fff));
820 }
821
822 return 0;
823}
824
825const struct argp fstab_argp = {options, parse_opt, 0, 0};
826
827struct fstab *
828fstab_argp_create (struct fstab_argp_params *params,
829 const char *default_search_fmts,
830 size_t default_search_fmts_len)
831{
832 error_t err;
833 struct fstab *fstab, *check;
834 struct fstypes *types;
835
836 if (params->fstab_path == 0)
1
Taking false branch
837 params->fstab_path = _PATH_MNTTAB"/etc/fstab";
838 if (params->program_search_fmts == 0)
2
Taking false branch
839 {
840 params->program_search_fmts = (char *) default_search_fmts;
841 params->program_search_fmts_len = default_search_fmts_len;
842 }
843
844 err = fstypes_create (params->program_search_fmts,
845 params->program_search_fmts_len,
846 &types);
847 if (err)
3
Taking false branch
848 error (102, err, "fstypes_create");
849
850 err = fstab_create (types, &fstab);
4
Calling 'fstab_create'
8
Returned allocated memory via 2nd parameter
851 if (err)
9
Taking false branch
852 error (101, err, "fstab_create");
853
854 err = fstab_read (fstab, params->fstab_path);
855 if (err)
10
Taking false branch
856 error (103, err, "%s", params->fstab_path);
857
858 if (params->names)
11
Taking false branch
859 {
860 /* Process specified filesystems; also look at /var/run/mtab. */
861 const char *name;
862
863 err = fstab_read (fstab, _PATH_MOUNTED"/etc/mtab");
864 if (err && err != ENOENT((0x10 << 26) | ((2) & 0x3fff)))
865 error (104, err, "%s", _PATH_MOUNTED"/etc/mtab");
866
867 err = fstab_create (types, &check);
868 if (err)
869 error (105, err, "fstab_create");
870
871 for (name = params->names; name; name = argz_next (params->names,
872 params->names_len,
873 name))
874 {
875 struct fs *fs = fstab_find (fstab, name);
876 if (! fs)
877 error (106, 0, "%s: Unknown device or filesystem", name);
878 fstab_add_fs (check, fs, 0);
879 }
880
881 /* fstab_free (fstab); XXX */
882 }
883 else
884 {
885 /* Process everything in /etc/fstab. */
886
887 if (params->exclude == 0 && params->types == 0)
888 check = fstab;
889 else
890 {
891 err = fstab_create (types, &check);
892 if (err)
12
Taking false branch
893 error (105, err, "fstab_create");
894
895 int blacklist = strncasecmp (params->types, "no", 2) == 0;
896 if (blacklist)
13
Taking false branch
897 params->types += 2; /* Skip no. */
898
899 struct fs *fs;
900 for (fs = fstab->entries; fs; fs = fs->next)
14
Memory is never released; potential leak of memory pointed to by 'fstab'
901 {
902 if (strcmp (fs->mntent.mnt_type, MNTTYPE_SWAP"swap") == 0)
903 continue; /* Ignore swap entries. */
904
905 const char *tn;
906 int matched = 0;
907 for (tn = params->types; tn;
908 tn = argz_next (params->types, params->types_len, tn))
909 {
910 const char *type = fs->mntent.mnt_type;
911 if (strcmp (type, tn) == 0
912 /* Skip no for compatibility. */
913 || ((strncasecmp (type, "no", 2) == 0)
914 && strcmp (type, tn) == 0))
915 {
916 matched = 1;
917 break;
918 }
919 }
920
921 if (matched == blacklist)
922 continue; /* Either matched and types is a blacklist
923 or not matched and types is a whitelist */
924
925 const char *ptn;
926 for (ptn = params->exclude; ptn;
927 ptn = argz_next (params->exclude, params->exclude_len, ptn))
928 if (fnmatch (ptn, fs->mntent.mnt_dir, 0) == 0)
929 break;
930 if (ptn) /* An exclude pattern matched. */
931 continue;
932
933 err = fstab_add_fs (check, fs, 0);
934 if (err)
935 error (107, err, "fstab_add_fs");
936 }
937
938 /* fstab_free (fstab); XXX */
939 }
940 }
941
942 return check;
943}