new package aufs2-util
[openadk.git] / package / aufs2-util / src / mount.aufs.c
blobd801cfd3c30dbd7a3620175ed332e5f69f9483fe
1 /*
2 * Copyright (C) 2005-2009 Junjiro Okajima
4 * This program, aufs is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * The main purpose of this script is updating /etc/mtab and calling auplilnk.
21 * This behaviour is highly depending on mount(8) in util-linux package.
24 #define _XOPEN_SOURCE 500 /* getsubopt */
25 #define _BSD_SOURCE /* dirfd */
27 #include <sys/types.h>
28 #include <dirent.h>
29 #include <mntent.h>
30 #include <regex.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <wait.h>
37 #include <linux/aufs_type.h>
38 #include "au_util.h"
40 enum { Remount, Bind, Fake, Update, Verbose, AuFlush, LastOpt };
41 static void test_opts(char opts[], unsigned char flags[])
43 int c;
44 char *p, *o, *val, *pat[] = {
45 [Remount] = "remount",
46 [Bind] = "bind",
47 NULL
50 o = strdup(opts);
51 if (!o)
52 AuFin("stdup");
54 p = o;
55 while (*p) {
56 c = getsubopt(&p, pat, &val);
57 switch (c) {
58 case Remount:
59 flags[Remount] = 1;
60 break;
61 case Bind:
62 flags[Bind] = 1;
63 break;
66 free(o);
69 static int test_flush(char opts[])
71 int err, i;
72 regex_t preg;
73 char *p, *o;
74 const char *pat = "^((add|ins|append|prepend|del)[:=]"
75 "|(mod|imod)[:=][^,]*=ro"
76 "|(noplink|ro)$)";
79 o = strdup(opts);
80 if (!o)
81 AuFin("stdup");
83 p = o;
84 i = 1;
85 while ((p = strchr(p, ','))) {
86 i++;
87 *p++ = 0;
90 /* todo: try getsubopt(3)? */
91 err = regcomp(&preg, pat, REG_EXTENDED | REG_NOSUB);
92 if (err)
93 AuFin("regcomp");
95 p = o;
96 while (i--) {
97 if (!regexec(&preg, p, 0, NULL, 0)) {
98 err = 1;
99 break;
100 } else
101 p += strlen(p) + 1;
103 regfree(&preg);
104 free(o);
106 return err;
109 static void do_mount(char *dev, char *mntpnt, int argc, char *argv[],
110 unsigned char flags[])
112 int i;
113 const int ac = argc + 6;
114 char *av[ac], **a;
116 /* todo: eliminate the duplicated options */
117 a = av;
118 *a++ = "mount";
119 *a++ = "-i";
120 if (flags[Fake])
121 *a++ = "-f";
122 if (!flags[Bind] || !flags[Update])
123 *a++ = "-n";
124 if (flags[Bind] && flags[Verbose])
125 *a++ = "-v";
126 *a++ = "-t";
127 *a++ = AUFS_NAME;
129 for (i = 3; i < argc; i++)
130 if (strcmp(argv[i], "-v") && strcmp(argv[i], "-n"))
131 *a++ = argv[i];
132 *a++ = dev;
133 *a++ = mntpnt;
134 *a++ = NULL;
136 #ifdef DEBUG
137 for (i = 0; av[i] && i < ac; i++)
138 puts(av[i]);
139 exit(0);
140 #endif
141 execvp("mount", av);
142 AuFin("mount");
145 /* ---------------------------------------------------------------------- */
147 int main(int argc, char *argv[])
149 int err, c, status;
150 pid_t pid;
151 unsigned char flags[LastOpt];
152 struct mntent ent;
153 char *dev, *mntpnt, *opts, *cwd;
154 DIR *cur;
156 if (argc < 3) {
157 errno = EINVAL;
158 AuFin(NULL);
161 memset(flags, 0, sizeof(flags));
162 flags[Update] = 1;
163 opts = NULL;
165 /* mount(8) always passes the arguments in this order */
166 dev = argv[1];
167 mntpnt = argv[2];
168 while ((c = getopt(argc - 2, argv + 2, "fnvo:")) != -1) {
169 switch (c) {
170 case 'f':
171 flags[Fake] = 1;
172 break;
173 case 'n':
174 flags[Update] = 0;
175 break;
176 case 'v':
177 flags[Verbose] = 1;
178 break;
179 case 'o':
180 opts = optarg;
181 break;
182 case '?':
183 case ':':
184 errno = EINVAL;
185 AuFin("internal error");
189 cur = opendir(".");
190 if (!cur)
191 AuFin(".");
192 err = chdir(mntpnt);
193 if (err)
194 AuFin("%s", mntpnt);
195 cwd = getcwd(NULL, 0); /* glibc */
196 if (!cwd)
197 AuFin("getcwd");
198 err = fchdir(dirfd(cur));
199 if (err)
200 AuFin("fchdir");
201 closedir(cur); /* ignore */
203 if (opts)
204 test_opts(opts, flags);
206 if (!flags[Bind] && flags[Update]) {
207 err = access(MTab, R_OK | W_OK);
208 if (err)
209 AuFin(MTab);
212 if (flags[Remount]) {
213 errno = EINVAL;
214 if (flags[Bind])
215 AuFin("both of remount and bind are specified");
216 flags[AuFlush] = test_flush(opts);
217 if (flags[AuFlush] /* && !flags[Fake] */) {
218 err = au_plink(cwd, AuPlink_FLUSH, 1, 1);
219 if (err)
220 AuFin(NULL);
224 pid = fork();
225 if (!pid) {
226 /* actual mount operation */
227 do_mount(dev, mntpnt, argc, argv, flags);
228 return 0;
229 } else if (pid < 0)
230 AuFin("fork");
232 err = waitpid(pid, &status, 0);
233 if (err < 0)
234 AuFin("child process");
236 err = !WIFEXITED(status);
237 if (!err)
238 err = WEXITSTATUS(status);
240 if (!err && !flags[Bind]) {
241 if (flags[Update])
242 err = au_update_mtab(cwd, flags[Remount],
243 flags[Verbose]);
244 else if (flags[Verbose]) {
245 /* withoug blocking plink */
246 err = au_proc_getmntent(cwd, &ent);
247 if (!err)
248 au_print_ent(&ent);
249 else
250 AuFin("internal error");
254 return err;