diff options
Diffstat (limited to 'package/aufs2-util/src/mount.aufs.c')
-rw-r--r-- | package/aufs2-util/src/mount.aufs.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/package/aufs2-util/src/mount.aufs.c b/package/aufs2-util/src/mount.aufs.c new file mode 100644 index 000000000..d801cfd3c --- /dev/null +++ b/package/aufs2-util/src/mount.aufs.c @@ -0,0 +1,255 @@ +/* + * 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 + */ + +/* + * The main purpose of this script is updating /etc/mtab and calling auplilnk. + * This behaviour is highly depending on mount(8) in util-linux package. + */ + +#define _XOPEN_SOURCE 500 /* getsubopt */ +#define _BSD_SOURCE /* dirfd */ + +#include <sys/types.h> +#include <dirent.h> +#include <mntent.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wait.h> + +#include <linux/aufs_type.h> +#include "au_util.h" + +enum { Remount, Bind, Fake, Update, Verbose, AuFlush, LastOpt }; +static void test_opts(char opts[], unsigned char flags[]) +{ + int c; + char *p, *o, *val, *pat[] = { + [Remount] = "remount", + [Bind] = "bind", + NULL + }; + + o = strdup(opts); + if (!o) + AuFin("stdup"); + + p = o; + while (*p) { + c = getsubopt(&p, pat, &val); + switch (c) { + case Remount: + flags[Remount] = 1; + break; + case Bind: + flags[Bind] = 1; + break; + } + } + free(o); +} + +static int test_flush(char opts[]) +{ + int err, i; + regex_t preg; + char *p, *o; + const char *pat = "^((add|ins|append|prepend|del)[:=]" + "|(mod|imod)[:=][^,]*=ro" + "|(noplink|ro)$)"; + + + o = strdup(opts); + if (!o) + AuFin("stdup"); + + p = o; + i = 1; + while ((p = strchr(p, ','))) { + i++; + *p++ = 0; + } + + /* todo: try getsubopt(3)? */ + err = regcomp(&preg, pat, REG_EXTENDED | REG_NOSUB); + if (err) + AuFin("regcomp"); + + p = o; + while (i--) { + if (!regexec(&preg, p, 0, NULL, 0)) { + err = 1; + break; + } else + p += strlen(p) + 1; + } + regfree(&preg); + free(o); + + return err; +} + +static void do_mount(char *dev, char *mntpnt, int argc, char *argv[], + unsigned char flags[]) +{ + int i; + const int ac = argc + 6; + char *av[ac], **a; + + /* todo: eliminate the duplicated options */ + a = av; + *a++ = "mount"; + *a++ = "-i"; + if (flags[Fake]) + *a++ = "-f"; + if (!flags[Bind] || !flags[Update]) + *a++ = "-n"; + if (flags[Bind] && flags[Verbose]) + *a++ = "-v"; + *a++ = "-t"; + *a++ = AUFS_NAME; + + for (i = 3; i < argc; i++) + if (strcmp(argv[i], "-v") && strcmp(argv[i], "-n")) + *a++ = argv[i]; + *a++ = dev; + *a++ = mntpnt; + *a++ = NULL; + +#ifdef DEBUG + for (i = 0; av[i] && i < ac; i++) + puts(av[i]); + exit(0); +#endif + execvp("mount", av); + AuFin("mount"); +} + +/* ---------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + int err, c, status; + pid_t pid; + unsigned char flags[LastOpt]; + struct mntent ent; + char *dev, *mntpnt, *opts, *cwd; + DIR *cur; + + if (argc < 3) { + errno = EINVAL; + AuFin(NULL); + } + + memset(flags, 0, sizeof(flags)); + flags[Update] = 1; + opts = NULL; + + /* mount(8) always passes the arguments in this order */ + dev = argv[1]; + mntpnt = argv[2]; + while ((c = getopt(argc - 2, argv + 2, "fnvo:")) != -1) { + switch (c) { + case 'f': + flags[Fake] = 1; + break; + case 'n': + flags[Update] = 0; + break; + case 'v': + flags[Verbose] = 1; + break; + case 'o': + opts = optarg; + break; + case '?': + case ':': + errno = EINVAL; + AuFin("internal error"); + } + } + + cur = opendir("."); + if (!cur) + AuFin("."); + err = chdir(mntpnt); + if (err) + AuFin("%s", mntpnt); + cwd = getcwd(NULL, 0); /* glibc */ + if (!cwd) + AuFin("getcwd"); + err = fchdir(dirfd(cur)); + if (err) + AuFin("fchdir"); + closedir(cur); /* ignore */ + + if (opts) + test_opts(opts, flags); + + if (!flags[Bind] && flags[Update]) { + err = access(MTab, R_OK | W_OK); + if (err) + AuFin(MTab); + } + + if (flags[Remount]) { + errno = EINVAL; + if (flags[Bind]) + AuFin("both of remount and bind are specified"); + flags[AuFlush] = test_flush(opts); + if (flags[AuFlush] /* && !flags[Fake] */) { + err = au_plink(cwd, AuPlink_FLUSH, 1, 1); + if (err) + AuFin(NULL); + } + } + + pid = fork(); + if (!pid) { + /* actual mount operation */ + do_mount(dev, mntpnt, argc, argv, flags); + return 0; + } else if (pid < 0) + AuFin("fork"); + + err = waitpid(pid, &status, 0); + if (err < 0) + AuFin("child process"); + + err = !WIFEXITED(status); + if (!err) + err = WEXITSTATUS(status); + + if (!err && !flags[Bind]) { + if (flags[Update]) + err = au_update_mtab(cwd, flags[Remount], + flags[Verbose]); + else if (flags[Verbose]) { + /* withoug blocking plink */ + err = au_proc_getmntent(cwd, &ent); + if (!err) + au_print_ent(&ent); + else + AuFin("internal error"); + } + } + + return err; +} |