plink.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. #define _FILE_OFFSET_BITS 64 /* ftw.h */
  19. #define _XOPEN_SOURCE 500 /* ftw.h */
  20. #define _GNU_SOURCE /* ftw.h */
  21. #include <sys/ioctl.h>
  22. #include <sys/resource.h>
  23. #include <sys/time.h>
  24. #include <sys/types.h>
  25. #include <dirent.h>
  26. #include <ftw.h>
  27. #include <mntent.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include <linux/aufs_type.h>
  33. #include "au_util.h"
  34. /* todo: try argz? */
  35. static struct name_array {
  36. char *o;
  37. int bytes;
  38. char *cur;
  39. int nname;
  40. } na;
  41. static struct ino_array {
  42. char *o;
  43. int bytes;
  44. union {
  45. char *p;
  46. ino_t *cur;
  47. };
  48. int nino;
  49. } ia;
  50. static int na_append(char *plink_dir, char *name)
  51. {
  52. int l, sz;
  53. char *p;
  54. const int cur = na.cur - na.o;
  55. l = strlen(plink_dir) + strlen(name) + 2;
  56. sz = na.bytes + l;
  57. p = realloc(na.o, sz);
  58. if (!p)
  59. AuFin("realloc");
  60. na.o = p;
  61. na.bytes = sz;
  62. na.cur = p + cur;
  63. na.cur += sprintf(na.cur, "%s/%s", plink_dir, name) + 1;
  64. na.nname++;
  65. return 0;
  66. }
  67. static int ia_append(ino_t ino)
  68. {
  69. int sz;
  70. char *p;
  71. const int cur = ia.p - ia.o;
  72. sz = na.bytes + sizeof(ino_t);
  73. p = realloc(ia.o, sz);
  74. if (!p)
  75. AuFin("realloc");
  76. ia.o = p;
  77. ia.bytes = sz;
  78. ia.p = p + cur;
  79. *ia.cur++ = ino;
  80. ia.nino++;
  81. return 0;
  82. }
  83. static int build_array(char *plink_dir)
  84. {
  85. int err;
  86. DIR *dp;
  87. struct dirent *de;
  88. char *p;
  89. ino_t ino;
  90. err = access(plink_dir, F_OK);
  91. if (err)
  92. return 0;
  93. err = 0;
  94. dp = opendir(plink_dir);
  95. if (!dp)
  96. AuFin("%s", plink_dir);
  97. while ((de = readdir(dp))) {
  98. if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
  99. continue;
  100. #if 0
  101. if (de->d_type == DT_DIR) {
  102. errno = EISDIR;
  103. AuFin(de->d_name);
  104. }
  105. #endif
  106. err = na_append(plink_dir, de->d_name);
  107. if (err)
  108. break;
  109. p = strchr(de->d_name, '.');
  110. if (!p) {
  111. errno = EINVAL;
  112. AuFin("internal error, %s", de->d_name);
  113. }
  114. *p = 0;
  115. errno = 0;
  116. ino = strtoull(de->d_name, NULL, 0);
  117. if (ino == /*ULLONG_MAX*/-1 && errno == ERANGE)
  118. AuFin("internal error, %s", de->d_name);
  119. err = ia_append(ino);
  120. if (err)
  121. break;
  122. }
  123. closedir(dp);
  124. return err;
  125. }
  126. static int ia_test(ino_t ino)
  127. {
  128. int i;
  129. ino_t *p;
  130. /* todo: hash table */
  131. ia.p = ia.o;
  132. p = ia.cur;
  133. for (i = 0; i < ia.nino; i++)
  134. if (*p++ == ino)
  135. return 1;
  136. return 0;
  137. }
  138. /* ---------------------------------------------------------------------- */
  139. static int ftw_list(const char *fname, const struct stat *st, int flags,
  140. struct FTW *ftw)
  141. {
  142. if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
  143. return FTW_SKIP_SUBTREE;
  144. if (flags == FTW_D || flags == FTW_DNR)
  145. return FTW_CONTINUE;
  146. if (ia_test(st->st_ino))
  147. puts(fname);
  148. return FTW_CONTINUE;
  149. }
  150. static int ftw_cpup(const char *fname, const struct stat *st, int flags,
  151. struct FTW *ftw)
  152. {
  153. int err;
  154. if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
  155. return FTW_SKIP_SUBTREE;
  156. if (flags == FTW_D || flags == FTW_DNR)
  157. return FTW_CONTINUE;
  158. /*
  159. * do nothing but update something harmless in order to make it copyup
  160. */
  161. if (ia_test(st->st_ino)) {
  162. Dpri("%s\n", fname);
  163. if (!S_ISLNK(st->st_mode))
  164. err = chown(fname, -1, -1);
  165. else
  166. err = lchown(fname, -1, -1);
  167. if (err)
  168. AuFin("%s", fname);
  169. }
  170. return FTW_CONTINUE;
  171. }
  172. /* ---------------------------------------------------------------------- */
  173. static DIR *dp;
  174. void au_plink_maint(char *path)
  175. {
  176. int err;
  177. if (path) {
  178. if (dp) {
  179. errno = EINVAL;
  180. AuFin("dp is not NULL");
  181. }
  182. dp = opendir(path);
  183. if (!dp)
  184. AuFin("%s", path);
  185. err = ioctl(dirfd(dp), AUFS_CTL_PLINK_MAINT);
  186. #ifndef DEBUG
  187. if (err)
  188. AuFin("AUFS_CTL_PLINK_MAINT");
  189. #endif
  190. } else {
  191. err = closedir(dp);
  192. if (err)
  193. AuFin("closedir");
  194. dp = NULL;
  195. }
  196. }
  197. void au_clean_plink(void)
  198. {
  199. int err;
  200. err = ioctl(dirfd(dp), AUFS_CTL_PLINK_CLEAN);
  201. #ifndef DEBUG
  202. if (err)
  203. AuFin("AUFS_CTL_PLINK_CLEAN");
  204. #endif
  205. }
  206. static int do_plink(char *cwd, int cmd, int nbr, char *br[])
  207. {
  208. int err, i, l;
  209. struct rlimit rlim;
  210. __nftw_func_t func;
  211. char *p;
  212. err = 0;
  213. switch (cmd) {
  214. case AuPlink_FLUSH:
  215. /*FALLTHROUGH*/
  216. case AuPlink_CPUP:
  217. func = ftw_cpup;
  218. break;
  219. case AuPlink_LIST:
  220. func = ftw_list;
  221. break;
  222. default:
  223. errno = EINVAL;
  224. AuFin(NULL);
  225. func = NULL; /* never reach here */
  226. }
  227. for (i = 0; i < nbr; i++) {
  228. //puts(br[i]);
  229. p = strchr(br[i], '=');
  230. if (strcmp(p + 1, AUFS_BRPERM_RW)
  231. && strcmp(p + 1, AUFS_BRPERM_RWNLWH))
  232. continue;
  233. *p = 0;
  234. l = strlen(br[i]);
  235. p = malloc(l + sizeof(AUFS_WH_PLINKDIR) + 2);
  236. if (!p)
  237. AuFin("malloc");
  238. sprintf(p, "%s/%s", br[i], AUFS_WH_PLINKDIR);
  239. //puts(p);
  240. err = build_array(p);
  241. if (err)
  242. AuFin("build_array");
  243. free(p);
  244. }
  245. if (!ia.nino)
  246. goto out;
  247. if (cmd == AuPlink_LIST) {
  248. ia.p = ia.o;
  249. for (i = 0; i < ia.nino; i++)
  250. printf("%llu ", (unsigned long long)*ia.cur++);
  251. putchar('\n');
  252. }
  253. err = getrlimit(RLIMIT_NOFILE, &rlim);
  254. if (err)
  255. AuFin("getrlimit");
  256. nftw(cwd, func, rlim.rlim_cur - 10,
  257. FTW_PHYS | FTW_MOUNT | FTW_ACTIONRETVAL);
  258. /* ignore */
  259. if (cmd == AuPlink_FLUSH) {
  260. au_clean_plink();
  261. na.cur = na.o;
  262. for (i = 0; i < na.nname; i++) {
  263. Dpri("%s\n", na.cur);
  264. err = unlink(na.cur);
  265. if (err)
  266. AuFin("%s", na.cur);
  267. na.cur += strlen(na.cur) + 1;
  268. }
  269. }
  270. out:
  271. free(ia.o);
  272. free(na.o);
  273. return err;
  274. }
  275. int au_plink(char cwd[], int cmd, int begin_maint, int end_maint)
  276. {
  277. int err, nbr;
  278. struct mntent ent;
  279. char **br;
  280. if (begin_maint)
  281. au_plink_maint(cwd);
  282. err = au_proc_getmntent(cwd, &ent);
  283. if (err)
  284. AuFin("no such mount point");
  285. if (hasmntopt(&ent, "noplink"))
  286. goto out; /* success */
  287. #ifdef DEBUG
  288. //char a[] = "a,b,br:/tmp/br0=rw:/br1=ro";
  289. char a[] = "a,b,si=1,c";
  290. ent.mnt_opts = a;
  291. #endif
  292. err = au_br(&br, &nbr, &ent);
  293. //printf("nbr %d\n", nbr);
  294. if (err)
  295. AuFin(NULL);
  296. err = do_plink(cwd, cmd, nbr, br);
  297. if (err)
  298. AuFin(NULL);
  299. out:
  300. if (end_maint)
  301. au_plink_maint(NULL);
  302. return err;
  303. }