266 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* mkdir - Make directories		Author: V. Archer */
 | |
| 
 | |
| /* Copyright 1991 by Vincent Archer
 | |
|  *	You may freely redistribute this software, in source or binary
 | |
|  *	form, provided that you do not alter this copyright mention in any
 | |
|  *	way.
 | |
|  */
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <minix/minlib.h>
 | |
| #include <limits.h>
 | |
| #include <errno.h>
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| extern int optind, opterr;
 | |
| extern char *optarg;
 | |
| 
 | |
| #define USR_MODES (S_ISUID|S_IRWXU)
 | |
| #define GRP_MODES (S_ISGID|S_IRWXG)
 | |
| #define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH)
 | |
| #ifdef S_ISVTX
 | |
| #define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX)
 | |
| #else
 | |
| #define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO)
 | |
| #endif
 | |
| #define DEFAULT_MODE (S_IRWXU|S_IRWXG|S_IRWXO)
 | |
| #define USER_WX (S_IWUSR|S_IXUSR)
 | |
| 
 | |
| 
 | |
| /* Global variables */
 | |
| int pflag;
 | |
| char *symbolic;
 | |
| mode_t u_mask;
 | |
| struct stat st;
 | |
| 
 | |
| _PROTOTYPE(int main, (int argc, char **argv));
 | |
| _PROTOTYPE(mode_t parsemode, (char *symbolic, Mode_t oldmode));
 | |
| _PROTOTYPE(int makepath, (char *fordir));
 | |
| _PROTOTYPE(int makedir, (char *dirname));
 | |
| _PROTOTYPE(void usage, (void));
 | |
| 
 | |
| /* Parse a P1003.2 4.7.7-conformant symbolic mode. */
 | |
| mode_t parsemode(symbolic, oldmode)
 | |
| char *symbolic;
 | |
| mode_t oldmode;
 | |
| {
 | |
|   mode_t who, mask, newmode, tmpmask;
 | |
|   char action;
 | |
|   char *end;
 | |
|   unsigned long octalmode;
 | |
| 
 | |
|   octalmode = strtoul(symbolic, &end, 010);
 | |
|   if (octalmode < ALL_MODES && *end == 0 && end != symbolic) return octalmode;
 | |
| 
 | |
|   newmode = oldmode & ALL_MODES;
 | |
|   while (*symbolic) {
 | |
| 	who = 0;
 | |
| 	for (; *symbolic; symbolic++) {
 | |
| 		if (*symbolic == 'a') {
 | |
| 			who |= ALL_MODES;
 | |
| 			continue;
 | |
| 		}
 | |
| 		if (*symbolic == 'u') {
 | |
| 			who |= USR_MODES;
 | |
| 			continue;
 | |
| 		}
 | |
| 		if (*symbolic == 'g') {
 | |
| 			who |= GRP_MODES;
 | |
| 			continue;
 | |
| 		}
 | |
| 		if (*symbolic == 'o') {
 | |
| 			who |= S_IRWXO;
 | |
| 			continue;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	if (!*symbolic || *symbolic == ',') usage();
 | |
| 	while (*symbolic) {
 | |
| 		if (*symbolic == ',') break;
 | |
| 		switch (*symbolic) {
 | |
| 		    default:
 | |
| 			usage();
 | |
| 		    case '+':
 | |
| 		    case '-':
 | |
| 		    case '=':	action = *symbolic++;
 | |
| 		}
 | |
| 		mask = 0;
 | |
| 		for (; *symbolic; symbolic++) {
 | |
| 			if (*symbolic == 'u') {
 | |
| 				tmpmask = newmode & S_IRWXU;
 | |
| 				mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6);
 | |
| 				symbolic++;
 | |
| 				break;
 | |
| 			}
 | |
| 			if (*symbolic == 'g') {
 | |
| 				tmpmask = newmode & S_IRWXG;
 | |
| 				mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
 | |
| 				symbolic++;
 | |
| 				break;
 | |
| 			}
 | |
| 			if (*symbolic == 'o') {
 | |
| 				tmpmask = newmode & S_IRWXO;
 | |
| 				mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
 | |
| 				symbolic++;
 | |
| 				break;
 | |
| 			}
 | |
| 			if (*symbolic == 'r') {
 | |
| 				mask |= S_IRUSR | S_IRGRP | S_IROTH;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (*symbolic == 'w') {
 | |
| 				mask |= S_IWUSR | S_IWGRP | S_IWOTH;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (*symbolic == 'x') {
 | |
| 				mask |= EXE_MODES;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (*symbolic == 's') {
 | |
| 				mask |= S_ISUID | S_ISGID;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (*symbolic == 'X') {
 | |
| 				if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
 | |
| 					mask |= EXE_MODES;
 | |
| 				continue;
 | |
| 			}
 | |
| #ifdef S_ISVTX
 | |
| 			if (*symbolic == 't') {
 | |
| 				mask |= S_ISVTX;
 | |
| 				who |= S_ISVTX;
 | |
| 				continue;
 | |
| 			}
 | |
| #endif
 | |
| 			break;
 | |
| 		}
 | |
| 		switch (action) {
 | |
| 		    case '=':
 | |
| 			if (who)
 | |
| 				newmode &= ~who;
 | |
| 			else
 | |
| 				newmode = 0;
 | |
| 		    case '+':
 | |
| 			if (who)
 | |
| 				newmode |= who & mask;
 | |
| 			else
 | |
| 				newmode |= mask & (~u_mask);
 | |
| 			break;
 | |
| 		    case '-':
 | |
| 			if (who)
 | |
| 				newmode &= ~(who & mask);
 | |
| 			else
 | |
| 				newmode &= ~mask | u_mask;
 | |
| 		}
 | |
| 	}
 | |
| 	if (*symbolic) symbolic++;
 | |
|   }
 | |
|   return(newmode);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Main module. */
 | |
| int main(argc, argv)
 | |
| int argc;
 | |
| char **argv;
 | |
| {
 | |
|   int error, c;
 | |
| 
 | |
|   opterr = 0;
 | |
|   pflag = 0;
 | |
|   symbolic = (char *) 0;
 | |
|   u_mask = umask(0);
 | |
|   umask(u_mask);
 | |
|   while ((c = getopt(argc, argv, "m:p")) != EOF) switch (c) {
 | |
| 	    case 'm':	symbolic = optarg;	break;
 | |
| 	    case 'p':	pflag = 1;	break;
 | |
| 	    default:	usage();
 | |
| 	}
 | |
|   if (optind >= argc) usage();
 | |
| 
 | |
|   error = 0;
 | |
|   while (optind < argc) error |= makedir(argv[optind++]);
 | |
|   return(error);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* P1003.2 requires that missing intermediate pathname components should be
 | |
|  *	created if the -p option is specified (4.40.3).
 | |
|  */
 | |
| int makepath(fordir)
 | |
| char *fordir;
 | |
| {
 | |
|   char parent[PATH_MAX + 1], *end;
 | |
| 
 | |
|   strcpy(parent, fordir);
 | |
|   if (!(end = strrchr(parent, '/'))) return(0);
 | |
|   *end = '\0';
 | |
|   if (!parent[0]) return(0);
 | |
| 
 | |
|   if (!stat(parent, &st)) {
 | |
| 	if (S_ISDIR(st.st_mode)) return(0);
 | |
| 	errno = ENOTDIR;
 | |
| 	perror(parent);
 | |
| 	return(1);
 | |
|   }
 | |
|   if (mkdir(parent, DEFAULT_MODE)) {
 | |
| 	if (makepath(parent)) return(1);
 | |
| 	if (mkdir(parent, DEFAULT_MODE)) {
 | |
| 		perror(parent);
 | |
| 		return(1);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
| /* P1003.2 states that, regardless of umask() value, intermediate paths
 | |
|  *	should have at least write and search (x) permissions (4.40.10).
 | |
|  */
 | |
|   if ((u_mask & USER_WX) &&
 | |
|       chmod(parent, ((~u_mask) | USER_WX)) & DEFAULT_MODE) {
 | |
| 	perror(parent);
 | |
| 	return(1);
 | |
|   }
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Actual directory creation, using a mkdir() system call. */
 | |
| int makedir(dirname)
 | |
| char *dirname;
 | |
| {
 | |
|   if (mkdir(dirname, DEFAULT_MODE)) {
 | |
| 	if (!pflag) {
 | |
| 		perror(dirname);
 | |
| 		return(1);
 | |
| 	}
 | |
| 	if (!stat(dirname, &st)) {
 | |
| 		if (S_ISDIR(st.st_mode)) return(0);
 | |
| 		errno = ENOTDIR;
 | |
| 		perror(dirname);
 | |
| 		return(1);
 | |
| 	}
 | |
| 	if (makepath(dirname)) return(1);
 | |
| 	if (mkdir(dirname, DEFAULT_MODE)) {
 | |
| 		perror(dirname);
 | |
| 		return(1);
 | |
| 	}
 | |
|   }
 | |
|   if (symbolic && (stat(dirname, &st) ||
 | |
| 		 chmod(dirname, parsemode(symbolic, st.st_mode)))) {
 | |
| 	perror(dirname);
 | |
| 	return(1);
 | |
|   }
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Posix command prototype. */
 | |
| void usage()
 | |
| {
 | |
|   std_err("Usage: mkdir [-p] [-m mode] dir...\n");
 | |
|   exit(1);
 | |
| }
 | 
