diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2009-08-23 21:43:50 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2009-08-23 21:43:50 +0200 |
commit | df0420a62dde5030d0cf8c28c26031f5deb59155 (patch) | |
tree | 8395fcf057779660f3e0fb5f4f4c16637386b69a /package/aufs2-util/src/mtab.c | |
parent | 2b198ddc02b3231e43ab8fdddef76ff103a0f5a4 (diff) | |
parent | 5774bab43a1946acd8440ad759eb6cc26335e64c (diff) |
Merge branch 'master' of git+ssh://openadk.org/git/openadk
Diffstat (limited to 'package/aufs2-util/src/mtab.c')
-rw-r--r-- | package/aufs2-util/src/mtab.c | 216 |
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; +} |