|
|
1.1 ! root 1: /* ! 2: * chmog -- change the mode, owner, and group of files. ! 3: * ! 4: * This program was done from the 'chmod', 'chown', and 'chgrp' ! 5: * As result code may not be optimal, but should be pretty reliable ! 6: * and be backword compatible (including bugs and bad design as exit(2)). ! 7: * ! 8: * chmog should be link to chown, chmod, and chgrp. BTW it saves about ! 9: * 15K :-). ! 10: * ! 11: * 1-31-92 Vlad ! 12: */ ! 13: ! 14: #include <stdio.h> ! 15: #include <pwd.h> ! 16: #include <grp.h> ! 17: #include <ctype.h> ! 18: #include <sys/stat.h> ! 19: #include <string.h> ! 20: ! 21: /* Masks by types of permissions */ ! 22: #define AEXEC (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) ! 23: #define AREAD (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) ! 24: #define AWRITE (S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6)) ! 25: #define ASUID (S_ISUID|S_ISGID) ! 26: #define ATEXT S_ISVTX ! 27: ! 28: /* Masks by types of users */ ! 29: #define AOWN (S_ISUID|S_ISVTX|S_IREAD|S_IWRITE|S_IEXEC) ! 30: #define AGRP (S_ISGID|S_ISVTX|(S_IREAD>>3)|(S_IWRITE>>3)|(S_IEXEC>>3)) ! 31: #define AOTH (S_ISVTX|(S_IREAD>>6)|(S_IWRITE>>6)|(S_IEXEC>>6)) ! 32: #define AALL (AOWN|AGRP|AOTH) ! 33: ! 34: short int uid; ! 35: ! 36: char *chmod_usage = "chmod mode file ..."; ! 37: char *chown_usage = "chown owner file ..."; ! 38: char *chgrp_usage = "chgrp group file ..."; ! 39: char *chmog_usage = "chmog mod owner group file ..."; ! 40: ! 41: char stickwarn[] = "\ ! 42: chmod: Warning: non-super user may not set sticky bit\n\ ! 43: "; ! 44: ! 45: main(argc, argv) ! 46: int argc; ! 47: char *argv[]; ! 48: { ! 49: char *cmdname; /* Name of the command */ ! 50: ! 51: /* Strip the pathname off of the name of the executable */ ! 52: if ((cmdname = strrchr(argv[0], '/')) != (char *) NULL) ! 53: cmdname++; ! 54: else ! 55: cmdname = argv[0]; ! 56: ! 57: /* Who am I? */ ! 58: if (!strcmp(cmdname, "chmod")) ! 59: cmd_chmod(argc, argv, 0); /* Emulate chmod */ ! 60: else if (!strcmp(cmdname, "chown")) ! 61: cmd_chown(argc, argv, 0, 0); /* Emulate chown */ ! 62: else if (!strcmp(cmdname, "chgrp")) ! 63: cmd_chgrp(argc, argv, 0, 0); /* Emulate chgrp */ ! 64: else if (!strcmp(cmdname, "chmog")) ! 65: chmog(argc, argv); /* Be itself */ ! 66: else /* If some entysiast will link to a different name....*/ ! 67: usage(chmog_usage); ! 68: exit(0); ! 69: } ! 70: ! 71: /* ! 72: * This is main entry for chmog. Call all functions (*chmod, *chown, *chgrp) ! 73: * and set the proper shifts of the argv. If correspoding *argv is '-' ! 74: * it means that this characteristic of file should be unchanged. ! 75: */ ! 76: chmog(argc, argv) ! 77: int argc; ! 78: char **argv; ! 79: { ! 80: if (argc < 5) ! 81: usage(chmog_usage); ! 82: ! 83: /* Change owner */ ! 84: if (strcmp(argv[2], "-")) ! 85: cmd_chown(argc, argv, 1, 2); ! 86: /* Change group */ ! 87: if (strcmp(argv[3], "-")) ! 88: cmd_chgrp(argc, argv, 2, 2); ! 89: /* Change mode. We want to do it at the very and, otherwise ! 90: * chown or chgrp will remove setuid & setgid bits ! 91: */ ! 92: if (strcmp(argv[1], "-")) ! 93: cmd_chmod(argc, argv, 2); ! 94: exit(0); ! 95: } ! 96: ! 97: /* ! 98: * Change mode of the file. ! 99: */ ! 100: cmd_chmod(argc, argv, shift_file) ! 101: int argc; ! 102: char **argv; ! 103: int shift_file; /* Shift argv to the file names */ ! 104: { ! 105: register int i; ! 106: register char *fn; ! 107: int status = 0; ! 108: ! 109: if (argc < 3) ! 110: usage(chmod_usage); ! 111: uid = getuid(); ! 112: for (i = 2 + shift_file; i < argc; i++) { ! 113: fn = argv[i]; ! 114: if (chmod(fn, readmode(argv[1], fn)) < 0) { ! 115: perror(fn); ! 116: status = 2; ! 117: } ! 118: } ! 119: if (status) ! 120: exit(status); ! 121: } ! 122: ! 123: /* ! 124: * Read in the symbolic mode and ! 125: * set the variables `who', `op', ! 126: * and `mode'. ! 127: * Knows about the old octal modes as well. ! 128: */ ! 129: readmode(s, file) ! 130: register char *s; ! 131: char *file; ! 132: { ! 133: register int c; ! 134: register int mode; ! 135: register int op; ! 136: register int m1, m2; ! 137: struct stat sb; ! 138: ! 139: mode = 0; ! 140: if (*s>='0' && *s<='7') { ! 141: while (*s != '\0') { ! 142: if (*s<'0' || *s>'7') ! 143: omusage(); ! 144: mode = (mode<<3) | *s++-'0'; ! 145: } ! 146: checkmode(mode); ! 147: return (mode); ! 148: } ! 149: sb.st_mode = 0; ! 150: stat(file, &sb); ! 151: mode = sb.st_mode; ! 152: newsym: ! 153: m1 = 0; ! 154: for (;;) { ! 155: switch (*s++) { ! 156: case 'u': ! 157: m1 |= AOWN; ! 158: continue; ! 159: ! 160: case 'g': ! 161: m1 |= AGRP; ! 162: continue; ! 163: ! 164: case 'o': ! 165: m1 |= AOTH; ! 166: continue; ! 167: ! 168: case 'a': ! 169: m1 |= AALL; ! 170: continue; ! 171: ! 172: default: ! 173: s--; ! 174: break; ! 175: } ! 176: break; ! 177: } ! 178: if (m1 == 0) { ! 179: m1 = AALL&~getumask(); ! 180: } ! 181: newop: ! 182: if ((c = *s++)=='=' || c=='+' || c=='-') ! 183: op = c; ! 184: else ! 185: smusage(); ! 186: m2 = 0; ! 187: for (;;) { ! 188: switch (*s++) { ! 189: case 'r': ! 190: m2 |= AREAD; ! 191: continue; ! 192: ! 193: case 'w': ! 194: m2 |= AWRITE; ! 195: continue; ! 196: ! 197: case 'x': ! 198: m2 |= AEXEC; ! 199: continue; ! 200: ! 201: case 's': ! 202: m2 |= ASUID; ! 203: continue; ! 204: ! 205: case 't': ! 206: m2 |= ATEXT; ! 207: continue; ! 208: ! 209: case 'u': ! 210: m2 |= mrepl(mode&AOWN); ! 211: continue; ! 212: ! 213: case 'g': ! 214: m2 |= mrepl((mode&AGRP)<<3); ! 215: continue; ! 216: ! 217: case 'o': ! 218: m2 |= mrepl((mode&AOTH)<<6); ! 219: continue; ! 220: ! 221: default: ! 222: s--; ! 223: break; ! 224: } ! 225: break; ! 226: } ! 227: switch (op) { ! 228: case '-': ! 229: mode &= ~(m1&m2); ! 230: break; ! 231: ! 232: case '+': ! 233: mode |= m1&m2; ! 234: break; ! 235: ! 236: case '=': ! 237: mode = (mode&~m1) | (m1&m2); ! 238: break; ! 239: } ! 240: if (*s == '\0') { ! 241: checkmode(mode); ! 242: return (mode); ! 243: } ! 244: if (*s=='+' || *s=='-' || *s=='=') ! 245: goto newop; ! 246: if (*s++ == ',') ! 247: goto newsym; ! 248: smusage(); ! 249: } ! 250: ! 251: /* ! 252: * Get the value of the umask setting. ! 253: */ ! 254: getumask() ! 255: { ! 256: register int omask; ! 257: ! 258: omask = umask(0); ! 259: umask(omask); ! 260: return (omask); ! 261: } ! 262: ! 263: /* ! 264: * Check the mode to see if any problem ! 265: * bits are on. For now, this is ! 266: * S_ISVTX for non-super-users. ! 267: */ ! 268: checkmode(mode) ! 269: register int mode; ! 270: { ! 271: static int beenhere; ! 272: ! 273: if (!beenhere && uid!=0 && mode&S_ISVTX) { ! 274: fprintf(stderr, stickwarn); ! 275: beenhere++; ! 276: } ! 277: } ! 278: ! 279: /* ! 280: * Replicate the 3-bits of the mode from ! 281: * the owner position to all positions. ! 282: */ ! 283: mrepl(m) ! 284: register int m; ! 285: { ! 286: register int m1; ! 287: ! 288: m1 = m&AOWN; ! 289: m = m1 | (m1>>3) | (m1>>6); ! 290: if (m1 & S_ISUID) ! 291: m |= S_ISGID; ! 292: return (m); ! 293: } ! 294: ! 295: smusage() ! 296: { ! 297: fprintf(stderr, "chmod: badly formed symbolic mode\n"); ! 298: exit(1); ! 299: } ! 300: ! 301: omusage() ! 302: { ! 303: fprintf(stderr, "chmod: badly formed octal mode\n"); ! 304: exit(1); ! 305: } ! 306: ! 307: /* ! 308: * Change owner of the file ! 309: */ ! 310: cmd_chown(argc, argv, shift_cmd, shift_file) ! 311: int argc; ! 312: char **argv; ! 313: int shift_cmd; /* Shift argv to the owner */ ! 314: int shift_file; /* Shift argv to the file names */ ! 315: { ! 316: register struct passwd *pwp; ! 317: register int c; ! 318: register short owner, group; ! 319: struct stat sb; ! 320: register short status = 0; ! 321: int i_cmd; ! 322: int i_file; ! 323: ! 324: if (argc < 3) ! 325: usage(chown_usage); ! 326: i_cmd = 1 + shift_cmd; ! 327: i_file = 2 + shift_file; ! 328: ! 329: if ((c = *argv[i_cmd]) >='0' && c <= '9') ! 330: owner = atoi(argv[i_cmd]); ! 331: else { ! 332: if ((pwp = getpwnam(argv[i_cmd])) == NULL) ! 333: cherr("%s: bad username `%s'\n", argv[0], argv[i_cmd]); ! 334: owner = pwp->pw_uid; ! 335: } ! 336: for (c = i_file; c < argc; c++) { ! 337: group = 0; ! 338: if (stat(argv[c], &sb) >= 0) ! 339: group = sb.st_gid; ! 340: if (chown(argv[c], owner, group) < 0) { ! 341: perror(argv[c]); ! 342: status = 2; ! 343: } ! 344: } ! 345: if (status) ! 346: exit (status); ! 347: } ! 348: ! 349: /* ! 350: * Change the group owner of specified files. ! 351: */ ! 352: cmd_chgrp(argc, argv, shift_cmd, shift_file) ! 353: int argc; ! 354: char **argv; ! 355: int shift_cmd; /* Shift argv to the group */ ! 356: int shift_file; /* Shift argv to the file names */ ! 357: { ! 358: register struct group *grp; ! 359: register int c; ! 360: register short owner, group; ! 361: struct stat sb; ! 362: register short status = 0; ! 363: int i_cmd; ! 364: int i_file; ! 365: ! 366: /* Only superuser can invoke chgrp under COHERENT. Vlad */ ! 367: if (geteuid()) ! 368: cherr("%s: only superuser can changed group name.\n", argv[0]); ! 369: ! 370: if (argc < 3) ! 371: usage(chgrp_usage); ! 372: ! 373: i_cmd = 1 + shift_cmd; ! 374: i_file = 2 + shift_file; ! 375: ! 376: /* You can specify group by numeric id or by name. Vlad */ ! 377: if (isdigit((int) *argv[i_cmd])) { ! 378: if ((grp = getgrgid(atoi(argv[i_cmd]))) == NULL) ! 379: cherr("%s: bad numeric group id `%s'\n", ! 380: argv[0], argv[i_cmd]); ! 381: } else ! 382: if ((grp = getgrnam(argv[i_cmd])) == NULL) ! 383: cherr("%s: bad group name `%s'\n", argv[0],argv[i_cmd]); ! 384: ! 385: group = grp->gr_gid; ! 386: ! 387: for (c = i_file; c < argc; c++) { ! 388: owner = 0; ! 389: if (stat(argv[c], &sb) >= 0) ! 390: owner = sb.st_uid; ! 391: if (chown(argv[c], owner, group) < 0) { ! 392: perror(argv[c]); ! 393: status = 2; ! 394: } ! 395: } ! 396: if (status) ! 397: exit (status); ! 398: } ! 399: ! 400: usage(msg) ! 401: char *msg; ! 402: { ! 403: fprintf(stderr, "Usage: %s\n", msg); ! 404: exit(1); ! 405: } ! 406: ! 407: /* VARARGS */ ! 408: cherr(x) ! 409: { ! 410: fprintf(stderr, "%r", &x); ! 411: exit(2); ! 412: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.