new package aufs2-util
[openadk.git] / package / aufs2-util / src / plink.c
blob6ff16c76a55fd70fca93f5e7b6abaca55301c541
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
19 #define _FILE_OFFSET_BITS 64 /* ftw.h */
20 #define _XOPEN_SOURCE 500 /* ftw.h */
21 #define _GNU_SOURCE /* ftw.h */
23 #include <sys/ioctl.h>
24 #include <sys/resource.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <ftw.h>
29 #include <mntent.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
35 #include <linux/aufs_type.h>
36 #include "au_util.h"
38 /* todo: try argz? */
39 static struct name_array {
40 char *o;
41 int bytes;
43 char *cur;
44 int nname;
45 } na;
47 static struct ino_array {
48 char *o;
49 int bytes;
51 union {
52 char *p;
53 ino_t *cur;
55 int nino;
56 } ia;
58 static int na_append(char *plink_dir, char *name)
60 int l, sz;
61 char *p;
62 const int cur = na.cur - na.o;
64 l = strlen(plink_dir) + strlen(name) + 2;
65 sz = na.bytes + l;
66 p = realloc(na.o, sz);
67 if (!p)
68 AuFin("realloc");
70 na.o = p;
71 na.bytes = sz;
72 na.cur = p + cur;
73 na.cur += sprintf(na.cur, "%s/%s", plink_dir, name) + 1;
74 na.nname++;
76 return 0;
79 static int ia_append(ino_t ino)
81 int sz;
82 char *p;
83 const int cur = ia.p - ia.o;
85 sz = na.bytes + sizeof(ino_t);
86 p = realloc(ia.o, sz);
87 if (!p)
88 AuFin("realloc");
90 ia.o = p;
91 ia.bytes = sz;
92 ia.p = p + cur;
93 *ia.cur++ = ino;
94 ia.nino++;
96 return 0;
99 static int build_array(char *plink_dir)
101 int err;
102 DIR *dp;
103 struct dirent *de;
104 char *p;
105 ino_t ino;
107 err = access(plink_dir, F_OK);
108 if (err)
109 return 0;
111 err = 0;
112 dp = opendir(plink_dir);
113 if (!dp)
114 AuFin("%s", plink_dir);
115 while ((de = readdir(dp))) {
116 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
117 continue;
118 #if 0
119 if (de->d_type == DT_DIR) {
120 errno = EISDIR;
121 AuFin(de->d_name);
123 #endif
125 err = na_append(plink_dir, de->d_name);
126 if (err)
127 break;
129 p = strchr(de->d_name, '.');
130 if (!p) {
131 errno = EINVAL;
132 AuFin("internal error, %s", de->d_name);
134 *p = 0;
135 errno = 0;
136 ino = strtoull(de->d_name, NULL, 0);
137 if (ino == /*ULLONG_MAX*/-1 && errno == ERANGE)
138 AuFin("internal error, %s", de->d_name);
139 err = ia_append(ino);
140 if (err)
141 break;
143 closedir(dp);
145 return err;
148 static int ia_test(ino_t ino)
150 int i;
151 ino_t *p;
153 /* todo: hash table */
154 ia.p = ia.o;
155 p = ia.cur;
156 for (i = 0; i < ia.nino; i++)
157 if (*p++ == ino)
158 return 1;
159 return 0;
162 /* ---------------------------------------------------------------------- */
164 static int ftw_list(const char *fname, const struct stat *st, int flags,
165 struct FTW *ftw)
167 if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
168 return FTW_SKIP_SUBTREE;
169 if (flags == FTW_D || flags == FTW_DNR)
170 return FTW_CONTINUE;
172 if (ia_test(st->st_ino))
173 puts(fname);
175 return FTW_CONTINUE;
178 static int ftw_cpup(const char *fname, const struct stat *st, int flags,
179 struct FTW *ftw)
181 int err;
183 if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
184 return FTW_SKIP_SUBTREE;
185 if (flags == FTW_D || flags == FTW_DNR)
186 return FTW_CONTINUE;
189 * do nothing but update something harmless in order to make it copyup
191 if (ia_test(st->st_ino)) {
192 Dpri("%s\n", fname);
193 if (!S_ISLNK(st->st_mode))
194 err = chown(fname, -1, -1);
195 else
196 err = lchown(fname, -1, -1);
197 if (err)
198 AuFin("%s", fname);
201 return FTW_CONTINUE;
204 /* ---------------------------------------------------------------------- */
206 static DIR *dp;
207 void au_plink_maint(char *path)
209 int err;
211 if (path) {
212 if (dp) {
213 errno = EINVAL;
214 AuFin("dp is not NULL");
216 dp = opendir(path);
217 if (!dp)
218 AuFin("%s", path);
220 err = ioctl(dirfd(dp), AUFS_CTL_PLINK_MAINT);
221 #ifndef DEBUG
222 if (err)
223 AuFin("AUFS_CTL_PLINK_MAINT");
224 #endif
225 } else {
226 err = closedir(dp);
227 if (err)
228 AuFin("closedir");
229 dp = NULL;
233 void au_clean_plink(void)
235 int err;
237 err = ioctl(dirfd(dp), AUFS_CTL_PLINK_CLEAN);
238 #ifndef DEBUG
239 if (err)
240 AuFin("AUFS_CTL_PLINK_CLEAN");
241 #endif
244 static int do_plink(char *cwd, int cmd, int nbr, char *br[])
246 int err, i, l;
247 struct rlimit rlim;
248 __nftw_func_t func;
249 char *p;
251 err = 0;
252 switch (cmd) {
253 case AuPlink_FLUSH:
254 /*FALLTHROUGH*/
255 case AuPlink_CPUP:
256 func = ftw_cpup;
257 break;
258 case AuPlink_LIST:
259 func = ftw_list;
260 break;
261 default:
262 errno = EINVAL;
263 AuFin(NULL);
264 func = NULL; /* never reach here */
267 for (i = 0; i < nbr; i++) {
268 //puts(br[i]);
269 p = strchr(br[i], '=');
270 if (strcmp(p + 1, AUFS_BRPERM_RW)
271 && strcmp(p + 1, AUFS_BRPERM_RWNLWH))
272 continue;
274 *p = 0;
275 l = strlen(br[i]);
276 p = malloc(l + sizeof(AUFS_WH_PLINKDIR) + 2);
277 if (!p)
278 AuFin("malloc");
279 sprintf(p, "%s/%s", br[i], AUFS_WH_PLINKDIR);
280 //puts(p);
281 err = build_array(p);
282 if (err)
283 AuFin("build_array");
284 free(p);
286 if (!ia.nino)
287 goto out;
289 if (cmd == AuPlink_LIST) {
290 ia.p = ia.o;
291 for (i = 0; i < ia.nino; i++)
292 printf("%llu ", (unsigned long long)*ia.cur++);
293 putchar('\n');
296 err = getrlimit(RLIMIT_NOFILE, &rlim);
297 if (err)
298 AuFin("getrlimit");
299 nftw(cwd, func, rlim.rlim_cur - 10,
300 FTW_PHYS | FTW_MOUNT | FTW_ACTIONRETVAL);
301 /* ignore */
303 if (cmd == AuPlink_FLUSH) {
304 au_clean_plink();
306 na.cur = na.o;
307 for (i = 0; i < na.nname; i++) {
308 Dpri("%s\n", na.cur);
309 err = unlink(na.cur);
310 if (err)
311 AuFin("%s", na.cur);
312 na.cur += strlen(na.cur) + 1;
316 out:
317 free(ia.o);
318 free(na.o);
319 return err;
322 int au_plink(char cwd[], int cmd, int begin_maint, int end_maint)
324 int err, nbr;
325 struct mntent ent;
326 char **br;
328 if (begin_maint)
329 au_plink_maint(cwd);
331 err = au_proc_getmntent(cwd, &ent);
332 if (err)
333 AuFin("no such mount point");
335 if (hasmntopt(&ent, "noplink"))
336 goto out; /* success */
338 #ifdef DEBUG
339 //char a[] = "a,b,br:/tmp/br0=rw:/br1=ro";
340 char a[] = "a,b,si=1,c";
341 ent.mnt_opts = a;
342 #endif
343 err = au_br(&br, &nbr, &ent);
344 //printf("nbr %d\n", nbr);
345 if (err)
346 AuFin(NULL);
348 err = do_plink(cwd, cmd, nbr, br);
349 if (err)
350 AuFin(NULL);
352 out:
353 if (end_maint)
354 au_plink_maint(NULL);
355 return err;