diff options
Diffstat (limited to 'mount/sundries.c')
-rw-r--r-- | mount/sundries.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/mount/sundries.c b/mount/sundries.c new file mode 100644 index 000000000..45e0e14d8 --- /dev/null +++ b/mount/sundries.c @@ -0,0 +1,283 @@ +/* + * Support functions. Exported functions are prototyped in sundries.h. + * sundries.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp + */ + +#include "sundries.h" + +/* File pointer for /etc/mtab. */ +FILE *F_mtab = NULL; + +/* File pointer for temp mtab. */ +FILE *F_temp = NULL; + +/* File descriptor for lock. Value tested in unlock_mtab() to remove race. */ +static int lock = -1; + +/* String list constructor. (car() and cdr() are defined in "sundries.h"). */ +string_list +cons (char *a, const string_list b) +{ + string_list p; + + p = xmalloc (sizeof *p); + + car (p) = a; + cdr (p) = b; + return p; +} + +void * +xmalloc (size_t size) +{ + void *t; + + if (size == 0) + return NULL; + + t = malloc (size); + if (t == NULL) + die (2, "not enough memory"); + + return t; +} + +char * +xstrdup (const char *s) +{ + char *t; + + if (s == NULL) + return NULL; + + t = strdup (s); + + if (t == NULL) + die (2, "not enough memory"); + + return t; +} + +/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock. */ +void +block_signals (int how) +{ + sigset_t sigs; + + sigfillset (&sigs); + sigprocmask (how, &sigs, (sigset_t *) 0); +} + + +/* Non-fatal error. Print message and return. */ +void +error (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); +} + +/* Fatal error. Print message and exit. */ +void +die (int err, const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); + + unlock_mtab (); + exit (err); +} + +/* Ensure that the lock is released if we are interrupted. */ +static void +handler (int sig) +{ + die (2, "%s", sys_siglist[sig]); +} + +/* Create the lock file. The lock file will be removed if we catch a signal + or when we exit. The value of lock is tested to remove the race. */ +void +lock_mtab (void) +{ + int sig = 0; + struct sigaction sa; + + /* If this is the first time, ensure that the lock will be removed. */ + if (lock < 0) + { + sa.sa_handler = handler; + sa.sa_flags = 0; + sigfillset (&sa.sa_mask); + + while (sigismember (&sa.sa_mask, ++sig) != -1) + sigaction (sig, &sa, (struct sigaction *) 0); + + if ((lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT|O_EXCL, 0)) < 0) + die (2, "can't create lock file %s: %s", + MOUNTED_LOCK, strerror (errno)); + } +} + +/* Remove lock file. */ +void +unlock_mtab (void) +{ + if (lock != -1) + { + close( lock ); + unlink (MOUNTED_LOCK); + } +} + +/* Open mtab. */ +void +open_mtab (const char *mode) +{ + if ((F_mtab = setmntent (MOUNTED, mode)) == NULL) + die (2, "can't open %s: %s", MOUNTED, strerror (errno)); +} + +/* Close mtab. */ +void +close_mtab (void) +{ + if (fchmod (fileno (F_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + die (1, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno)); + endmntent (F_mtab); +} + +/* Update the mtab by removing any DIR entries and replace it with INSTEAD. */ +void +update_mtab (const char *dir, struct mntent *instead) +{ + struct mntent *mnt; + struct mntent *next; + int added = 0; + + open_mtab ("r"); + + if ((F_temp = setmntent (MOUNTED_TEMP, "w")) == NULL) + die (2, "can't open %s: %s", MOUNTED_TEMP, strerror (errno)); + + while ((mnt = getmntent (F_mtab))) + { + next = streq (mnt->mnt_dir, dir) ? (added++, instead) : mnt; + if (next && addmntent(F_temp, next) == 1) + die (1, "error writing %s: %s", MOUNTED_TEMP, strerror (errno)); + } + if (instead && !added) + addmntent(F_temp, instead); + + endmntent (F_mtab); + if (fchmod (fileno (F_temp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + die (1, "error changing mode of %s: %s", MOUNTED_TEMP, strerror (errno)); + endmntent (F_temp); + + if (rename (MOUNTED_TEMP, MOUNTED) < 0) + die (1, "can't rename %s to %s: %s", + MOUNTED_TEMP, MOUNTED, strerror(errno)); +} + +/* Given the name FILE, try to find it in mtab. */ +struct mntent * +getmntfile (const char *file) +{ + struct mntent *mnt; + + if (!F_mtab) + return NULL; + + rewind(F_mtab); + + while ((mnt = getmntent (F_mtab)) != NULL) + { + if (streq (mnt->mnt_dir, file)) + break; + if (streq (mnt->mnt_fsname, file)) + break; + } + + return mnt; +} + +/* Parse a list of strings like str[,str]... into a string list. */ +string_list +parse_list (char *strings) +{ + string_list list; + char *t; + + if (strings == NULL) + return NULL; + + list = cons (strtok (strings, ","), NULL); + + while ((t = strtok (NULL, ",")) != NULL) + list = cons (t, list); + + return list; +} + +/* True if fstypes match. Null *TYPES means match anything, + except that swap types always return false. This routine + has some ugliness to deal with ``no'' types. */ +int +matching_type (const char *type, string_list types) +{ + char *notype; + int no; /* true if a "no" type match, ie -t nominix */ + + if (streq (type, MNTTYPE_SWAP)) + return 0; + if (types == NULL) + return 1; + + if ((notype = alloca (strlen (type) + 3)) == NULL) + die (2, "mount: out of memory"); + sprintf (notype, "no%s", type); + no = (car (types)[0] == 'n') && (car (types)[1] == 'o'); + + /* If we get a match and the user specified a positive match type (e.g. + "minix") we return true. If we match and a negative match type (e.g. + "nominix") was specified we return false. */ + while (types != NULL) + if (streq (type, car (types))) + return !no; + else if (streq (notype, car (types))) + return 0; /* match with "nofoo" always returns false */ + else + types = cdr (types); + + /* No matches, so if the user specified a positive match type return false, + if a negative match type was specified, return true. */ + return no; +} + +/* Make a canonical pathname from PATH. Returns a freshly malloced string. + It is up the *caller* to ensure that the PATH is sensible. i.e. + canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.'' + is not a legal pathname for ``/dev/fd0.'' Anything we cannot parse + we return unmodified. */ +char * +canonicalize (const char *path) +{ + char *canonical = xmalloc (PATH_MAX + 1); + + if (path == NULL) + return NULL; + + if (realpath (path, canonical)) + return canonical; + + strcpy (canonical, path); + return canonical; +} |