summaryrefslogtreecommitdiff
path: root/package/aufs2-util/src/mtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/aufs2-util/src/mtab.c')
-rw-r--r--package/aufs2-util/src/mtab.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/package/aufs2-util/src/mtab.c b/package/aufs2-util/src/mtab.c
new file mode 100644
index 000000000..713e9e267
--- /dev/null
+++ b/package/aufs2-util/src/mtab.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* cf. fstab.c or the locking for /etc/mtab in util-linux */
+/*
+ * we need to extract a part of util-linux and create a simple and generic
+ * library for locking /etc/mtab.
+ */
+
+/* #include <linux/proc_fs.h> */
+#define PROC_SUPER_MAGIC 0x9fa0
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "au_util.h"
+
+void au_print_ent(struct mntent *ent)
+{
+ printf("%s on %s type %s (%s)\n",
+ ent->mnt_fsname, ent->mnt_dir, ent->mnt_type, ent->mnt_opts);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void lock_mtab(char *pid_file)
+{
+ int err, i;
+
+ for (i = 0; i < 5; i++) {
+ err = link(pid_file, MTab "~");
+ if (!err)
+ break;
+ sleep(1);
+ }
+ if (err)
+ AuFin(MTab "~");
+}
+
+static void unlock_mtab(void)
+{
+ int err;
+
+ err = rename(MTab "~", MTab);
+ if (err)
+ AuFin(MTab);
+}
+
+static void append_mtab(FILE *fp, FILE *ofp, struct mntent *ent)
+{
+ int err;
+ struct mntent *p;
+
+ while ((p = getmntent(ofp))) {
+ err = addmntent(fp, p);
+ if (err)
+ AuFin("addmntent");
+ }
+
+ err = addmntent(fp, ent);
+ if (err)
+ AuFin("addmntent");
+}
+
+/* todo: there are some cases which options are not changed */
+static void update_mtab(FILE *fp, char *mntpnt, int do_remount, int do_verbose)
+{
+ int err;
+ long pos;
+ FILE *ofp;
+ struct mntent ent, *p;
+
+ /* prohibit updating mount options for this mntpnt */
+ au_plink_maint(mntpnt);
+ err = au_proc_getmntent(mntpnt, &ent);
+ if (err)
+ AuFin("no such mount point");
+
+ ofp = setmntent(MTab, "r");
+ if (!ofp)
+ AuFin(MTab);
+
+ if (do_remount) {
+ /* find the last one */
+ pos = -1;
+ while ((p = getmntent(ofp))) {
+ if (!strcmp(p->mnt_dir, mntpnt))
+ pos = ftell(ofp);
+ }
+ rewind(ofp);
+
+ if (pos > 0) {
+ while ((p = getmntent(ofp))) {
+ if (ftell(ofp) == pos) {
+ /* replace the line */
+ p = &ent;
+ pos = -1;
+ }
+ err = addmntent(fp, p);
+ if (err)
+ AuFin("addmntent");
+ }
+ if (pos > 0)
+ AuFin("internal error");
+ } else
+ append_mtab(fp, ofp, &ent);
+ } else
+ append_mtab(fp, ofp, &ent);
+
+ endmntent(ofp); /* ignore */
+ au_plink_maint(NULL);
+ if (do_verbose)
+ au_print_ent(&ent);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int au_update_mtab(char *mntpnt, int do_remount, int do_verbose)
+{
+ int err, fd, status, e2;
+ pid_t pid;
+ ino_t ino;
+ struct stat st;
+ struct statfs stfs;
+ struct flock flock = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+ char pid_file[sizeof(MTab "~.") + 20];
+ FILE *fp;
+
+ err = statfs(MTab, &stfs);
+ if (stfs.f_type == PROC_SUPER_MAGIC)
+ return 0;
+
+ snprintf(pid_file, sizeof(pid_file), MTab "~.%d", getpid());
+ fd = open(pid_file, O_RDWR | O_CREAT | O_EXCL,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ AuFin("%s", pid_file);
+ err = fcntl(fd, F_SETLK, &flock);
+ if (err)
+ AuFin("%s", pid_file);
+ fp = fdopen(fd, "r+");
+ if (!fp)
+ AuFin("%s", pid_file);
+
+ pid = fork();
+ if (!pid) {
+ lock_mtab(pid_file);
+ update_mtab(fp, mntpnt, do_remount, do_verbose);
+ unlock_mtab();
+ return 0;
+ } else if (pid < 0)
+ AuFin("fork");
+
+ err = fstat(fd, &st);
+ if (err)
+ perror(pid_file);
+ ino = st.st_ino;
+
+ err = waitpid(pid, &status, 0);
+ if (err < 0) {
+ perror(pid_file);
+ goto out;
+ }
+ err = !WIFEXITED(status);
+ if (!err)
+ err = WEXITSTATUS(status);
+
+ e2 = unlink(pid_file);
+ if (e2 && errno != ENOENT)
+ perror(pid_file);
+ e2 = stat(MTab "~", &st);
+ if (!e2) {
+ if (st.st_ino == ino) {
+ /*
+ * The inode number is same,
+ * it means it is we who made the file.
+ * If someone else removed our file between stat(2) and
+ * unlink(2), it is a breakage of the rule.
+ */
+ e2 = unlink(MTab "~");
+ if (e2)
+ perror(MTab);
+ }
+ } else if (errno != ENOENT)
+ perror(MTab "~");
+ fclose(fp);
+
+ out:
+ return err;
+}