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*66543Sbostic static char sccsid[] = "@(#)chmod.c 8.4 (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 { 3653782Selan register FTS *ftsp; 3739829Sbostic register FTSENT *p; 3839829Sbostic register int oct, omode; 3952070Sbostic mode_t *set; 40*66543Sbostic int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; 4152070Sbostic char *ep, *mode; 4216242Slayer 43*66543Sbostic Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0; 44*66543Sbostic while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF) 4566445Sbostic switch (ch) { 4653782Selan case 'H': 4753782Selan Hflag = 1; 48*66543Sbostic Lflag = Pflag = 0; 4953782Selan break; 50*66543Sbostic case 'L': 51*66543Sbostic Lflag = 1; 52*66543Sbostic Hflag = Pflag = 0; 53*66543Sbostic break; 54*66543Sbostic case 'P': 55*66543Sbostic Pflag = 1; 56*66543Sbostic Hflag = Lflag = 0; 57*66543Sbostic break; 5824503Ssam case 'R': 59*66543Sbostic Rflag = 1; 6024503Ssam break; 61*66543Sbostic case 'f': /* XXX: undocumented. */ 6247072Sbostic fflag = 1; 6324503Ssam break; 6453782Selan case 'h': 65*66543Sbostic /* 66*66543Sbostic * In System V (and probably POSIX.2) the -h option 67*66543Sbostic * causes chmod to change the mode of the symbolic 68*66543Sbostic * link. 4.4BSD's symbolic links don't have modes, 69*66543Sbostic * so it's an undocumented noop. Do syntax checking, 70*66543Sbostic * though. 71*66543Sbostic */ 7253782Selan hflag = 1; 7353782Selan break; 7465163Sbostic /* 7566445Sbostic * XXX 7665163Sbostic * "-[rwx]" are valid mode commands. If they are the entire 7765163Sbostic * argument, getopt has moved past them, so decrement optind. 7865163Sbostic * Regardless, we're done argument processing. 7965163Sbostic */ 8066445Sbostic case 'g': case 'o': case 'r': case 's': 8166445Sbostic case 't': case 'u': case 'w': case 'X': case 'x': 8266445Sbostic if (argv[optind - 1][0] == '-' && 8366445Sbostic argv[optind - 1][1] == ch && 8466445Sbostic argv[optind - 1][2] == '\0') 8565163Sbostic --optind; 8665163Sbostic goto done; 8734043Sbostic case '?': 8824503Ssam default: 8939829Sbostic usage(); 9023482Smckusick } 9134043Sbostic done: argv += optind; 9234043Sbostic argc -= optind; 9334043Sbostic 9439829Sbostic if (argc < 2) 9539829Sbostic usage(); 9639829Sbostic 97*66543Sbostic fts_options = FTS_PHYSICAL; 98*66543Sbostic if (Rflag) { 99*66543Sbostic if (hflag) 100*66543Sbostic errx(1, 101*66543Sbostic "the -R and -h options may not be specified together."); 102*66543Sbostic if (Hflag) 103*66543Sbostic fts_options |= FTS_COMFOLLOW; 104*66543Sbostic if (Lflag) { 105*66543Sbostic fts_options &= ~FTS_PHYSICAL; 106*66543Sbostic fts_options |= FTS_LOGICAL; 107*66543Sbostic } 108*66543Sbostic } 109*66543Sbostic 11039829Sbostic mode = *argv; 11139829Sbostic if (*mode >= '0' && *mode <= '7') { 11252070Sbostic omode = (int)strtol(mode, &ep, 8); 11352070Sbostic if (omode < 0 || *ep) 11458142Sbostic errx(1, "invalid file mode: %s", mode); 11539829Sbostic oct = 1; 11639829Sbostic } else { 11758142Sbostic if ((set = setmode(mode)) == NULL) 11858142Sbostic errx(1, "invalid file mode: %s", mode); 11939829Sbostic oct = 0; 12016242Slayer } 12134043Sbostic 12253782Selan if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 123*66543Sbostic err(1, NULL); 124*66543Sbostic for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 12566445Sbostic switch (p->fts_info) { 12653782Selan case FTS_D: 127*66543Sbostic if (Rflag) /* Change it at FTS_DP. */ 128*66543Sbostic continue; 129*66543Sbostic fts_set(ftsp, p, FTS_SKIP); 13053782Selan break; 131*66543Sbostic case FTS_DC: /* Ignore. */ 132*66543Sbostic continue; 133*66543Sbostic case FTS_DNR: /* Warn, chmod, continue. */ 134*66543Sbostic errno = p->fts_errno; 135*66543Sbostic warn("%s", p->fts_path); 136*66543Sbostic rval = 1; 137*66543Sbostic break; 138*66543Sbostic case FTS_ERR: /* Warn, continue. */ 13953782Selan case FTS_NS: 140*66543Sbostic errno = p->fts_errno; 141*66543Sbostic warn("%s", p->fts_path); 142*66543Sbostic rval = 1; 143*66543Sbostic continue; 144*66543Sbostic case FTS_SL: /* Ignore. */ 145*66543Sbostic case FTS_SLNONE: 146*66543Sbostic /* 147*66543Sbostic * The only symlinks that end up here are ones that 148*66543Sbostic * don't point to anything and ones that we found 149*66543Sbostic * doing a physical walk. 150*66543Sbostic */ 151*66543Sbostic continue; 152*66543Sbostic default: 15353782Selan break; 15453782Selan } 155*66543Sbostic if (chmod(p->fts_accpath, oct ? omode : 156*66543Sbostic getmode(set, p->fts_statp->st_mode)) && !fflag) { 157*66543Sbostic warn(p->fts_path); 158*66543Sbostic rval = 1; 159*66543Sbostic } 160*66543Sbostic } 161*66543Sbostic exit(rval); 16216242Slayer } 16316242Slayer 16452070Sbostic void 16539829Sbostic usage() 16616242Slayer { 167*66543Sbostic (void)fprintf(stderr, 168*66543Sbostic "usage: chmod [-R [-H | -L | -P]] mode file ...\n"); 16939829Sbostic exit(1); 17016242Slayer } 171