14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1992-2010 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * * 204887Schin ***********************************************************************/ 214887Schin #pragma prototyped 224887Schin /* 234887Schin * David Korn 244887Schin * Glenn Fowler 254887Schin * AT&T Research 264887Schin * 274887Schin * chmod 284887Schin */ 294887Schin 304887Schin static const char usage[] = 3110898Sroland.mainz@nrubsig.org "[-?\n@(#)$Id: chmod (AT&T Research) 2009-07-02 $\n]" 324887Schin USAGE_LICENSE 334887Schin "[+NAME?chmod - change the access permissions of files]" 344887Schin "[+DESCRIPTION?\bchmod\b changes the permission of each file " 354887Schin "according to mode, which can be either a symbolic representation " 364887Schin "of changes to make, or an octal number representing the bit " 374887Schin "pattern for the new permissions.]" 384887Schin "[+?Symbolic mode strings consist of one or more comma separated list " 394887Schin "of operations that can be perfomed on the mode. Each operation is of " 404887Schin "the form \auser\a \aop\a \aperm\a where \auser\a is zero or more of " 414887Schin "the following letters:]{" 424887Schin "[+u?User permission bits.]" 434887Schin "[+g?Group permission bits.]" 444887Schin "[+o?Other permission bits.]" 454887Schin "[+a?All permission bits. This is the default if none are specified.]" 464887Schin "}" 474887Schin "[+?The \aperm\a portion consists of zero or more of the following letters:]{" 484887Schin "[+r?Read permission.]" 494887Schin "[+s?Setuid when \bu\b is selected for \awho\a and setgid when \bg\b " 504887Schin "is selected for \awho\a.]" 514887Schin "[+w?Write permission.]" 524887Schin "[+x?Execute permission for files, search permission for directories.]" 534887Schin "[+X?Same as \bx\b except that it is ignored for files that do not " 544887Schin "already have at least one \bx\b bit set.]" 554887Schin "[+l?Exclusive lock bit on systems that support it. Group execute " 564887Schin "must be off.]" 574887Schin "[+t?Sticky bit on systems that support it.]" 584887Schin "}" 594887Schin "[+?The \aop\a portion consists of one or more of the following characters:]{" 604887Schin "[++?Cause the permission selected to be added to the existing " 614887Schin "permissions. | is equivalent to +.]" 624887Schin "[+-?Cause the permission selected to be removed to the existing " 634887Schin "permissions.]" 644887Schin "[+=?Cause the permission to be set to the given permissions.]" 654887Schin "[+&?Cause the permission selected to be \aand\aed with the existing " 664887Schin "permissions.]" 674887Schin "[+^?Cause the permission selected to be propagated to more " 684887Schin "restrictive groups.]" 694887Schin "}" 704887Schin "[+?Symbolic modes with the \auser\a portion omitted are subject to " 714887Schin "\bumask\b(2) settings unless the \b=\b \aop\a or the " 724887Schin "\b--ignore-umask\b option is specified.]" 734887Schin "[+?A numeric mode is from one to four octal digits (0-7), " 744887Schin "derived by adding up the bits with values 4, 2, and 1. " 754887Schin "Any omitted digits are assumed to be leading zeros. The " 764887Schin "first digit selects the set user ID (4) and set group ID " 774887Schin "(2) and save text image (1) attributes. The second digit " 784887Schin "selects permissions for the user who owns the file: read " 794887Schin "(4), write (2), and execute (1); the third selects permissions" 804887Schin "for other users in the file's group, with the same values; " 814887Schin "and the fourth for other users not in the file's group, with " 824887Schin "the same values.]" 834887Schin 844887Schin "[+?For symbolic links, by default, \bchmod\b changes the mode on the file " 854887Schin "referenced by the symbolic link, not on the symbolic link itself. " 864887Schin "The \b-h\b options can be specified to change the mode of the link. " 874887Schin "When traversing directories with \b-R\b, \bchmod\b either follows " 884887Schin "symbolic links or does not follow symbolic links, based on the " 894887Schin "options \b-H\b, \b-L\b, and \b-P\b. The configuration parameter " 904887Schin "\bPATH_RESOLVE\b determines the default behavior if none of these " 914887Schin "options is specified.]" 924887Schin 934887Schin "[+?When the \b-c\b or \b-v\b options are specified, change notifications " 944887Schin "are written to standard output using the format, " 958462SApril.Chin@Sun.COM "\b%s: mode changed to %0.4o (%s)\b, with arguments of the " 964887Schin "pathname, the numeric mode, and the resulting permission bits as " 974887Schin "would be displayed by the \bls\b command.]" 984887Schin 994887Schin "[+?For backwards compatibility, if an invalid option is given that is a valid " 1004887Schin "symbolic mode specification, \bchmod\b treats this as a mode " 1014887Schin "specification rather than as an option specification.]" 1024887Schin 1034887Schin "[H:metaphysical?Follow symbolic links for command arguments; otherwise don't " 1044887Schin "follow symbolic links when traversing directories.]" 1054887Schin "[L:logical|follow?Follow symbolic links when traversing directories.]" 1064887Schin "[P:physical|nofollow?Don't follow symbolic links when traversing directories.]" 1074887Schin "[R:recursive?Change the mode for files in subdirectories recursively.]" 1084887Schin "[c:changes?Describe only files whose permission actually change.]" 1094887Schin "[f:quiet|silent?Do not report files whose permissioins fail to change.]" 1104887Schin "[h:symlink?Change the mode of the symbolic links on systems that " 1114887Schin "support this.]" 1124887Schin "[i:ignore-umask?Ignore the \bumask\b(2) value in symbolic mode " 1134887Schin "expressions. This is probably how you expect \bchmod\b to work.]" 1148462SApril.Chin@Sun.COM "[n:show?Show actions but do not change any file modes.]" 1154887Schin "[F:reference?Omit the \amode\a operand and use the mode of \afile\a " 1164887Schin "instead.]:[file]" 1174887Schin "[v:verbose?Describe changed permissions of all files.]" 1184887Schin "\n" 1194887Schin "\nmode file ...\n" 1204887Schin "\n" 1214887Schin "[+EXIT STATUS?]{" 1224887Schin "[+0?All files changed successfully.]" 1234887Schin "[+>0?Unable to change mode of one or more files.]" 1244887Schin "}" 1254887Schin "[+SEE ALSO?\bchgrp\b(1), \bchown\b(1), \btw\b(1), \bgetconf\b(1), \bls\b(1), " 1264887Schin "\bumask\b(2)]" 1274887Schin ; 1284887Schin 1294887Schin 1304887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide) 1314887Schin __STDPP__directive pragma pp:hide lchmod 1324887Schin #else 1334887Schin #define lchmod ______lchmod 1344887Schin #endif 1354887Schin 1364887Schin #include <cmd.h> 1374887Schin #include <ls.h> 138*12068SRoger.Faulkner@Oracle.COM #include <fts_fix.h> 1394887Schin 1404887Schin #include "FEATURE/symlink" 1414887Schin 1424887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide) 1434887Schin __STDPP__directive pragma pp:nohide lchmod 1444887Schin #else 1454887Schin #undef lchmod 1464887Schin #endif 1474887Schin 1484887Schin extern int lchmod(const char*, mode_t); 1494887Schin 1504887Schin int 1514887Schin b_chmod(int argc, char** argv, void* context) 1524887Schin { 1534887Schin register int mode; 1544887Schin register int force = 0; 1554887Schin register int flags; 1564887Schin register char* amode = 0; 1574887Schin register FTS* fts; 1584887Schin register FTSENT*ent; 1594887Schin char* last; 1604887Schin int (*chmodf)(const char*, mode_t); 16110898Sroland.mainz@nrubsig.org int logical = 1; 1624887Schin int notify = 0; 1634887Schin int ignore = 0; 1648462SApril.Chin@Sun.COM int show = 0; 1654887Schin #if _lib_lchmod 1664887Schin int chlink = 0; 1674887Schin #endif 1684887Schin struct stat st; 1694887Schin 1704887Schin cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); 1714887Schin flags = fts_flags() | FTS_TOP | FTS_NOPOSTORDER | FTS_NOSEEDOTDIR; 1724887Schin 1734887Schin /* 1744887Schin * NOTE: we diverge from the normal optget boilerplate 1754887Schin * to allow `chmod -x etc' to fall through 1764887Schin */ 1774887Schin 1784887Schin for (;;) 1794887Schin { 1804887Schin switch (optget(argv, usage)) 1814887Schin { 1824887Schin case 'c': 1834887Schin notify = 1; 1844887Schin continue; 1854887Schin case 'f': 1864887Schin force = 1; 1874887Schin continue; 1884887Schin case 'h': 1894887Schin #if _lib_lchmod 1904887Schin chlink = 1; 1914887Schin #endif 1924887Schin continue; 1934887Schin case 'i': 1944887Schin ignore = 1; 1954887Schin continue; 1968462SApril.Chin@Sun.COM case 'n': 1978462SApril.Chin@Sun.COM show = 1; 1988462SApril.Chin@Sun.COM continue; 1994887Schin case 'v': 2004887Schin notify = 2; 2014887Schin continue; 2024887Schin case 'F': 2034887Schin if (stat(opt_info.arg, &st)) 2044887Schin error(ERROR_exit(1), "%s: cannot stat", opt_info.arg); 2054887Schin mode = st.st_mode; 2064887Schin amode = ""; 2074887Schin continue; 2084887Schin case 'H': 2094887Schin flags |= FTS_META|FTS_PHYSICAL; 21010898Sroland.mainz@nrubsig.org logical = 0; 2114887Schin continue; 2124887Schin case 'L': 2134887Schin flags &= ~(FTS_META|FTS_PHYSICAL); 21410898Sroland.mainz@nrubsig.org logical = 0; 2154887Schin continue; 2164887Schin case 'P': 2174887Schin flags &= ~FTS_META; 2184887Schin flags |= FTS_PHYSICAL; 21910898Sroland.mainz@nrubsig.org logical = 0; 2204887Schin continue; 2214887Schin case 'R': 2224887Schin flags &= ~FTS_TOP; 22310898Sroland.mainz@nrubsig.org logical = 0; 2244887Schin continue; 2254887Schin case '?': 2264887Schin error(ERROR_usage(2), "%s", opt_info.arg); 2274887Schin break; 2284887Schin } 2294887Schin break; 2304887Schin } 2314887Schin argv += opt_info.index; 2324887Schin if (error_info.errors || !*argv || !amode && !*(argv + 1)) 2334887Schin error(ERROR_usage(2), "%s", optusage(NiL)); 23410898Sroland.mainz@nrubsig.org if (logical) 23510898Sroland.mainz@nrubsig.org flags &= ~(FTS_META|FTS_PHYSICAL); 2364887Schin if (ignore) 2374887Schin ignore = umask(0); 2384887Schin if (amode) 2394887Schin amode = 0; 2404887Schin else 2414887Schin { 2424887Schin amode = *argv++; 2434887Schin mode = strperm(amode, &last, 0); 2444887Schin if (*last) 2454887Schin { 2464887Schin if (ignore) 2474887Schin umask(ignore); 2484887Schin error(ERROR_exit(1), "%s: invalid mode", amode); 2494887Schin } 2504887Schin } 2514887Schin chmodf = 2524887Schin #if _lib_lchmod 2534887Schin chlink ? lchmod : 2544887Schin #endif 2554887Schin chmod; 2564887Schin if (!(fts = fts_open(argv, flags, NiL))) 2574887Schin { 2584887Schin if (ignore) 2594887Schin umask(ignore); 2604887Schin error(ERROR_system(1), "%s: not found", *argv); 2614887Schin } 2628462SApril.Chin@Sun.COM while (!sh_checksig(context) && (ent = fts_read(fts))) 2634887Schin switch (ent->fts_info) 2644887Schin { 2654887Schin case FTS_SL: 2664887Schin if (chmodf == chmod) 2674887Schin { 2684887Schin if (!(flags & FTS_PHYSICAL) || (flags & FTS_META) && ent->fts_level == 1) 2694887Schin fts_set(NiL, ent, FTS_FOLLOW); 2704887Schin break; 2714887Schin } 2724887Schin /*FALLTHROUGH*/ 2734887Schin case FTS_F: 2744887Schin case FTS_D: 2754887Schin case FTS_SLNONE: 2764887Schin anyway: 2774887Schin if (amode) 2784887Schin mode = strperm(amode, &last, ent->fts_statp->st_mode); 2798462SApril.Chin@Sun.COM if (show || (*chmodf)(ent->fts_accpath, mode) >= 0) 2804887Schin { 2814887Schin if (notify == 2 || notify == 1 && (mode&S_IPERM) != (ent->fts_statp->st_mode&S_IPERM)) 2824887Schin sfprintf(sfstdout, "%s: mode changed to %0.4o (%s)\n", ent->fts_path, mode, fmtmode(mode, 1)+1); 2834887Schin } 2844887Schin else if (!force) 2854887Schin error(ERROR_system(0), "%s: cannot change mode", ent->fts_accpath); 2864887Schin break; 2874887Schin case FTS_DC: 2884887Schin if (!force) 2894887Schin error(ERROR_warn(0), "%s: directory causes cycle", ent->fts_accpath); 2904887Schin break; 2914887Schin case FTS_DNR: 2924887Schin if (!force) 2934887Schin error(ERROR_system(0), "%s: cannot read directory", ent->fts_accpath); 2944887Schin goto anyway; 2954887Schin case FTS_DNX: 2964887Schin if (!force) 2974887Schin error(ERROR_system(0), "%s: cannot search directory", ent->fts_accpath); 2984887Schin goto anyway; 2994887Schin case FTS_NS: 3004887Schin if (!force) 3014887Schin error(ERROR_system(0), "%s: not found", ent->fts_accpath); 3024887Schin break; 3034887Schin } 3044887Schin fts_close(fts); 3054887Schin if (ignore) 3064887Schin umask(ignore); 3074887Schin return error_info.errors != 0; 3084887Schin } 309