chmod.c revision 1557
1139749Simp/* 276479Swpaul * Copyright (c) 1989, 1993, 1994 376479Swpaul * The Regents of the University of California. All rights reserved. 476479Swpaul * 576479Swpaul * Redistribution and use in source and binary forms, with or without 676479Swpaul * modification, are permitted provided that the following conditions 776479Swpaul * are met: 876479Swpaul * 1. Redistributions of source code must retain the above copyright 976479Swpaul * notice, this list of conditions and the following disclaimer. 1076479Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1176479Swpaul * notice, this list of conditions and the following disclaimer in the 1276479Swpaul * documentation and/or other materials provided with the distribution. 1376479Swpaul * 3. All advertising materials mentioning features or use of this software 1476479Swpaul * must display the following acknowledgement: 1576479Swpaul * This product includes software developed by the University of 1676479Swpaul * California, Berkeley and its contributors. 1776479Swpaul * 4. Neither the name of the University nor the names of its contributors 1876479Swpaul * may be used to endorse or promote products derived from this software 1976479Swpaul * without specific prior written permission. 2076479Swpaul * 2176479Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2276479Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2376479Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2476479Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2576479Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2676479Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2776479Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2876479Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2976479Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3076479Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3176479Swpaul * SUCH DAMAGE. 3276479Swpaul */ 3376479Swpaul 34119418Sobrien#ifndef lint 35119418Sobrienstatic char copyright[] = 36119418Sobrien"@(#) Copyright (c) 1989, 1993, 1994\n\ 3776479Swpaul The Regents of the University of California. All rights reserved.\n"; 3876479Swpaul#endif /* not lint */ 3976479Swpaul 4076479Swpaul#ifndef lint 4176479Swpaulstatic char sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94"; 4276479Swpaul#endif /* not lint */ 4376479Swpaul 4476479Swpaul#include <sys/types.h> 4576479Swpaul#include <sys/stat.h> 4676479Swpaul 4776479Swpaul#include <err.h> 4876479Swpaul#include <errno.h> 4976479Swpaul#include <fts.h> 5076479Swpaul#include <stdio.h> 5176479Swpaul#include <stdlib.h> 5276479Swpaul#include <string.h> 5376479Swpaul#include <unistd.h> 5476479Swpaul 5576479Swpaulvoid usage __P((void)); 5676479Swpaul 5776479Swpaulint 5876479Swpaulmain(argc, argv) 5976479Swpaul int argc; 6076479Swpaul char *argv[]; 6176479Swpaul{ 6276479Swpaul FTS *ftsp; 6376479Swpaul FTSENT *p; 6476479Swpaul mode_t *set; 6576479Swpaul long val; 6676479Swpaul int oct, omode; 6776479Swpaul int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; 6876479Swpaul char *ep, *mode; 6976479Swpaul 7076479Swpaul Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0; 7176479Swpaul while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF) 7276479Swpaul switch (ch) { 7378323Swpaul case 'H': 7478323Swpaul Hflag = 1; 7578323Swpaul Lflag = Pflag = 0; 7678323Swpaul break; 7778323Swpaul case 'L': 7878323Swpaul Lflag = 1; 7978323Swpaul Hflag = Pflag = 0; 8078323Swpaul break; 8178323Swpaul case 'P': 8278323Swpaul Pflag = 1; 8378323Swpaul Hflag = Lflag = 0; 8478323Swpaul break; 8578323Swpaul case 'R': 8678323Swpaul Rflag = 1; 8778323Swpaul break; 8878323Swpaul case 'f': /* XXX: undocumented. */ 8976479Swpaul fflag = 1; 9076479Swpaul break; 91150968Sglebius case 'h': 92150968Sglebius /* 93150968Sglebius * In System V (and probably POSIX.2) the -h option 94150968Sglebius * causes chmod to change the mode of the symbolic 9576479Swpaul * link. 4.4BSD's symbolic links don't have modes, 9676479Swpaul * so it's an undocumented noop. Do syntax checking, 97192506Syongari * though. 98192506Syongari */ 99192506Syongari hflag = 1; 100192506Syongari break; 101192506Syongari /* 10276479Swpaul * XXX 103129879Sphk * "-[rwx]" are valid mode commands. If they are the entire 104192506Syongari * argument, getopt has moved past them, so decrement optind. 105192506Syongari * Regardless, we're done argument processing. 10676479Swpaul */ 107192506Syongari case 'g': case 'o': case 'r': case 's': 108192506Syongari case 't': case 'u': case 'w': case 'X': case 'x': 10976479Swpaul if (argv[optind - 1][0] == '-' && 110192506Syongari argv[optind - 1][1] == ch && 11176479Swpaul argv[optind - 1][2] == '\0') 11276479Swpaul --optind; 11376479Swpaul goto done; 11476479Swpaul case '?': 11576479Swpaul default: 11676479Swpaul usage(); 11776479Swpaul } 11876479Swpauldone: argv += optind; 11976479Swpaul argc -= optind; 120226995Smarius 12176479Swpaul if (argc < 2) 12276479Swpaul usage(); 123119285Simp 124119285Simp fts_options = FTS_PHYSICAL; 12576479Swpaul if (Rflag) { 126192506Syongari if (hflag) 12776479Swpaul errx(1, 12876522Swpaul "the -R and -h options may not be specified together."); 12976479Swpaul if (Hflag) 130192506Syongari fts_options |= FTS_COMFOLLOW; 131192506Syongari if (Lflag) { 132192506Syongari fts_options &= ~FTS_PHYSICAL; 133113506Smdodd fts_options |= FTS_LOGICAL; 134113506Smdodd } 13576479Swpaul } 13676479Swpaul 13776479Swpaul mode = *argv; 13876479Swpaul if (*mode >= '0' && *mode <= '7') { 13976479Swpaul errno = 0; 14076479Swpaul val = strtol(mode, &ep, 8); 14176479Swpaul if (val > INT_MAX || val < 0) 142242625Sdim errno = ERANGE; 14376479Swpaul if (errno) 14476479Swpaul err(1, "invalid file mode: %s", mode); 14576479Swpaul if (*ep) 14676479Swpaul errx(1, "invalid file mode: %s", mode); 14776479Swpaul omode = val; 14899497Salfred oct = 1; 14999497Salfred } else { 15099497Salfred if ((set = setmode(mode)) == NULL) 151192506Syongari errx(1, "invalid file mode: %s", mode); 152192506Syongari oct = 0; 153192506Syongari } 15476479Swpaul 155192506Syongari if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 156192506Syongari err(1, NULL); 157192506Syongari for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 158192506Syongari switch (p->fts_info) { 159192506Syongari case FTS_D: 160135250Swpaul if (Rflag) /* Change it at FTS_DP. */ 161193105Sattilio continue; 16299497Salfred fts_set(ftsp, p, FTS_SKIP); 16399497Salfred break; 16499497Salfred case FTS_DNR: /* Warn, chmod, continue. */ 165192506Syongari warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 16699497Salfred rval = 1; 167135250Swpaul break; 16899497Salfred case FTS_ERR: /* Warn, continue. */ 16999497Salfred case FTS_NS: 170135250Swpaul warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 171192506Syongari rval = 1; 17299497Salfred continue; 173192506Syongari case FTS_SL: /* Ignore. */ 174192506Syongari case FTS_SLNONE: 175192506Syongari /* 176192506Syongari * The only symlinks that end up here are ones that 17776479Swpaul * don't point to anything and ones that we found 17899497Salfred * doing a physical walk. 17999497Salfred */ 18099497Salfred continue; 181192294Syongari default: 182192506Syongari break; 18376479Swpaul } 18499497Salfred if (chmod(p->fts_accpath, oct ? omode : 18599497Salfred getmode(set, p->fts_statp->st_mode)) && !fflag) { 18699497Salfred warn(p->fts_path); 18776479Swpaul rval = 1; 188192506Syongari } 18999497Salfred } 190192506Syongari if (errno) 191192506Syongari err(1, "fts_read"); 192192506Syongari exit(rval); 19399497Salfred} 19499497Salfred 195192506Syongarivoid 196192506Syongariusage() 197192506Syongari{ 19876479Swpaul (void)fprintf(stderr, 199226995Smarius "usage: chmod [-R [-H | -L | -P]] mode file ...\n"); 200226995Smarius exit(1); 201226995Smarius} 202226995Smarius