mirror of https://github.com/trapexit/mergerfs.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							231 lines
						
					
					
						
							4.5 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							231 lines
						
					
					
						
							4.5 KiB
						
					
					
				| /* | |
|   FUSE: Filesystem in Userspace | |
|   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> | |
|  | |
|   This program can be distributed under the terms of the GNU GPL. | |
|   See the file COPYING. | |
| */ | |
| 
 | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <errno.h> | |
|  | |
| static char *progname; | |
| 
 | |
| static char *xstrdup(const char *s) | |
| { | |
| 	char *t = strdup(s); | |
| 	if (!t) { | |
| 		fprintf(stderr, "%s: failed to allocate memory\n", progname); | |
| 		exit(1); | |
| 	} | |
| 	return t; | |
| } | |
| 
 | |
| static void *xrealloc(void *oldptr, size_t size) | |
| { | |
| 	void *ptr = realloc(oldptr, size); | |
| 	if (!ptr) { | |
| 		fprintf(stderr, "%s: failed to allocate memory\n", progname); | |
| 		exit(1); | |
| 	} | |
| 	return ptr; | |
| } | |
| 
 | |
| static void add_arg(char **cmdp, const char *opt) | |
| { | |
| 	size_t optlen = strlen(opt); | |
| 	size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; | |
| 	char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); | |
| 	char *s; | |
| 	s = cmd + cmdlen; | |
| 	if (*cmdp) | |
| 		*s++ = ' '; | |
| 
 | |
| 	*s++ = '\''; | |
| 	for (; *opt; opt++) { | |
| 		if (*opt == '\'') { | |
| 			*s++ = '\''; | |
| 			*s++ = '\\'; | |
| 			*s++ = '\''; | |
| 			*s++ = '\''; | |
| 		} else | |
| 			*s++ = *opt; | |
| 	} | |
| 	*s++ = '\''; | |
| 	*s = '\0'; | |
| 	*cmdp = cmd; | |
| } | |
| 
 | |
| static char *add_option(const char *opt, char *options) | |
| { | |
| 	int oldlen = options ? strlen(options) : 0; | |
| 
 | |
| 	options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); | |
| 	if (!oldlen) | |
| 		strcpy(options, opt); | |
| 	else { | |
| 		strcat(options, ","); | |
| 		strcat(options, opt); | |
| 	} | |
| 	return options; | |
| } | |
| 
 | |
| int main(int argc, char *argv[]) | |
| { | |
| 	char *type = NULL; | |
| 	char *source; | |
| 	const char *mountpoint; | |
| 	char *basename; | |
| 	char *options = NULL; | |
| 	char *command = NULL; | |
| 	char *setuid = NULL; | |
| 	int i; | |
| 	int dev = 1; | |
| 	int suid = 1; | |
| 
 | |
| 	progname = argv[0]; | |
| 	basename = strrchr(argv[0], '/'); | |
| 	if (basename) | |
| 		basename++; | |
| 	else | |
| 		basename = argv[0]; | |
| 
 | |
|         type = "mergerfs"; | |
| 	if (strncmp(basename, "mount.fuse.", 11) == 0) | |
| 		type = basename + 11; | |
| 	if (strncmp(basename, "mount.fuseblk.", 14) == 0) | |
| 		type = basename + 14; | |
| 
 | |
| 	if (type && !type[0]) | |
| 		type = NULL; | |
| 
 | |
| 	if (argc < 3) { | |
| 		fprintf(stderr, | |
| 			"usage: %s %s destination [-t type] [-o opt[,opts...]]\n", | |
| 			progname, type ? "source" : "type#[source]"); | |
| 		exit(1); | |
| 	} | |
| 
 | |
| 	source = argv[1]; | |
| 	if (!source[0]) | |
| 		source = NULL; | |
| 
 | |
| 	mountpoint = argv[2]; | |
| 
 | |
| 	for (i = 3; i < argc; i++) { | |
| 		if (strcmp(argv[i], "-v") == 0) { | |
| 			continue; | |
| 		} else if (strcmp(argv[i], "-t") == 0) { | |
| 			i++; | |
| 
 | |
| 			if (i == argc) { | |
| 				fprintf(stderr, | |
| 					"%s: missing argument to option '-t'\n", | |
| 					progname); | |
| 				exit(1); | |
| 			} | |
| 			type = argv[i]; | |
| 			if (strncmp(type, "fuse.", 5) == 0) | |
| 				type += 5; | |
| 			else if (strncmp(type, "fuseblk.", 8) == 0) | |
| 				type += 8; | |
| 
 | |
| 			if (!type[0]) { | |
| 				fprintf(stderr, | |
| 					"%s: empty type given as argument to option '-t'\n", | |
| 					progname); | |
| 				exit(1); | |
| 			} | |
| 		} else	if (strcmp(argv[i], "-o") == 0) { | |
| 			char *opts; | |
| 			char *opt; | |
| 			i++; | |
| 			if (i == argc) | |
| 				break; | |
| 
 | |
| 			opts = xstrdup(argv[i]); | |
| 			opt = strtok(opts, ","); | |
| 			while (opt) { | |
| 				int j; | |
| 				int ignore = 0; | |
| 				const char *ignore_opts[] = { "", | |
| 							      "user", | |
| 							      "nouser", | |
| 							      "users", | |
| 							      "auto", | |
| 							      "noauto", | |
| 							      "_netdev", | |
| 							      NULL}; | |
| 				if (strncmp(opt, "setuid=", 7) == 0) { | |
| 					setuid = xstrdup(opt + 7); | |
| 					ignore = 1; | |
| 				} | |
| 				for (j = 0; ignore_opts[j]; j++) | |
| 					if (strcmp(opt, ignore_opts[j]) == 0) | |
| 						ignore = 1; | |
| 
 | |
| 				if (!ignore) { | |
| 					if (strcmp(opt, "nodev") == 0) | |
| 						dev = 0; | |
| 					else if (strcmp(opt, "nosuid") == 0) | |
| 						suid = 0; | |
| 
 | |
| 					options = add_option(opt, options); | |
| 				} | |
| 				opt = strtok(NULL, ","); | |
| 			} | |
| 		} | |
| 	} | |
| 
 | |
| 	if (dev) | |
| 		options = add_option("dev", options); | |
| 	if (suid) | |
| 		options = add_option("suid", options); | |
| 
 | |
| 	if (!type) { | |
| 		if (source) { | |
| 			type = xstrdup(source); | |
| 			source = strchr(type, '#'); | |
| 			if (source) | |
| 				*source++ = '\0'; | |
| 			if (!type[0]) { | |
| 				fprintf(stderr, "%s: empty filesystem type\n", | |
| 					progname); | |
| 				exit(1); | |
| 			} | |
| 		} else { | |
| 			fprintf(stderr, "%s: empty source\n", progname); | |
| 			exit(1); | |
| 		} | |
| 	} | |
| 
 | |
| 	add_arg(&command, type); | |
| 	if (source) | |
| 		add_arg(&command, source); | |
| 	add_arg(&command, mountpoint); | |
| 	if (options) { | |
| 		add_arg(&command, "-o"); | |
| 		add_arg(&command, options); | |
| 	} | |
| 
 | |
| 	if (setuid && setuid[0]) { | |
| 		char *sucommand = command; | |
| 		command = NULL; | |
| 		add_arg(&command, "su"); | |
| 		add_arg(&command, "-"); | |
| 		add_arg(&command, setuid); | |
| 		add_arg(&command, "-c"); | |
| 		add_arg(&command, sucommand); | |
| 	} else if (!getenv("HOME")) { | |
| 		/* Hack to make filesystems work in the boot environment */ | |
| 		setenv("HOME", "/root", 0); | |
| 	} | |
| 
 | |
| 	execl("/bin/sh", "/bin/sh", "-c", command, NULL); | |
| 	fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, | |
| 		strerror(errno)); | |
| 	return 1; | |
| }
 |