chmod.c revision 17496
1135446Strhodes/* 2165071Sdougb * Copyright (c) 1989, 1993, 1994 3135446Strhodes * The Regents of the University of California. All rights reserved. 4135446Strhodes * 5135446Strhodes * Redistribution and use in source and binary forms, with or without 6135446Strhodes * modification, are permitted provided that the following conditions 7135446Strhodes * are met: 8135446Strhodes * 1. Redistributions of source code must retain the above copyright 9135446Strhodes * notice, this list of conditions and the following disclaimer. 10135446Strhodes * 2. Redistributions in binary form must reproduce the above copyright 11135446Strhodes * notice, this list of conditions and the following disclaimer in the 12135446Strhodes * documentation and/or other materials provided with the distribution. 13135446Strhodes * 3. All advertising materials mentioning features or use of this software 14135446Strhodes * must display the following acknowledgement: 15135446Strhodes * This product includes software developed by the University of 16135446Strhodes * California, Berkeley and its contributors. 17135446Strhodes * 4. Neither the name of the University nor the names of its contributors 18165071Sdougb * may be used to endorse or promote products derived from this software 19135446Strhodes * without specific prior written permission. 20135446Strhodes * 21135446Strhodes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22135446Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23135446Strhodes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24135446Strhodes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25135446Strhodes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26135446Strhodes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27135446Strhodes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28135446Strhodes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29135446Strhodes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30135446Strhodes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31135446Strhodes * SUCH DAMAGE. 32135446Strhodes * 33135446Strhodes * $Id: chmod.c,v 1.4 1995/03/19 13:27:43 joerg Exp $ 34135446Strhodes */ 35135446Strhodes 36135446Strhodes#ifndef lint 37135446Strhodesstatic char copyright[] = 38135446Strhodes"@(#) Copyright (c) 1989, 1993, 1994\n\ 39135446Strhodes The Regents of the University of California. All rights reserved.\n"; 40135446Strhodes#endif /* not lint */ 41135446Strhodes 42135446Strhodes#ifndef lint 43135446Strhodesstatic char sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94"; 44143731Sdougb#endif /* not lint */ 45143731Sdougb 46135446Strhodes#include <sys/types.h> 47135446Strhodes#include <sys/stat.h> 48135446Strhodes 49135446Strhodes#include <err.h> 50135446Strhodes#include <errno.h> 51135446Strhodes#include <fts.h> 52135446Strhodes#include <limits.h> 53135446Strhodes#include <stdio.h> 54135446Strhodes#include <stdlib.h> 55143731Sdougb#include <string.h> 56135446Strhodes#include <unistd.h> 57135446Strhodes 58135446Strhodesvoid usage __P((void)); 59135446Strhodes 60135446Strhodesint 61135446Strhodesmain(argc, argv) 62143731Sdougb int argc; 63135446Strhodes char *argv[]; 64135446Strhodes{ 65135446Strhodes FTS *ftsp; 66135446Strhodes FTSENT *p; 67135446Strhodes mode_t *set; 68135446Strhodes long val; 69135446Strhodes int oct, omode; 70135446Strhodes int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; 71135446Strhodes char *ep, *mode; 72135446Strhodes 73135446Strhodes set = NULL; 74135446Strhodes omode = 0; 75135446Strhodes Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0; 76135446Strhodes while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF) 77135446Strhodes switch (ch) { 78135446Strhodes case 'H': 79135446Strhodes Hflag = 1; 80135446Strhodes Lflag = Pflag = 0; 81135446Strhodes break; 82135446Strhodes case 'L': 83135446Strhodes Lflag = 1; 84135446Strhodes Hflag = Pflag = 0; 85135446Strhodes break; 86135446Strhodes case 'P': 87135446Strhodes Pflag = 1; 88135446Strhodes Hflag = Lflag = 0; 89135446Strhodes break; 90135446Strhodes case 'R': 91135446Strhodes Rflag = 1; 92135446Strhodes break; 93135446Strhodes case 'f': /* XXX: undocumented. */ 94135446Strhodes fflag = 1; 95135446Strhodes break; 96135446Strhodes case 'h': 97135446Strhodes /* 98135446Strhodes * In System V (and probably POSIX.2) the -h option 99135446Strhodes * causes chmod to change the mode of the symbolic 100135446Strhodes * link. 4.4BSD's symbolic links don't have modes, 101135446Strhodes * so it's an undocumented noop. Do syntax checking, 102135446Strhodes * though. 103135446Strhodes */ 104135446Strhodes hflag = 1; 105135446Strhodes break; 106135446Strhodes /* 107135446Strhodes * XXX 108135446Strhodes * "-[rwx]" are valid mode commands. If they are the entire 109135446Strhodes * argument, getopt has moved past them, so decrement optind. 110135446Strhodes * Regardless, we're done argument processing. 111135446Strhodes */ 112135446Strhodes case 'g': case 'o': case 'r': case 's': 113135446Strhodes case 't': case 'u': case 'w': case 'X': case 'x': 114135446Strhodes if (argv[optind - 1][0] == '-' && 115135446Strhodes argv[optind - 1][1] == ch && 116135446Strhodes argv[optind - 1][2] == '\0') 117135446Strhodes --optind; 118135446Strhodes goto done; 119135446Strhodes case '?': 120135446Strhodes default: 121135446Strhodes usage(); 122135446Strhodes } 123135446Strhodesdone: argv += optind; 124135446Strhodes argc -= optind; 125135446Strhodes 126135446Strhodes if (argc < 2) 127135446Strhodes usage(); 128135446Strhodes 129135446Strhodes fts_options = FTS_PHYSICAL; 130135446Strhodes if (Rflag) { 131135446Strhodes if (hflag) 132135446Strhodes errx(1, 133135446Strhodes "the -R and -h options may not be specified together."); 134135446Strhodes if (Hflag) 135135446Strhodes fts_options |= FTS_COMFOLLOW; 136135446Strhodes if (Lflag) { 137135446Strhodes fts_options &= ~FTS_PHYSICAL; 138135446Strhodes fts_options |= FTS_LOGICAL; 139135446Strhodes } 140135446Strhodes } 141135446Strhodes 142135446Strhodes mode = *argv; 143135446Strhodes if (*mode >= '0' && *mode <= '7') { 144135446Strhodes errno = 0; 145135446Strhodes val = strtol(mode, &ep, 8); 146135446Strhodes if (val > INT_MAX || val < 0) 147135446Strhodes errno = ERANGE; 148135446Strhodes if (errno) 149135446Strhodes err(1, "invalid file mode: %s", mode); 150135446Strhodes if (*ep) 151135446Strhodes errx(1, "invalid file mode: %s", mode); 152135446Strhodes omode = val; 153135446Strhodes oct = 1; 154135446Strhodes } else { 155135446Strhodes if ((set = setmode(mode)) == NULL) 156135446Strhodes errx(1, "invalid file mode: %s", mode); 157135446Strhodes oct = 0; 158135446Strhodes } 159135446Strhodes 160135446Strhodes if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 161135446Strhodes err(1, NULL); 162135446Strhodes for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 163135446Strhodes switch (p->fts_info) { 164135446Strhodes case FTS_D: /* Change it at FTS_DP. */ 165135446Strhodes if (!Rflag) 166135446Strhodes fts_set(ftsp, p, FTS_SKIP); 167135446Strhodes continue; 168135446Strhodes case FTS_DNR: /* Warn, chmod, continue. */ 169135446Strhodes warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 170135446Strhodes rval = 1; 171135446Strhodes break; 172135446Strhodes case FTS_ERR: /* Warn, continue. */ 173135446Strhodes case FTS_NS: 174135446Strhodes warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 175135446Strhodes rval = 1; 176135446Strhodes continue; 177135446Strhodes case FTS_SL: /* Ignore. */ 178135446Strhodes case FTS_SLNONE: 179135446Strhodes /* 180135446Strhodes * The only symlinks that end up here are ones that 181135446Strhodes * don't point to anything and ones that we found 182135446Strhodes * doing a physical walk. 183135446Strhodes */ 184135446Strhodes continue; 185135446Strhodes default: 186135446Strhodes break; 187135446Strhodes } 188135446Strhodes if (chmod(p->fts_accpath, oct ? omode : 189135446Strhodes getmode(set, p->fts_statp->st_mode)) && !fflag) { 190135446Strhodes warn(p->fts_path); 191135446Strhodes rval = 1; 192135446Strhodes } 193135446Strhodes } 194135446Strhodes if (errno) 195135446Strhodes err(1, "fts_read"); 196135446Strhodes exit(rval); 197135446Strhodes} 198135446Strhodes 199135446Strhodesvoid 200135446Strhodesusage() 201135446Strhodes{ 202135446Strhodes (void)fprintf(stderr, 203135446Strhodes "usage: chmod [-R [-H | -L | -P]] mode file ...\n"); 204135446Strhodes exit(1); 205135446Strhodes} 206135446Strhodes