mount.aufs.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright (C) 2005-2009 Junjiro Okajima
  3. *
  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.
  8. *
  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.
  13. *
  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
  17. */
  18. /*
  19. * The main purpose of this script is updating /etc/mtab and calling auplilnk.
  20. * This behaviour is highly depending on mount(8) in util-linux package.
  21. */
  22. #define _XOPEN_SOURCE 500 /* getsubopt */
  23. #define _BSD_SOURCE /* dirfd */
  24. #include <sys/types.h>
  25. #include <dirent.h>
  26. #include <mntent.h>
  27. #include <regex.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include <wait.h>
  33. #include <linux/aufs_type.h>
  34. #include "au_util.h"
  35. enum { Remount, Bind, Fake, Update, Verbose, AuFlush, LastOpt };
  36. static void test_opts(char opts[], unsigned char flags[])
  37. {
  38. int c;
  39. char *p, *o, *val, *pat[] = {
  40. [Remount] = "remount",
  41. [Bind] = "bind",
  42. NULL
  43. };
  44. o = strdup(opts);
  45. if (!o)
  46. AuFin("stdup");
  47. p = o;
  48. while (*p) {
  49. c = getsubopt(&p, pat, &val);
  50. switch (c) {
  51. case Remount:
  52. flags[Remount] = 1;
  53. break;
  54. case Bind:
  55. flags[Bind] = 1;
  56. break;
  57. }
  58. }
  59. free(o);
  60. }
  61. static int test_flush(char opts[])
  62. {
  63. int err, i;
  64. regex_t preg;
  65. char *p, *o;
  66. const char *pat = "^((add|ins|append|prepend|del)[:=]"
  67. "|(mod|imod)[:=][^,]*=ro"
  68. "|(noplink|ro)$)";
  69. o = strdup(opts);
  70. if (!o)
  71. AuFin("stdup");
  72. p = o;
  73. i = 1;
  74. while ((p = strchr(p, ','))) {
  75. i++;
  76. *p++ = 0;
  77. }
  78. /* todo: try getsubopt(3)? */
  79. err = regcomp(&preg, pat, REG_EXTENDED | REG_NOSUB);
  80. if (err)
  81. AuFin("regcomp");
  82. p = o;
  83. while (i--) {
  84. if (!regexec(&preg, p, 0, NULL, 0)) {
  85. err = 1;
  86. break;
  87. } else
  88. p += strlen(p) + 1;
  89. }
  90. regfree(&preg);
  91. free(o);
  92. return err;
  93. }
  94. static void do_mount(char *dev, char *mntpnt, int argc, char *argv[],
  95. unsigned char flags[])
  96. {
  97. int i;
  98. const int ac = argc + 6;
  99. char *av[ac], **a;
  100. /* todo: eliminate the duplicated options */
  101. a = av;
  102. *a++ = "mount";
  103. *a++ = "-i";
  104. if (flags[Fake])
  105. *a++ = "-f";
  106. if (!flags[Bind] || !flags[Update])
  107. *a++ = "-n";
  108. if (flags[Bind] && flags[Verbose])
  109. *a++ = "-v";
  110. *a++ = "-t";
  111. *a++ = AUFS_NAME;
  112. for (i = 3; i < argc; i++)
  113. if (strcmp(argv[i], "-v") && strcmp(argv[i], "-n"))
  114. *a++ = argv[i];
  115. *a++ = dev;
  116. *a++ = mntpnt;
  117. *a++ = NULL;
  118. #ifdef DEBUG
  119. for (i = 0; av[i] && i < ac; i++)
  120. puts(av[i]);
  121. exit(0);
  122. #endif
  123. execvp("mount", av);
  124. AuFin("mount");
  125. }
  126. /* ---------------------------------------------------------------------- */
  127. int main(int argc, char *argv[])
  128. {
  129. int err, c, status;
  130. pid_t pid;
  131. unsigned char flags[LastOpt];
  132. struct mntent ent;
  133. char *dev, *mntpnt, *opts, *cwd;
  134. DIR *cur;
  135. if (argc < 3) {
  136. errno = EINVAL;
  137. AuFin(NULL);
  138. }
  139. memset(flags, 0, sizeof(flags));
  140. flags[Update] = 1;
  141. opts = NULL;
  142. /* mount(8) always passes the arguments in this order */
  143. dev = argv[1];
  144. mntpnt = argv[2];
  145. while ((c = getopt(argc - 2, argv + 2, "fnvo:")) != -1) {
  146. switch (c) {
  147. case 'f':
  148. flags[Fake] = 1;
  149. break;
  150. case 'n':
  151. flags[Update] = 0;
  152. break;
  153. case 'v':
  154. flags[Verbose] = 1;
  155. break;
  156. case 'o':
  157. opts = optarg;
  158. break;
  159. case '?':
  160. case ':':
  161. errno = EINVAL;
  162. AuFin("internal error");
  163. }
  164. }
  165. cur = opendir(".");
  166. if (!cur)
  167. AuFin(".");
  168. err = chdir(mntpnt);
  169. if (err)
  170. AuFin("%s", mntpnt);
  171. cwd = getcwd(NULL, 0); /* glibc */
  172. if (!cwd)
  173. AuFin("getcwd");
  174. err = fchdir(dirfd(cur));
  175. if (err)
  176. AuFin("fchdir");
  177. closedir(cur); /* ignore */
  178. if (opts)
  179. test_opts(opts, flags);
  180. if (!flags[Bind] && flags[Update]) {
  181. err = access(MTab, R_OK | W_OK);
  182. if (err)
  183. AuFin(MTab);
  184. }
  185. if (flags[Remount]) {
  186. errno = EINVAL;
  187. if (flags[Bind])
  188. AuFin("both of remount and bind are specified");
  189. flags[AuFlush] = test_flush(opts);
  190. if (flags[AuFlush] /* && !flags[Fake] */) {
  191. err = au_plink(cwd, AuPlink_FLUSH, 1, 1);
  192. if (err)
  193. AuFin(NULL);
  194. }
  195. }
  196. pid = fork();
  197. if (!pid) {
  198. /* actual mount operation */
  199. do_mount(dev, mntpnt, argc, argv, flags);
  200. return 0;
  201. } else if (pid < 0)
  202. AuFin("fork");
  203. err = waitpid(pid, &status, 0);
  204. if (err < 0)
  205. AuFin("child process");
  206. err = !WIFEXITED(status);
  207. if (!err)
  208. err = WEXITSTATUS(status);
  209. if (!err && !flags[Bind]) {
  210. if (flags[Update])
  211. err = au_update_mtab(cwd, flags[Remount],
  212. flags[Verbose]);
  213. else if (flags[Verbose]) {
  214. /* withoug blocking plink */
  215. err = au_proc_getmntent(cwd, &ent);
  216. if (!err)
  217. au_print_ent(&ent);
  218. else
  219. AuFin("internal error");
  220. }
  221. }
  222. return err;
  223. }