Exemple #1
0
void au_plink_maint(char *path)
{
	int err;

	if (path) {
		if (dp) {
			errno = EINVAL;
			AuFin("dp is not NULL");
		}
		dp = opendir(path);
		if (!dp)
			AuFin("%s", path);

		err = ioctl(dirfd(dp), AUFS_CTL_PLINK_MAINT);
#ifndef DEBUG
		if (err)
			AuFin("AUFS_CTL_PLINK_MAINT");
#endif
	} else {
		err = closedir(dp);
		if (err)
			AuFin("closedir");
		dp = NULL;
	}
}
Exemple #2
0
/*
 * Ideally the mounted aufs should be unmounted even if its mntpnt has very long
 * pathname. In other words, if umount.aufs cannot handle a long pathname, then
 * mount.aufs should reject in the beginning.
 * getmntent(3) in glibc reads 4096 bytes for a single mnt entry. I agree it is
 * large enough. And mount(8) rejects too long pathname. It is OK too. As long
 * as 4095 (4096 - 1) bytes pathname succeeds mounting, then it should be
 * unmounted flawlessly.
 * Testing on Debian v7 (wheezy) succeeded mounting 4095 bytes pathname, but
 * failed unmounting. I don't like this unbalancing. So replace getmntent() by
 * getmntent_r() with larger buffer. Obviously this is less important since such
 * long pathname is very rare.
 */
int au_proc_getmntent(char *mntpnt, struct mntent *rent)
{
	int found;
	struct mntent *p, e;
	FILE *fp;
	char a[4096 + 1024], path[PATH_MAX], *decoded;

	decoded = au_decode_mntpnt(mntpnt, path, sizeof(path));
	if (!decoded)
		AuFin("au_decode_mntpnt");

	fp = setmntent(ProcMounts, "r");
	if (!fp)
		AuFin(ProcMounts);

	/* find the last one */
	memset(rent, 0, sizeof(*rent));
	found = 0;
	while ((p = getmntent_r(fp, &e, a, sizeof(a))))
		if (!strcmp(p->mnt_dir, decoded)) {
			Dpri("%s, %s, %s, %s, %d, %d\n",
			     p->mnt_fsname, p->mnt_dir, p->mnt_type,
			     p->mnt_opts, p->mnt_freq, p->mnt_passno);
			copy_ent(rent, p);
			found = 1;
		}
	endmntent(fp);

	if (!found) {
		errno = EINVAL;
		AuFin("%s, %s", mntpnt, decoded);
	}

	return 0;
}
Exemple #3
0
int au_plink(char cwd[], int cmd, int begin_maint, int end_maint)
{
	int err, nbr;
	struct mntent ent;
	char **br;

	if (begin_maint)
		au_plink_maint(cwd);

	err = au_proc_getmntent(cwd, &ent);
	if (err)
		AuFin("no such mount point");

	if (hasmntopt(&ent, "noplink"))
		goto out; /* success */

#ifdef DEBUG
	//char a[] = "a,b,br:/tmp/br0=rw:/br1=ro";
	char a[] = "a,b,si=1,c";
	ent.mnt_opts = a;
#endif
	err = au_br(&br, &nbr, &ent);
	//printf("nbr %d\n", nbr);
	if (err)
		AuFin(NULL);

	err = do_plink(cwd, cmd, nbr, br);
	if (err)
		AuFin(NULL);

 out:
	if (end_maint)
		au_plink_maint(NULL);
	return err;
}
Exemple #4
0
int au_proc_getmntent(char *mntpnt, struct mntent *rent)
{
	int found;
	struct mntent *p;
	FILE *fp;

	fp = setmntent(ProcMounts, "r");
	if (!fp)
		AuFin(ProcMounts);

	/* find the last one */
	memset(rent, 0, sizeof(*rent));
	found = 0;
	while ((p = getmntent(fp)))
		if (!strcmp(p->mnt_dir, mntpnt)) {
			Dpri("%s, %s, %s, %s, %d, %d\n",
			     p->mnt_fsname, p->mnt_dir, p->mnt_type,
			     p->mnt_opts, p->mnt_freq, p->mnt_passno);
			copy_ent(rent, p);
			found = 1;
		}
	endmntent(fp);

	if (!found) {
		errno = EINVAL;
		AuFin("%s", mntpnt);
	}

	return 0;
}
Exemple #5
0
static void opt(int argc, char *argv[])
{
	int opt, i, err, need_ck, done;
	char *dir, *p;

	done = 0;
	dir = getenv("AUFHSM_LIST_DIR");
	for (i = 1; !done && i < argc; i++) {
		opt = getopt_long(argc, argv, short_opts, opts, NULL);
		switch (opt) {
		case -1:
			done = 1;
			break;
		case 'd':
			dir = optarg;
			break;
		case 'v':
			au_opt_set(fhsmd.optflags, VERBOSE);
			break;

		case 'D':
			au_opt_set(fhsmd.optflags, NODAEMON);
			break;

		case 'V':
			printf("%s version %s\n",
			       program_invocation_short_name, AuVersion);
			exit(0);
		case 'h':
		case '?':
			usage();
			exit(0);
		default:
			//usage();
			exit(EINVAL);
		}
	}

	if (dir) {
		p = realpath(dir, NULL);
		if (!p || !*p)
			AuFin("%s", dir);
		dir = strdup(p);
		if (!dir)
			AuFin("%s", p);
		need_ck = 1;
	} else {
		dir = au_list_dir_def();
		if (!dir)
			AuFin("au_list_dir_def");
		need_ck = 0;
	}
	err = au_list_dir_set(dir, need_ck);
	if (err)
		AuFin("au_list_dir_set");
	/* unfree dir */
}
Exemple #6
0
int main(int argc, char *argv[])
{
	int err;
	char *mntpnt;

	opt(argc, argv);
	if (optind == argc) {
		//usage();
		errno = EINVAL;
		AuFin(NULL);
	}

	mntpnt = realpath(argv[optind], NULL);
	if (!mntpnt)
		AuFin("%s", mntpnt);
	err = chdir(mntpnt);
	if (err)
		AuFin("%s", mntpnt);

	if (!au_opt_test(fhsmd.optflags, NODAEMON)) {
		au_do_syslog = 1;
		openlog(program_invocation_short_name, AuFhsmd_OPTION,
			AuFhsmd_FACILITY);
		err = daemon(/*nochdir*/0, /*noclose*/0);
		if (err)
			AuFin("daemon");
	}

	shm_names(mntpnt, fhsmd.name, sizeof(*fhsmd.name));
	free(mntpnt);
	comm_fd(fhsmd.name[AuName_LCOPY].a, &fhsmd.fd[AuFd_FHSM],
		&fhsmd.fd[AuFd_MSG]);
	INIT_LIST_HEAD(&fhsmd.in_ope);
	err = au_fhsmd_load();
	if (err)
		AuLogFin("au_fhsmd_load");

	err = au_epsigfd();
	if (err)
		AuLogFin("create_epsig");
	err = au_ep_add(fhsmd.fd[AuFd_MSG], EPOLLIN | EPOLLPRI);
	if (err)
		AuLogFin("au_ep_add");
	err = au_ep_add(fhsmd.fd[AuFd_FHSM], EPOLLIN | EPOLLPRI);
	if (err)
		AuLogFin("au_ep_add");

	/* main loop */
	err = au_fhsmd_loop();

	AuDbgFhsmLog("exit %d", err);
	return err;
}
Exemple #7
0
/* todo: there are some cases which options are not changed */
static void update_mtab(FILE *fp, char *mntpnt, int do_remount, int do_verbose)
{
	int err;
	long pos;
	FILE *ofp;
	struct mntent ent, *p;

	/* prohibit updating mount options for this mntpnt */
	au_plink_maint(mntpnt);
	err = au_proc_getmntent(mntpnt, &ent);
	if (err)
		AuFin("no such mount point");

	ofp = setmntent(MTab, "r");
	if (!ofp)
		AuFin(MTab);

	if (do_remount) {
		/* find the last one */
		pos = -1;
		while ((p = getmntent(ofp))) {
			if (!strcmp(p->mnt_dir, mntpnt))
				pos = ftell(ofp);
		}
		rewind(ofp);

		if (pos > 0) {
			while ((p = getmntent(ofp))) {
				if (ftell(ofp) == pos) {
					/* replace the line */
					p = &ent;
					pos = -1;
				}
				err = addmntent(fp, p);
				if (err)
					AuFin("addmntent");
			}
			if (pos > 0)
				AuFin("internal error");
		} else
			append_mtab(fp, ofp, &ent);
	} else
		append_mtab(fp, ofp, &ent);

	endmntent(ofp); /* ignore */
	au_plink_maint(NULL);
	if (do_verbose)
		au_print_ent(&ent);
}
Exemple #8
0
static void append_mtab(FILE *fp, FILE *ofp, struct mntent *ent)
{
	int err;
	struct mntent *p;

	while ((p = getmntent(ofp))) {
		err = addmntent(fp, p);
		if (err)
			AuFin("addmntent");
	}

	err = addmntent(fp, ent);
	if (err)
		AuFin("addmntent");
}
Exemple #9
0
static int build_array(char *plink_dir)
{
	int err;
	DIR *dp;
	struct dirent *de;
	char *p;
	ino_t ino;

	err = access(plink_dir, F_OK);
	if (err)
		return 0;

	err = 0;
	dp = opendir(plink_dir);
	if (!dp)
		AuFin("%s", plink_dir);
	while ((de = readdir(dp))) {
		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
			continue;
#if 0
		if (de->d_type == DT_DIR) {
			errno = EISDIR;
			AuFin(de->d_name);
		}
#endif

		err = na_append(plink_dir, de->d_name);
		if (err)
			break;

		p = strchr(de->d_name, '.');
		if (!p) {
			errno = EINVAL;
			AuFin("internal error, %s", de->d_name);
		}
		*p = 0;
		errno = 0;
		ino = strtoull(de->d_name, NULL, 0);
		if (ino == /*ULLONG_MAX*/-1 && errno == ERANGE)
			AuFin("internal error, %s", de->d_name);
		err = ia_append(ino);
		if (err)
			break;
	}
	closedir(dp);

	return err;
}
Exemple #10
0
static int ftw_cpup(const char *fname, const struct stat *st, int flags,
		   struct FTW *ftw)
{
	int err;

	if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
		return FTW_SKIP_SUBTREE;
	if (flags == FTW_D || flags == FTW_DNR)
		return FTW_CONTINUE;

	/*
	 * do nothing but update something harmless in order to make it copyup
	 */
	if (ia_test(st->st_ino)) {
		Dpri("%s\n", fname);
		if (!S_ISLNK(st->st_mode))
			err = chown(fname, -1, -1);
		else
			err = lchown(fname, -1, -1);
		if (err)
			AuFin("%s", fname);
	}

	return FTW_CONTINUE;
}
Exemple #11
0
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[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");
}
Exemple #12
0
static void copy_ent(struct mntent *dst, struct mntent *src)
{
	free(dst->mnt_opts);
	free(dst->mnt_type);
	free(dst->mnt_dir);
	free(dst->mnt_fsname);

	dst->mnt_dir = NULL;
	dst->mnt_type = NULL;
	dst->mnt_opts = NULL;

	dst->mnt_fsname = strdup(src->mnt_fsname);
	if (dst->mnt_fsname)
		dst->mnt_dir = strdup(src->mnt_dir);
	if (dst->mnt_dir)
		dst->mnt_type = strdup(src->mnt_type);
	if (dst->mnt_type)
		dst->mnt_opts = strdup(src->mnt_opts);
	if (dst->mnt_opts) {
		dst->mnt_freq = src->mnt_freq;
		dst->mnt_passno = src->mnt_passno;
	} else
		AuFin("strdup");

}
Exemple #13
0
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);
}
Exemple #14
0
static void unlock_mtab(void)
{
	int err;

	err = rename(MTab "~", MTab);
	if (err)
		AuFin(MTab);
}
Exemple #15
0
void au_clean_plink(void)
{
	int err;

	err = ioctl(dirfd(dp), AUFS_CTL_PLINK_CLEAN);
#ifndef DEBUG
	if (err)
		AuFin("AUFS_CTL_PLINK_CLEAN");
#endif
}
Exemple #16
0
static void lock_mtab(char *pid_file)
{
	int err, i;

	for (i = 0; i < 5; i++) {
		err = link(pid_file, MTab "~");
		if (!err)
			break;
		sleep(1);
	}
	if (err)
		AuFin(MTab "~");
}
Exemple #17
0
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;
}
Exemple #18
0
static int ia_append(ino_t ino)
{
	int sz;
	char *p;
	const int cur = ia.p - ia.o;

	sz = na.bytes + sizeof(ino_t);
	p = realloc(ia.o, sz);
	if (!p)
		AuFin("realloc");

	ia.o = p;
	ia.bytes = sz;
	ia.p = p + cur;
	*ia.cur++ = ino;
	ia.nino++;

	return 0;
}
Exemple #19
0
static int na_append(char *plink_dir, char *name)
{
	int l, sz;
	char *p;
	const int cur = na.cur - na.o;

	l = strlen(plink_dir) + strlen(name) + 2;
	sz = na.bytes + l;
	p = realloc(na.o, sz);
	if (!p)
		AuFin("realloc");

	na.o = p;
	na.bytes = sz;
	na.cur = p + cur;
	na.cur += sprintf(na.cur, "%s/%s", plink_dir, name) + 1;
	na.nname++;

	return 0;
}
Exemple #20
0
int au_update_mtab(char *mntpnt, int do_remount, int do_verbose)
{
	int err, fd, status, e2;
	pid_t pid;
	ino_t ino;
	struct stat st;
	struct statfs stfs;
	struct flock flock = {
		.l_type		= F_WRLCK,
		.l_whence	= SEEK_SET,
		.l_start	= 0,
		.l_len		= 0
	};
	char pid_file[sizeof(MTab "~.") + 20];
	FILE *fp;

	err = statfs(MTab, &stfs);
	if (stfs.f_type == PROC_SUPER_MAGIC)
		return 0;

	snprintf(pid_file, sizeof(pid_file), MTab "~.%d", getpid());
	fd = open(pid_file, O_RDWR | O_CREAT | O_EXCL,
		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
	if (fd < 0)
		AuFin("%s", pid_file);
	err = fcntl(fd, F_SETLK, &flock);
	if (err)
		AuFin("%s", pid_file);
	fp = fdopen(fd, "r+");
	if (!fp)
		AuFin("%s", pid_file);

	pid = fork();
	if (!pid) {
		lock_mtab(pid_file);
		update_mtab(fp, mntpnt, do_remount, do_verbose);
		unlock_mtab();
		return 0;
	} else if (pid < 0)
		AuFin("fork");

	err = fstat(fd, &st);
	if (err)
		perror(pid_file);
	ino = st.st_ino;

	err = waitpid(pid, &status, 0);
	if (err < 0) {
		perror(pid_file);
		goto out;
	}
	err = !WIFEXITED(status);
	if (!err)
		err = WEXITSTATUS(status);

	e2 = unlink(pid_file);
	if (e2 && errno != ENOENT)
		perror(pid_file);
	e2 = stat(MTab "~", &st);
	if (!e2) {
		if (st.st_ino == ino) {
			/*
			 * The inode number is same,
			 * it means it is we who made the file.
			 * If someone else removed our file between stat(2) and
			 * unlink(2), it is a breakage of the rule.
			 */
			e2 = unlink(MTab "~");
			if (e2)
				perror(MTab);
		}
	} else if (errno != ENOENT)
		perror(MTab "~");
	fclose(fp);

 out:
	return err;
}
Exemple #21
0
static int do_plink(char *cwd, int cmd, int nbr, char *br[])
{
	int err, i, l;
	struct rlimit rlim;
	__nftw_func_t func;
	char *p;

	err = 0;
	switch (cmd) {
	case AuPlink_FLUSH:
		/*FALLTHROUGH*/
	case AuPlink_CPUP:
		func = ftw_cpup;
		break;
	case AuPlink_LIST:
		func = ftw_list;
		break;
	default:
		errno = EINVAL;
		AuFin(NULL);
		func = NULL; /* never reach here */
	}

	for (i = 0; i < nbr; i++) {
		//puts(br[i]);
		p = strchr(br[i], '=');
		if (strcmp(p + 1, AUFS_BRPERM_RW)
		    && strcmp(p + 1, AUFS_BRPERM_RWNLWH))
			continue;

		*p = 0;
		l = strlen(br[i]);
		p = malloc(l + sizeof(AUFS_WH_PLINKDIR) + 2);
		if (!p)
			AuFin("malloc");
		sprintf(p, "%s/%s", br[i], AUFS_WH_PLINKDIR);
		//puts(p);
		err = build_array(p);
		if (err)
			AuFin("build_array");
		free(p);
	}
	if (!ia.nino)
		goto out;

	if (cmd == AuPlink_LIST) {
		ia.p = ia.o;
		for (i = 0; i < ia.nino; i++)
			printf("%llu ", (unsigned long long)*ia.cur++);
		putchar('\n');
	}

	err = getrlimit(RLIMIT_NOFILE, &rlim);
	if (err)
		AuFin("getrlimit");
	nftw(cwd, func, rlim.rlim_cur - 10,
	     FTW_PHYS | FTW_MOUNT | FTW_ACTIONRETVAL);
	/* ignore */

	if (cmd == AuPlink_FLUSH) {
		au_clean_plink();

		na.cur = na.o;
		for (i = 0; i < na.nname; i++) {
			Dpri("%s\n", na.cur);
			err = unlink(na.cur);
			if (err)
				AuFin("%s", na.cur);
			na.cur += strlen(na.cur) + 1;
		}
	}

 out:
	free(ia.o);
	free(na.o);
	return err;
}
Exemple #22
0
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, "nvo:")) != -1) {
		switch (c) {
		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(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]) {
			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;
}