| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | /* See LICENSE file for copyright and license details. */ | 
					
						
							|  |  |  | #include <stdbool.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | #include "util.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void chmodr(const char *); | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | static void parsemode(const char *); | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static bool rflag = false; | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | static char oper = '='; | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | static mode_t mode = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | usage(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-10-10 14:50:52 +01:00
										 |  |  | 	eprintf("usage: %s [-R] mode [file...]\n", argv0); | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | int | 
					
						
							|  |  |  | main(int argc, char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-10-10 14:50:52 +01:00
										 |  |  | 	int c; | 
					
						
							|  |  |  | 	argv0 = argv[0]; | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 14:50:52 +01:00
										 |  |  | 	while (--argc > 0 && (*++argv)[0] == '-') { | 
					
						
							|  |  |  | 		while ((c = *++argv[0])) { | 
					
						
							|  |  |  | 			switch (c) { | 
					
						
							|  |  |  | 			case 'R': | 
					
						
							|  |  |  | 				rflag = true; | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2013-10-20 10:53:43 +02:00
										 |  |  | 			case 'r': case 'w': case 'x': case 's': case 't': | 
					
						
							| 
									
										
										
										
											2013-10-10 14:50:52 +01:00
										 |  |  | 				/*
 | 
					
						
							| 
									
										
										
										
											2013-10-20 10:53:43 +02:00
										 |  |  | 				 * -[rwxst] are valid modes so do not interpret | 
					
						
							| 
									
										
										
										
											2013-10-10 14:50:52 +01:00
										 |  |  | 				 * them as options - in any case we are done if | 
					
						
							|  |  |  | 				 * we hit this case | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				--argv[0]; | 
					
						
							|  |  |  | 				goto done; | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				usage(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	parsemode(argv[0]); | 
					
						
							|  |  |  | 	argv++; | 
					
						
							|  |  |  | 	argc--; | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(argc < 1) | 
					
						
							|  |  |  | 		usage(); | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 14:50:52 +01:00
										 |  |  | 	for (; argc > 0; argc--, argv++) | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 		chmodr(argv[0]); | 
					
						
							| 
									
										
										
										
											2013-10-07 16:41:55 +01:00
										 |  |  | 	return EXIT_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | chmodr(const char *path) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 	struct stat st; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(stat(path, &st) == -1) | 
					
						
							|  |  |  | 		eprintf("stat %s:", path); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(oper) { | 
					
						
							|  |  |  | 	case '+': | 
					
						
							|  |  |  | 		st.st_mode |= mode; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case '-': | 
					
						
							|  |  |  | 		st.st_mode &= ~mode; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2011-06-11 00:31:44 +01:00
										 |  |  | 	case '=': | 
					
						
							|  |  |  | 		st.st_mode = mode; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if(chmod(path, st.st_mode) == -1) | 
					
						
							| 
									
										
										
										
											2011-05-27 23:48:07 +01:00
										 |  |  | 		eprintf("chmod %s:", path); | 
					
						
							|  |  |  | 	if(rflag) | 
					
						
							|  |  |  | 		recurse(path, chmodr); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | parsemode(const char *str) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *end; | 
					
						
							|  |  |  | 	const char *p; | 
					
						
							|  |  |  | 	int octal; | 
					
						
							|  |  |  | 	mode_t mask = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	octal = strtol(str, &end, 8); | 
					
						
							|  |  |  | 	if(*end == '\0') { | 
					
						
							| 
									
										
										
										
											2014-02-01 19:48:57 +00:00
										 |  |  | 		if( octal < 0 || octal > 07777) eprintf("invalid mode\n"); | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 		if(octal & 04000) mode |= S_ISUID; | 
					
						
							|  |  |  | 		if(octal & 02000) mode |= S_ISGID; | 
					
						
							| 
									
										
										
										
											2013-10-20 10:50:58 +02:00
										 |  |  | 		if(octal & 01000) mode |= S_ISVTX; | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 		if(octal & 00400) mode |= S_IRUSR; | 
					
						
							|  |  |  | 		if(octal & 00200) mode |= S_IWUSR; | 
					
						
							|  |  |  | 		if(octal & 00100) mode |= S_IXUSR; | 
					
						
							|  |  |  | 		if(octal & 00040) mode |= S_IRGRP; | 
					
						
							|  |  |  | 		if(octal & 00020) mode |= S_IWGRP; | 
					
						
							|  |  |  | 		if(octal & 00010) mode |= S_IXGRP; | 
					
						
							|  |  |  | 		if(octal & 00004) mode |= S_IROTH; | 
					
						
							|  |  |  | 		if(octal & 00002) mode |= S_IWOTH; | 
					
						
							|  |  |  | 		if(octal & 00001) mode |= S_IXOTH; | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2014-02-01 19:48:57 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		eprintf("not octal\n"); | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for(p = str; *p; p++) | 
					
						
							|  |  |  | 		switch(*p) { | 
					
						
							|  |  |  | 		/* masks */ | 
					
						
							|  |  |  | 		case 'u': | 
					
						
							|  |  |  | 			mask |= S_IRWXU; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'g': | 
					
						
							|  |  |  | 			mask |= S_IRWXG; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'o': | 
					
						
							|  |  |  | 			mask |= S_IRWXO; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'a': | 
					
						
							|  |  |  | 			mask |= S_IRWXU|S_IRWXG|S_IRWXO; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		/* opers */ | 
					
						
							|  |  |  | 		case '+': | 
					
						
							|  |  |  | 		case '-': | 
					
						
							|  |  |  | 		case '=': | 
					
						
							|  |  |  | 			oper = *p; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		/* modes */ | 
					
						
							|  |  |  | 		case 'r': | 
					
						
							|  |  |  | 			mode |= S_IRUSR|S_IRGRP|S_IROTH; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'w': | 
					
						
							|  |  |  | 			mode |= S_IWUSR|S_IWGRP|S_IWOTH; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'x': | 
					
						
							|  |  |  | 			mode |= S_IXUSR|S_IXGRP|S_IXOTH; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 's': | 
					
						
							|  |  |  | 			mode |= S_ISUID|S_ISGID; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2013-10-20 10:50:58 +02:00
										 |  |  | 		case 't': | 
					
						
							|  |  |  | 			mode |= S_ISVTX; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 			/* error */ | 
					
						
							| 
									
										
										
										
											2011-06-11 00:30:07 +01:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			eprintf("%s: invalid mode\n", str); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	if(mask) | 
					
						
							|  |  |  | 		mode &= mask; | 
					
						
							|  |  |  | } |