util-linux/mount/sundries.c

284 lines
6.1 KiB
C

/*
* 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;
}