119840Sdist /* 266445Sbostic * Copyright (c) 1989, 1993, 1994 363597Sbostic * The Regents of the University of California. All rights reserved. 439829Sbostic * 542527Sbostic * %sccs.include.redist.c% 619840Sdist */ 716242Slayer 819840Sdist #ifndef lint 963597Sbostic static char copyright[] = 1066445Sbostic "@(#) Copyright (c) 1989, 1993, 1994\n\ 1163597Sbostic The Regents of the University of California. All rights reserved.\n"; 1234043Sbostic #endif /* not lint */ 1319840Sdist 1434043Sbostic #ifndef lint 15*66544Sbostic static char sccsid[] = "@(#)chmod.c 8.5 (Berkeley) 03/31/94"; 1634043Sbostic #endif /* not lint */ 1734043Sbostic 1816242Slayer #include <sys/types.h> 1916242Slayer #include <sys/stat.h> 2058142Sbostic 2158142Sbostic #include <err.h> 2252070Sbostic #include <errno.h> 2339829Sbostic #include <fts.h> 2439829Sbostic #include <stdio.h> 2552070Sbostic #include <stdlib.h> 2642010Sbostic #include <string.h> 2758142Sbostic #include <unistd.h> 2816242Slayer 2952070Sbostic void usage __P((void)); 3052070Sbostic 3152070Sbostic int 3224503Ssam main(argc, argv) 3334043Sbostic int argc; 3452070Sbostic char *argv[]; 3516242Slayer { 36*66544Sbostic FTS *ftsp; 37*66544Sbostic FTSENT *p; 3852070Sbostic mode_t *set; 39*66544Sbostic long val; 40*66544Sbostic int oct, omode; 4166543Sbostic int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; 4252070Sbostic char *ep, *mode; 4316242Slayer 4466543Sbostic Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0; 4566543Sbostic while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF) 4666445Sbostic switch (ch) { 4753782Selan case 'H': 4853782Selan Hflag = 1; 4966543Sbostic Lflag = Pflag = 0; 5053782Selan break; 5166543Sbostic case 'L': 5266543Sbostic Lflag = 1; 5366543Sbostic Hflag = Pflag = 0; 5466543Sbostic break; 5566543Sbostic case 'P': 5666543Sbostic Pflag = 1; 5766543Sbostic Hflag = Lflag = 0; 5866543Sbostic break; 5924503Ssam case 'R': 6066543Sbostic Rflag = 1; 6124503Ssam break; 6266543Sbostic case 'f': /* XXX: undocumented. */ 6347072Sbostic fflag = 1; 6424503Ssam break; 6553782Selan case 'h': 6666543Sbostic /* 6766543Sbostic * In System V (and probably POSIX.2) the -h option 6866543Sbostic * causes chmod to change the mode of the symbolic 6966543Sbostic * link. 4.4BSD's symbolic links don't have modes, 7066543Sbostic * so it's an undocumented noop. Do syntax checking, 7166543Sbostic * though. 7266543Sbostic */ 7353782Selan hflag = 1; 7453782Selan break; 7565163Sbostic /* 7666445Sbostic * XXX 7765163Sbostic * "-[rwx]" are valid mode commands. If they are the entire 7865163Sbostic * argument, getopt has moved past them, so decrement optind. 7965163Sbostic * Regardless, we're done argument processing. 8065163Sbostic */ 8166445Sbostic case 'g': case 'o': case 'r': case 's': 8266445Sbostic case 't': case 'u': case 'w': case 'X': case 'x': 8366445Sbostic if (argv[optind - 1][0] == '-' && 8466445Sbostic argv[optind - 1][1] == ch && 8566445Sbostic argv[optind - 1][2] == '\0') 8665163Sbostic --optind; 8765163Sbostic goto done; 8834043Sbostic case '?': 8924503Ssam default: 9039829Sbostic usage(); 9123482Smckusick } 9234043Sbostic done: argv += optind; 9334043Sbostic argc -= optind; 9434043Sbostic 9539829Sbostic if (argc < 2) 9639829Sbostic usage(); 9739829Sbostic 9866543Sbostic fts_options = FTS_PHYSICAL; 9966543Sbostic if (Rflag) { 10066543Sbostic if (hflag) 10166543Sbostic errx(1, 10266543Sbostic "the -R and -h options may not be specified together."); 10366543Sbostic if (Hflag) 10466543Sbostic fts_options |= FTS_COMFOLLOW; 10566543Sbostic if (Lflag) { 10666543Sbostic fts_options &= ~FTS_PHYSICAL; 10766543Sbostic fts_options |= FTS_LOGICAL; 10866543Sbostic } 10966543Sbostic } 11066543Sbostic 11139829Sbostic mode = *argv; 11239829Sbostic if (*mode >= '0' && *mode <= '7') { 113*66544Sbostic errno = 0; 114*66544Sbostic val = strtol(mode, &ep, 8); 115*66544Sbostic if (val > INT_MAX || val < 0) 116*66544Sbostic errno = ERANGE; 117*66544Sbostic if (errno) 118*66544Sbostic err(1, "invalid file mode: %s", mode); 119*66544Sbostic if (*ep) 12058142Sbostic errx(1, "invalid file mode: %s", mode); 121*66544Sbostic omode = val; 12239829Sbostic oct = 1; 12339829Sbostic } else { 12458142Sbostic if ((set = setmode(mode)) == NULL) 12558142Sbostic errx(1, "invalid file mode: %s", mode); 12639829Sbostic oct = 0; 12716242Slayer } 12834043Sbostic 12953782Selan if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 13066543Sbostic err(1, NULL); 13166543Sbostic for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 13266445Sbostic switch (p->fts_info) { 13353782Selan case FTS_D: 13466543Sbostic if (Rflag) /* Change it at FTS_DP. */ 13566543Sbostic continue; 13666543Sbostic fts_set(ftsp, p, FTS_SKIP); 13753782Selan break; 13866543Sbostic case FTS_DC: /* Ignore. */ 13966543Sbostic continue; 14066543Sbostic case FTS_DNR: /* Warn, chmod, continue. */ 14166543Sbostic errno = p->fts_errno; 14266543Sbostic warn("%s", p->fts_path); 14366543Sbostic rval = 1; 14466543Sbostic break; 14566543Sbostic case FTS_ERR: /* Warn, continue. */ 14653782Selan case FTS_NS: 14766543Sbostic errno = p->fts_errno; 14866543Sbostic warn("%s", p->fts_path); 14966543Sbostic rval = 1; 15066543Sbostic continue; 15166543Sbostic case FTS_SL: /* Ignore. */ 15266543Sbostic case FTS_SLNONE: 15366543Sbostic /* 15466543Sbostic * The only symlinks that end up here are ones that 15566543Sbostic * don't point to anything and ones that we found 15666543Sbostic * doing a physical walk. 15766543Sbostic */ 15866543Sbostic continue; 15966543Sbostic default: 16053782Selan break; 16153782Selan } 16266543Sbostic if (chmod(p->fts_accpath, oct ? omode : 16366543Sbostic getmode(set, p->fts_statp->st_mode)) && !fflag) { 16466543Sbostic warn(p->fts_path); 16566543Sbostic rval = 1; 16666543Sbostic } 16766543Sbostic } 16866543Sbostic exit(rval); 16916242Slayer } 17016242Slayer 17152070Sbostic void 17239829Sbostic usage() 17316242Slayer { 17466543Sbostic (void)fprintf(stderr, 17566543Sbostic "usage: chmod [-R [-H | -L | -P]] mode file ...\n"); 17639829Sbostic exit(1); 17716242Slayer } 178