chmod.c revision 24348
1177633Sdfr/* 2177633Sdfr * Copyright (c) 1989, 1993, 1994 3177633Sdfr * The Regents of the University of California. All rights reserved. 4177633Sdfr * 5177633Sdfr * Redistribution and use in source and binary forms, with or without 6177633Sdfr * modification, are permitted provided that the following conditions 7177633Sdfr * are met: 8177633Sdfr * 1. Redistributions of source code must retain the above copyright 9177633Sdfr * notice, this list of conditions and the following disclaimer. 10177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11177633Sdfr * notice, this list of conditions and the following disclaimer in the 12177633Sdfr * documentation and/or other materials provided with the distribution. 13177633Sdfr * 3. All advertising materials mentioning features or use of this software 14177633Sdfr * must display the following acknowledgement: 15177633Sdfr * This product includes software developed by the University of 16177633Sdfr * California, Berkeley and its contributors. 17177633Sdfr * 4. Neither the name of the University nor the names of its contributors 18177633Sdfr * may be used to endorse or promote products derived from this software 19177633Sdfr * without specific prior written permission. 20177633Sdfr * 21177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31177633Sdfr * SUCH DAMAGE. 32177633Sdfr * 33177633Sdfr * $Id: chmod.c,v 1.8 1997/02/22 14:01:30 peter Exp $ 34177633Sdfr */ 35177633Sdfr 36177633Sdfr#ifndef lint 37177633Sdfrstatic char const copyright[] = 38177633Sdfr"@(#) Copyright (c) 1989, 1993, 1994\n\ 39177633Sdfr The Regents of the University of California. All rights reserved.\n"; 40177633Sdfr#endif /* not lint */ 41177633Sdfr 42177633Sdfr#ifndef lint 43177633Sdfrstatic char const sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94"; 44177633Sdfr#endif /* not lint */ 45177633Sdfr 46177633Sdfr#include <sys/types.h> 47177633Sdfr#include <sys/stat.h> 48177633Sdfr 49177633Sdfr#include <err.h> 50177633Sdfr#include <errno.h> 51177633Sdfr#include <fts.h> 52184588Sdfr#include <limits.h> 53177633Sdfr#include <stdio.h> 54184588Sdfr#include <stdlib.h> 55177633Sdfr#include <string.h> 56184588Sdfr#include <unistd.h> 57177633Sdfr 58184588Sdfrvoid usage __P((void)); 59177633Sdfr 60177633Sdfrint 61177633Sdfrmain(argc, argv) 62177633Sdfr int argc; 63177633Sdfr char *argv[]; 64184588Sdfr{ 65177633Sdfr FTS *ftsp; 66177685Sdfr FTSENT *p; 67177633Sdfr mode_t *set; 68177633Sdfr long val; 69184588Sdfr int oct, omode; 70177633Sdfr int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; 71177633Sdfr char *ep, *mode; 72177633Sdfr 73184588Sdfr set = NULL; 74184588Sdfr omode = 0; 75177633Sdfr Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0; 76177633Sdfr while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != -1) 77177633Sdfr switch (ch) { 78184588Sdfr case 'H': 79184588Sdfr Hflag = 1; 80184588Sdfr Lflag = Pflag = 0; 81177633Sdfr break; 82184588Sdfr case 'L': 83177633Sdfr Lflag = 1; 84177633Sdfr Hflag = Pflag = 0; 85177633Sdfr break; 86177633Sdfr case 'P': 87177633Sdfr Pflag = 1; 88177633Sdfr Hflag = Lflag = 0; 89184588Sdfr break; 90184588Sdfr case 'R': 91184588Sdfr Rflag = 1; 92177633Sdfr break; 93177633Sdfr case 'f': /* XXX: undocumented. */ 94177633Sdfr fflag = 1; 95184588Sdfr break; 96184588Sdfr case 'h': 97184588Sdfr /* 98184588Sdfr * In System V (and probably POSIX.2) the -h option 99184588Sdfr * causes chmod to change the mode of the symbolic 100177633Sdfr * link. 4.4BSD's symbolic links don't have modes, 101184588Sdfr * so it's an undocumented noop. Do syntax checking, 102184588Sdfr * though. 103184588Sdfr */ 104184588Sdfr hflag = 1; 105184588Sdfr break; 106184588Sdfr /* 107184588Sdfr * XXX 108184588Sdfr * "-[rwx]" are valid mode commands. If they are the entire 109184588Sdfr * argument, getopt has moved past them, so decrement optind. 110184588Sdfr * Regardless, we're done argument processing. 111184588Sdfr */ 112184588Sdfr case 'g': case 'o': case 'r': case 's': 113184588Sdfr case 't': case 'u': case 'w': case 'X': case 'x': 114184588Sdfr if (argv[optind - 1][0] == '-' && 115184588Sdfr argv[optind - 1][1] == ch && 116184588Sdfr argv[optind - 1][2] == '\0') 117184588Sdfr --optind; 118184588Sdfr goto done; 119184588Sdfr case '?': 120184588Sdfr default: 121184588Sdfr usage(); 122184588Sdfr } 123184588Sdfrdone: argv += optind; 124184588Sdfr argc -= optind; 125184588Sdfr 126184588Sdfr if (argc < 2) 127184588Sdfr usage(); 128184588Sdfr 129184588Sdfr fts_options = FTS_PHYSICAL; 130184588Sdfr if (Rflag) { 131184588Sdfr if (hflag) 132184588Sdfr errx(1, 133184588Sdfr "the -R and -h options may not be specified together."); 134184588Sdfr if (Hflag) 135184588Sdfr fts_options |= FTS_COMFOLLOW; 136184588Sdfr if (Lflag) { 137184588Sdfr fts_options &= ~FTS_PHYSICAL; 138184588Sdfr fts_options |= FTS_LOGICAL; 139184588Sdfr } 140184588Sdfr } 141184588Sdfr 142184588Sdfr mode = *argv; 143184588Sdfr if (*mode >= '0' && *mode <= '7') { 144184588Sdfr errno = 0; 145184588Sdfr val = strtol(mode, &ep, 8); 146184588Sdfr if (val > INT_MAX || val < 0) 147184588Sdfr errno = ERANGE; 148184588Sdfr if (errno) 149184588Sdfr err(1, "invalid file mode: %s", mode); 150184588Sdfr if (*ep) 151184588Sdfr errx(1, "invalid file mode: %s", mode); 152177633Sdfr omode = val; 153177633Sdfr oct = 1; 154177633Sdfr } else { 155177633Sdfr if ((set = setmode(mode)) == NULL) 156177633Sdfr errx(1, "invalid file mode: %s", mode); 157177633Sdfr oct = 0; 158184588Sdfr } 159177633Sdfr 160184588Sdfr if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 161177633Sdfr err(1, NULL); 162184588Sdfr for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 163177633Sdfr switch (p->fts_info) { 164177633Sdfr case FTS_D: /* Change it at FTS_DP. */ 165177633Sdfr if (!Rflag) 166177633Sdfr fts_set(ftsp, p, FTS_SKIP); 167184588Sdfr continue; 168184588Sdfr case FTS_DNR: /* Warn, chmod, continue. */ 169177633Sdfr warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 170177633Sdfr rval = 1; 171177633Sdfr break; 172177633Sdfr case FTS_ERR: /* Warn, continue. */ 173177633Sdfr case FTS_NS: 174177633Sdfr warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 175177633Sdfr rval = 1; 176177633Sdfr continue; 177177633Sdfr case FTS_SL: /* Ignore. */ 178177633Sdfr case FTS_SLNONE: 179184588Sdfr /* 180184588Sdfr * The only symlinks that end up here are ones that 181184588Sdfr * don't point to anything and ones that we found 182184588Sdfr * doing a physical walk. 183184588Sdfr */ 184184588Sdfr continue; 185184588Sdfr default: 186184588Sdfr break; 187184588Sdfr } 188177633Sdfr if (chmod(p->fts_accpath, oct ? omode : 189177633Sdfr getmode(set, p->fts_statp->st_mode)) && !fflag) { 190177633Sdfr warn(p->fts_path); 191184588Sdfr rval = 1; 192184588Sdfr } 193184588Sdfr } 194184588Sdfr if (errno) 195184588Sdfr err(1, "fts_read"); 196184588Sdfr exit(rval); 197184588Sdfr} 198184588Sdfr 199184588Sdfrvoid 200184588Sdfrusage() 201177633Sdfr{ 202184588Sdfr (void)fprintf(stderr, 203184588Sdfr "usage: chmod [-R [-H | -L | -P]] mode file ...\n"); 204184588Sdfr exit(1); 205184588Sdfr} 206184588Sdfr