📄 fstab.c
字号:
#include <unistd.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <mntent.h>#include "2mntent.h"#include "fstab.h"#include "sundries.h" /* for xmalloc() etc */#define streq(s, t) (strcmp ((s), (t)) == 0)#define PROC_MOUNTS "/proc/mounts"/* Information about mtab. ------------------------------------*/static int have_mtab_info = 0;static int var_mtab_does_not_exist = 0;static int var_mtab_is_a_symlink = 0;static voidget_mtab_info(void) { struct stat mtab_stat; if (!have_mtab_info) { if (lstat(MOUNTED, &mtab_stat)) var_mtab_does_not_exist = 1; else if (S_ISLNK(mtab_stat.st_mode)) var_mtab_is_a_symlink = 1; have_mtab_info = 1; }}intmtab_does_not_exist(void) { get_mtab_info(); return var_mtab_does_not_exist;}intmtab_is_a_symlink(void) { get_mtab_info(); return var_mtab_is_a_symlink;}intmtab_is_writable() { static int ret = -1; /* Should we write to /etc/mtab upon an update? Probably not if it is a symlink to /proc/mounts, since that would create a file /proc/mounts in case the proc filesystem is not mounted. */ if (mtab_is_a_symlink()) return 0; if (ret == -1) { int fd = open(MOUNTED, O_RDWR | O_CREAT, 0644); if (fd >= 0) { close(fd); ret = 1; } else ret = 0; } return ret;}/* Contents of mtab and fstab ---------------------------------*/struct mntentchn mounttable, fstab;static int got_mtab = 0;static int got_fstab = 0;static void read_mounttable(void), read_fstab(void);struct mntentchn *mtab_head() { if (!got_mtab) read_mounttable(); return &mounttable;}struct mntentchn *fstab_head() { if (!got_fstab) read_fstab(); return &fstab;}static voidread_mntentchn( mntFILE *mfp, const char *fnam, struct mntentchn *mc0) { struct mntentchn *mc = mc0; struct mntent *mnt; while ((mnt = my_getmntent (mfp)) != NULL && !streq (mnt->mnt_type, MNTTYPE_IGNORE)) { mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc)); mc->nxt->prev = mc; mc = mc->nxt; mc->mnt_fsname = mnt->mnt_fsname; mc->mnt_dir = mnt->mnt_dir; mc->mnt_type = mnt->mnt_type; mc->mnt_opts = mnt->mnt_opts; mc->nxt = NULL; } mc0->prev = mc; if (ferror (mfp->mntent_fp)) { error("warning: error reading %s: %s", fnam, strerror (errno)); mc0->nxt = mc0->prev = NULL; } my_endmntent(mfp);}/* * Read /etc/mtab. If that fails, try /proc/mounts. * This produces a linked list. The list head mounttable is a dummy. * Return 0 on success. */static voidread_mounttable() { mntFILE *mfp; const char *fnam; struct mntentchn *mc = &mounttable; got_mtab = 1; mc->nxt = mc->prev = NULL; fnam = MOUNTED; mfp = my_setmntent (fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; fnam = PROC_MOUNTS; mfp = my_setmntent (fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { error("warning: can't open %s: %s", MOUNTED, strerror (errsv)); return; } if (verbose) printf ("mount: could not open %s - using %s instead\n", MOUNTED, PROC_MOUNTS); } read_mntentchn(mfp, fnam, mc);}static voidread_fstab() { mntFILE *mfp = NULL; const char *fnam; struct mntentchn *mc = &fstab; got_fstab = 1; mc->nxt = mc->prev = NULL; fnam = _PATH_FSTAB; mfp = my_setmntent (fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { error("warning: can't open %s: %s", _PATH_FSTAB, strerror (errno)); return; } read_mntentchn(mfp, fnam, mc);} /* Given the name NAME, try to find it in mtab. */ struct mntentchn *getmntfile (const char *name) { struct mntentchn *mc; for (mc = mtab_head()->nxt; mc; mc = mc->nxt) if (streq (mc->mnt_dir, name) || (streq (mc->mnt_fsname, name))) break; return mc;}/* Given the name FILE, try to find the option "loop=FILE" in mtab. */ struct mntentchn *getmntoptfile (const char *file){ struct mntentchn *mc; char *opts, *s; int l; if (!file) return NULL; l = strlen(file); for (mc = mtab_head()->nxt; mc; mc = mc->nxt) if ((opts = mc->mnt_opts) != NULL && (s = strstr(opts, "loop=")) && !strncmp(s+5, file, l) && (s == opts || s[-1] == ',') && (s[l+5] == 0 || s[l+5] == ',')) return mc; return NULL;}/* Find the dir FILE in fstab. */struct mntentchn *getfsfile (const char *file) { struct mntentchn *mc; for (mc = fstab_head()->nxt; mc; mc = mc->nxt) if (streq (mc->mnt_dir, file)) break; return mc;}/* Find the device SPEC in fstab. */struct mntentchn *getfsspec (const char *spec){ struct mntentchn *mc; for (mc = fstab_head()->nxt; mc; mc = mc->nxt) if (streq (mc->mnt_fsname, spec)) break; return mc;}/* Updating mtab ----------------------------------------------*//* File descriptor for lock. Value tested in unlock_mtab() to remove race. */static int lock = -1;/* Flag for already existing lock file. */static int old_lockfile = 1;/* Ensure that the lock is released if we are interrupted. */static voidhandler (int sig) { die (EX_USER, "%s", sys_siglist[sig]);}static voidsetlkw_timeout (int sig) { /* nothing, fcntl will fail anyway */}/* 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. */voidlock_mtab (void) { int sig = 0; struct sigaction sa; struct flock flock; /* If this is the first time, ensure that the lock will be removed. */ if (lock < 0) { struct stat st; sa.sa_handler = handler; sa.sa_flags = 0; sigfillset (&sa.sa_mask); while (sigismember (&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD) { if (sig == SIGALRM) sa.sa_handler = setlkw_timeout; else sa.sa_handler = handler; sigaction (sig, &sa, (struct sigaction *) 0); } /* This stat is performed so we know when not to be overly eager when cleaning up after signals. The window between stat and open is not significant. */ if (lstat (MOUNTED_LOCK, &st) < 0 && errno == ENOENT) old_lockfile = 0; lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT, 0); if (lock < 0) { die (EX_FILEIO, "can't create lock file %s: %s " "(use -n flag to override)", MOUNTED_LOCK, strerror (errno)); } flock.l_type = F_WRLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; alarm(LOCK_TIMEOUT); if (fcntl (lock, F_SETLKW, &flock) == -1) { int errnosv = errno; close (lock); lock = -1; /* The file should not be removed */ die (EX_FILEIO, "can't lock lock file %s: %s", MOUNTED_LOCK, errnosv == EINTR ? "timed out" : strerror (errno)); } /* We have now access to the lock, and it can always be removed */ old_lockfile = 0; }}/* Remove lock file. */voidunlock_mtab (void) { if (lock != -1) { close (lock); if (!old_lockfile) unlink (MOUNTED_LOCK); }}/* * Update the mtab. * Used by umount with null INSTEAD: remove any DIR entries. * Used by mount upon a remount: update option part, * and complain if a wrong device or type was given. * [Note that often a remount will be a rw remount of / * where there was no entry before, and we'll have to believe * the values given in INSTEAD.] */voidupdate_mtab (const char *dir, struct mntent *instead) { struct mntent *mnt; struct mntent *next; struct mntent remnt; int added = 0; mntFILE *mfp, *mftmp; if (mtab_does_not_exist() || mtab_is_a_symlink()) return; lock_mtab(); mfp = my_setmntent(MOUNTED, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { error ("cannot open %s (%s) - mtab not updated", MOUNTED, strerror (errno)); goto leave; } mftmp = my_setmntent (MOUNTED_TEMP, "w"); if (mftmp == NULL || mfp->mntent_fp == NULL) { error ("can't open %s (%s) - mtab not updated", MOUNTED_TEMP, strerror (errno)); goto leave; } while ((mnt = my_getmntent (mfp))) { if (streq (mnt->mnt_dir, dir)) { added++; if (instead) { /* a remount */ remnt = *instead; next = &remnt; remnt.mnt_fsname = mnt->mnt_fsname; remnt.mnt_type = mnt->mnt_type; if (instead->mnt_fsname && !streq(mnt->mnt_fsname, instead->mnt_fsname)) printf("mount: warning: cannot change " "mounted device with a remount\n"); else if (instead->mnt_type && !streq(instead->mnt_type, "unknown") && !streq(mnt->mnt_type, instead->mnt_type)) printf("mount: warning: cannot change " "filesystem type with a remount\n"); } else next = NULL; } else next = mnt; if (next && my_addmntent(mftmp, next) == 1) die (EX_FILEIO, "error writing %s: %s", MOUNTED_TEMP, strerror (errno)); } if (instead && !added && my_addmntent(mftmp, instead) == 1) die (EX_FILEIO, "error writing %s: %s", MOUNTED_TEMP, strerror (errno)); my_endmntent (mfp); if (fchmod (fileno (mftmp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) fprintf(stderr, "error changing mode of %s: %s\n", MOUNTED_TEMP, strerror (errno)); my_endmntent (mftmp); if (rename (MOUNTED_TEMP, MOUNTED) < 0) fprintf(stderr, "can't rename %s to %s: %s\n", MOUNTED_TEMP, MOUNTED, strerror(errno));leave: unlock_mtab();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -