chmod.c revision 121794
15697Smcpowers/* 25697Smcpowers * Copyright (c) 1989, 1993, 1994 35697Smcpowers * The Regents of the University of California. All rights reserved. 45697Smcpowers * 55697Smcpowers * Redistribution and use in source and binary forms, with or without 65697Smcpowers * modification, are permitted provided that the following conditions 75697Smcpowers * are met: 85697Smcpowers * 1. Redistributions of source code must retain the above copyright 95697Smcpowers * notice, this list of conditions and the following disclaimer. 105697Smcpowers * 2. Redistributions in binary form must reproduce the above copyright 115697Smcpowers * notice, this list of conditions and the following disclaimer in the 125697Smcpowers * documentation and/or other materials provided with the distribution. 135697Smcpowers * 3. All advertising materials mentioning features or use of this software 145697Smcpowers * must display the following acknowledgement: 155697Smcpowers * This product includes software developed by the University of 165697Smcpowers * California, Berkeley and its contributors. 175697Smcpowers * 4. Neither the name of the University nor the names of its contributors 185697Smcpowers * may be used to endorse or promote products derived from this software 195697Smcpowers * without specific prior written permission. 205697Smcpowers * 215697Smcpowers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 225697Smcpowers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 235697Smcpowers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 245697Smcpowers * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 255697Smcpowers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 265697Smcpowers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 275697Smcpowers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 285697Smcpowers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 295697Smcpowers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 305697Smcpowers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 315697Smcpowers * SUCH DAMAGE. 325697Smcpowers */ 335697Smcpowers 345697Smcpowers#if 0 355697Smcpowers#ifndef lint 365697Smcpowersstatic char const copyright[] = 375697Smcpowers"@(#) Copyright (c) 1989, 1993, 1994\n\ 385697Smcpowers The Regents of the University of California. All rights reserved.\n"; 395697Smcpowers#endif /* not lint */ 405697Smcpowers 415697Smcpowers#ifndef lint 425697Smcpowersstatic char sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94"; 435697Smcpowers#endif /* not lint */ 445697Smcpowers#endif 455697Smcpowers#include <sys/cdefs.h> 465697Smcpowers__FBSDID("$FreeBSD: head/bin/chmod/chmod.c 121794 2003-10-31 13:20:09Z tobez $"); 475697Smcpowers 485697Smcpowers#include <sys/types.h> 495697Smcpowers#include <sys/stat.h> 505697Smcpowers 515697Smcpowers#include <err.h> 525697Smcpowers#include <errno.h> 535697Smcpowers#include <fts.h> 545697Smcpowers#include <limits.h> 555697Smcpowers#include <stdio.h> 565697Smcpowers#include <stdlib.h> 575697Smcpowers#include <string.h> 585697Smcpowers#include <unistd.h> 595697Smcpowers 605697Smcpowersvoid usage(void); 615697Smcpowers 625697Smcpowersint 635697Smcpowersmain(int argc, char *argv[]) 645697Smcpowers{ 655697Smcpowers FTS *ftsp; 665697Smcpowers FTSENT *p; 675697Smcpowers mode_t *set; 685697Smcpowers int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval; 695697Smcpowers int vflag; 705697Smcpowers char *mode; 715697Smcpowers mode_t newmode; 725697Smcpowers int (*change_mode)(const char *, mode_t); 735697Smcpowers 745697Smcpowers set = NULL; 755697Smcpowers Hflag = Lflag = Rflag = fflag = hflag = vflag = 0; 765697Smcpowers while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1) 775697Smcpowers switch (ch) { 785697Smcpowers case 'H': 795697Smcpowers Hflag = 1; 805697Smcpowers Lflag = 0; 815697Smcpowers break; 825697Smcpowers case 'L': 835697Smcpowers Lflag = 1; 845697Smcpowers Hflag = 0; 855697Smcpowers break; 865697Smcpowers case 'P': 875697Smcpowers Hflag = Lflag = 0; 885697Smcpowers break; 895697Smcpowers case 'R': 905697Smcpowers Rflag = 1; 915697Smcpowers break; 925697Smcpowers case 'f': 935697Smcpowers fflag = 1; 945697Smcpowers break; 955697Smcpowers case 'h': 965697Smcpowers /* 975697Smcpowers * In System V (and probably POSIX.2) the -h option 985697Smcpowers * causes chmod to change the mode of the symbolic 995697Smcpowers * link. 4.4BSD's symbolic links didn't have modes, 1005697Smcpowers * so it was an undocumented noop. In FreeBSD 3.0, 1015697Smcpowers * lchmod(2) is introduced and this option does real 1025697Smcpowers * work. 1035697Smcpowers */ 1045697Smcpowers hflag = 1; 1055697Smcpowers break; 1065697Smcpowers /* 1075697Smcpowers * XXX 1085697Smcpowers * "-[rwx]" are valid mode commands. If they are the entire 1095697Smcpowers * argument, getopt has moved past them, so decrement optind. 1105697Smcpowers * Regardless, we're done argument processing. 1115697Smcpowers */ 1125697Smcpowers case 'g': case 'o': case 'r': case 's': 1135697Smcpowers case 't': case 'u': case 'w': case 'X': case 'x': 1145697Smcpowers if (argv[optind - 1][0] == '-' && 1155697Smcpowers argv[optind - 1][1] == ch && 1165697Smcpowers argv[optind - 1][2] == '\0') 1175697Smcpowers --optind; 1185697Smcpowers goto done; 1195697Smcpowers case 'v': 1205697Smcpowers vflag++; 1215697Smcpowers break; 1225697Smcpowers case '?': 1235697Smcpowers default: 1245697Smcpowers usage(); 1255697Smcpowers } 1265697Smcpowersdone: argv += optind; 1275697Smcpowers argc -= optind; 1285697Smcpowers 1295697Smcpowers if (argc < 2) 1305697Smcpowers usage(); 1315697Smcpowers 1325697Smcpowers if (Rflag) { 1335697Smcpowers fts_options = FTS_PHYSICAL; 1345697Smcpowers if (hflag) 1355697Smcpowers errx(1, 1365697Smcpowers "the -R and -h options may not be specified together."); 1375697Smcpowers if (Hflag) 1385697Smcpowers fts_options |= FTS_COMFOLLOW; 1395697Smcpowers if (Lflag) { 1405697Smcpowers fts_options &= ~FTS_PHYSICAL; 1415697Smcpowers fts_options |= FTS_LOGICAL; 1425697Smcpowers } 1435697Smcpowers } else 1445697Smcpowers fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL; 1455697Smcpowers 1465697Smcpowers if (hflag) 1475697Smcpowers change_mode = lchmod; 1485697Smcpowers else 1495697Smcpowers change_mode = chmod; 1505697Smcpowers 1515697Smcpowers mode = *argv; 1525697Smcpowers if ((set = setmode(mode)) == NULL) 1535697Smcpowers errx(1, "invalid file mode: %s", mode); 1545697Smcpowers 1555697Smcpowers if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 1565697Smcpowers err(1, "fts_open"); 1575697Smcpowers for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 1585697Smcpowers switch (p->fts_info) { 1595697Smcpowers case FTS_D: /* Change it at FTS_DP. */ 1605697Smcpowers if (!Rflag) 1615697Smcpowers fts_set(ftsp, p, FTS_SKIP); 1625697Smcpowers continue; 1635697Smcpowers case FTS_DNR: /* Warn, chmod, continue. */ 1645697Smcpowers warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 1655697Smcpowers rval = 1; 1665697Smcpowers break; 1675697Smcpowers case FTS_ERR: /* Warn, continue. */ 1685697Smcpowers case FTS_NS: 1695697Smcpowers warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 1705697Smcpowers rval = 1; 1715697Smcpowers continue; 1725697Smcpowers case FTS_SL: /* Ignore. */ 1735697Smcpowers case FTS_SLNONE: 1745697Smcpowers /* 1755697Smcpowers * The only symlinks that end up here are ones that 1765697Smcpowers * don't point to anything and ones that we found 1775697Smcpowers * doing a physical walk. 1785697Smcpowers */ 1795697Smcpowers if (!hflag) 1805697Smcpowers continue; 1815697Smcpowers /* else */ 1825697Smcpowers /* FALLTHROUGH */ 1835697Smcpowers default: 1845697Smcpowers break; 1855697Smcpowers } 1865697Smcpowers newmode = getmode(set, p->fts_statp->st_mode); 1875697Smcpowers if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS)) 1885697Smcpowers continue; 1895697Smcpowers if ((*change_mode)(p->fts_accpath, newmode) && !fflag) { 1905697Smcpowers warn("%s", p->fts_path); 1915697Smcpowers rval = 1; 1925697Smcpowers } else { 1935697Smcpowers if (vflag) { 1945697Smcpowers (void)printf("%s", p->fts_accpath); 1955697Smcpowers 1965697Smcpowers if (vflag > 1) { 1975697Smcpowers char m1[12], m2[12]; 1985697Smcpowers 1995697Smcpowers strmode(p->fts_statp->st_mode, m1); 2005697Smcpowers strmode((p->fts_statp->st_mode & 2015697Smcpowers S_IFMT) | newmode, m2); 2025697Smcpowers 2035697Smcpowers (void)printf(": 0%o [%s] -> 0%o [%s]", 2045697Smcpowers p->fts_statp->st_mode, m1, 2055697Smcpowers (p->fts_statp->st_mode & S_IFMT) | 2065697Smcpowers newmode, m2); 2075697Smcpowers } 2085697Smcpowers (void)printf("\n"); 2095697Smcpowers } 2105697Smcpowers 2115697Smcpowers } 212 } 213 if (errno) 214 err(1, "fts_read"); 215 free(set); 216 exit(rval); 217} 218 219void 220usage(void) 221{ 222 (void)fprintf(stderr, 223 "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n"); 224 exit(1); 225} 226