123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- chmod.c
- Abstract:
- This module implements support for the chmod utility.
- Author:
- Evan Green 16-Jul-2013
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include "swlib.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Set this option to recursively change permissions for any directory.
- //
- #define CHMOD_OPTION_RECURSIVE 0x00000001
- //
- // Set this option to print out a message for each file changed.
- //
- #define CHMOD_OPTION_VERBOSE 0x00000002
- //
- // Set this option to suppress most error messages.
- //
- #define CHMOD_OPTION_QUIET 0x00000004
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- ChmodChangePermissions (
- ULONG Options,
- PSTR ModeString,
- PSTR Argument
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- ChmodMain (
- INT ArgumentCount,
- CHAR **Arguments
- )
- /*++
- Routine Description:
- This routine implements the main entry point for the chmod utility.
- Arguments:
- ArgumentCount - Supplies the number of arguments on the command line.
- Arguments - Supplies an array of pointers to strings representing the
- arguments.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR Argument;
- ULONG ArgumentIndex;
- BOOL DidSomething;
- PSTR ModeString;
- ULONG Options;
- mode_t OriginalUmask;
- INT Result;
- INT ReturnValue;
- BOOL SkipControlArguments;
- ModeString = NULL;
- Options = 0;
- ReturnValue = 0;
- OriginalUmask = umask(0);
- //
- // Loop through all the options.
- //
- SkipControlArguments = TRUE;
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Argument = Arguments[ArgumentIndex];
- if (SkipControlArguments != FALSE) {
- //
- // Stop if a -- is found.
- //
- if (strcmp(Argument, "--") == 0) {
- SkipControlArguments = FALSE;
- continue;
- }
- if (Argument[0] == '-') {
- //
- // Parse the argument, unless they're actually permissions.
- //
- if ((Argument[1] != 'r') && (Argument[1] != 'w') &&
- (Argument[1] != 'x') && (Argument[1] != 's') &&
- (Argument[1] != 'X') && (Argument[1] != 't') &&
- (Argument[1] != 'u') && (Argument[1] != 'g') &&
- (Argument[1] != 'o') && (Argument[1] != 'a')) {
- Argument += 1;
- while (*Argument != '\0') {
- switch (*Argument) {
- case 'R':
- Options |= CHMOD_OPTION_RECURSIVE;
- break;
- case 'v':
- Options |= CHMOD_OPTION_VERBOSE;
- Options &= ~CHMOD_OPTION_QUIET;
- break;
- case 'f':
- Options |= CHMOD_OPTION_QUIET;
- Options &= ~CHMOD_OPTION_VERBOSE;
- break;
- default:
- SwPrintError(0,
- NULL,
- "Unknown option %c",
- *Argument);
- Result = EINVAL;
- goto MainEnd;
- }
- Argument += 1;
- }
- continue;
- }
- }
- }
- //
- // This is a regular argument.
- //
- if (ModeString == NULL) {
- ModeString = Argument;
- }
- }
- if (ModeString == NULL) {
- SwPrintError(0, NULL, "Expecting mode argument");
- ReturnValue = EINVAL;
- goto MainEnd;
- }
- //
- // Now that the options have been figured out, loop through again to
- // actually change permissions.
- //
- DidSomething = FALSE;
- SkipControlArguments = TRUE;
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Argument = Arguments[ArgumentIndex];
- if (SkipControlArguments != FALSE) {
- //
- // If a -- is found, all other arguments are real parameters.
- //
- if (strcmp(Argument, "--") == 0) {
- SkipControlArguments = FALSE;
- continue;
- }
- if (Argument[0] == '-') {
- continue;
- }
- }
- if (Argument == ModeString) {
- continue;
- }
- DidSomething = TRUE;
- Result = ChmodChangePermissions(Options, ModeString, Argument);
- if (Result != 0) {
- ReturnValue = Result;
- }
- }
- if (DidSomething == FALSE) {
- SwPrintError(0, NULL, "Argument expected");
- Result = 1;
- goto MainEnd;
- }
- MainEnd:
- umask(OriginalUmask);
- return ReturnValue;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- ChmodChangePermissions (
- ULONG Options,
- PSTR ModeString,
- PSTR Argument
- )
- /*++
- Routine Description:
- This routine changes the mode bits for the given file entry.
- Arguments:
- Options - Supplies the invocation options. See CHMOD_OPTION_* definitions.
- ModeString - Supplies the string of mode bits to change.
- Argument - Supplies the path of the file to change.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR AppendedPath;
- ULONG AppendedPathSize;
- DIR *Directory;
- struct dirent Entry;
- struct dirent *EntryPointer;
- BOOL IsDirectory;
- mode_t NewMode;
- mode_t OriginalMode;
- CHAR PrintMode[10];
- PSTR QuotedPath;
- INT Result;
- struct stat Stat;
- INT StringIndex;
- PSTR Verb;
- Directory = NULL;
- //
- // Get the file information.
- //
- Result = SwStat(Argument, FALSE, &Stat);
- if (Result != 0) {
- Result = errno;
- if ((Options & CHMOD_OPTION_QUIET) == 0) {
- SwPrintError(Result, Argument, "Cannot stat");
- }
- goto ChangePermissionsEnd;
- }
- //
- // Skip symbolic links.
- //
- if (S_ISLNK(Stat.st_mode)) {
- if ((Options & CHMOD_OPTION_VERBOSE) != 0) {
- QuotedPath = SwQuoteArgument(Argument);
- printf("Neither symbolic link '%s' nor referent has been "
- "changed.\n",
- QuotedPath);
- if (QuotedPath != Argument) {
- free(QuotedPath);
- }
- }
- goto ChangePermissionsEnd;
- }
- OriginalMode = Stat.st_mode;
- NewMode = OriginalMode;
- IsDirectory = FALSE;
- if (S_ISDIR(Stat.st_mode)) {
- IsDirectory = TRUE;
- }
- Result = SwParseFilePermissionsString(ModeString, IsDirectory, &NewMode);
- if (Result == FALSE) {
- SwPrintError(0, ModeString, "Invalid mode");
- Result = EINVAL;
- goto ChangePermissionsEnd;
- }
- //
- // Attempt to change the mode of this file or directory.
- //
- Result = chmod(Argument, NewMode);
- if (Result != 0) {
- Result = errno;
- if ((Options & CHMOD_OPTION_QUIET) == 0) {
- SwPrintError(Result, Argument, "Could not change mode of");
- }
- goto ChangePermissionsEnd;
- }
- //
- // Print this out if verbose.
- //
- if ((Options & CHMOD_OPTION_VERBOSE) != 0) {
- for (StringIndex = 0; StringIndex < 9; StringIndex += 1) {
- PrintMode[StringIndex] = '-';
- }
- if ((NewMode & S_IRUSR) != 0) {
- PrintMode[0] = 'r';
- }
- if ((NewMode & S_IWUSR) != 0) {
- PrintMode[1] = 'w';
- }
- if ((NewMode & S_IXUSR) != 0) {
- PrintMode[2] = 'x';
- if ((NewMode & S_ISUID) != 0) {
- PrintMode[2] = 's';
- }
- } else {
- if ((NewMode & S_ISUID) != 0) {
- PrintMode[2] = 'S';
- }
- }
- if ((NewMode & S_IRGRP) != 0) {
- PrintMode[3] = 'r';
- }
- if ((NewMode & S_IWGRP) != 0) {
- PrintMode[4] = 'w';
- }
- if ((NewMode & S_IXGRP) != 0) {
- PrintMode[5] = 'x';
- if ((NewMode & S_ISGID) != 0) {
- PrintMode[5] = 's';
- }
- } else {
- if ((NewMode & S_ISGID) != 0) {
- PrintMode[5] = 'S';
- }
- }
- if ((NewMode & S_IROTH) != 0) {
- PrintMode[6] = 'r';
- }
- if ((NewMode & S_IWOTH) != 0) {
- PrintMode[7] = 'w';
- }
- if ((NewMode & S_IXOTH) != 0) {
- PrintMode[8] = 'x';
- if ((NewMode & S_ISVTX) != 0) {
- PrintMode[8] = 't';
- }
- } else {
- if ((NewMode & S_ISVTX) != 0) {
- PrintMode[8] = 'T';
- }
- }
- PrintMode[9] = '\0';
- if (NewMode != OriginalMode) {
- Verb = "changed to";
- } else {
- Verb = "retained as";
- }
- QuotedPath = SwQuoteArgument(Argument);
- printf("mode of '%s' %s 0%03o (%s)\n",
- QuotedPath,
- Verb,
- NewMode & (S_IRWXU | S_IRWXG | S_IRWXO),
- PrintMode);
- if (QuotedPath != Argument) {
- free(QuotedPath);
- }
- }
- //
- // If the options are not recursive or this is not a directory, then that's
- // all there is to do.
- //
- if (((Options & CHMOD_OPTION_RECURSIVE) == 0) || (IsDirectory == FALSE)) {
- goto ChangePermissionsEnd;
- }
- Directory = opendir(Argument);
- if (Directory == NULL) {
- Result = errno;
- if ((Options & CHMOD_OPTION_QUIET) == 0) {
- SwPrintError(Result, Argument, "Cannot open directory");
- }
- goto ChangePermissionsEnd;
- }
- //
- // Loop through all entries in the directory.
- //
- while (TRUE) {
- Result = SwReadDirectory(Directory, &Entry, &EntryPointer);
- if (Result != 0) {
- if ((Options & CHMOD_OPTION_QUIET) == 0) {
- SwPrintError(Result, Argument, "Unable to read directory");
- }
- goto ChangePermissionsEnd;
- }
- if (EntryPointer == NULL) {
- break;
- }
- if ((strcmp(Entry.d_name, ".") == 0) ||
- (strcmp(Entry.d_name, "..") == 0)) {
- continue;
- }
- Result = SwAppendPath(Argument,
- strlen(Argument) + 1,
- Entry.d_name,
- strlen(Entry.d_name) + 1,
- &AppendedPath,
- &AppendedPathSize);
- if (Result == FALSE) {
- Result = ENOMEM;
- goto ChangePermissionsEnd;
- }
- Result = ChmodChangePermissions(Options, ModeString, AppendedPath);
- free(AppendedPath);
- if (Result != 0) {
- goto ChangePermissionsEnd;
- }
- }
- ChangePermissionsEnd:
- if (Directory != NULL) {
- closedir(Directory);
- }
- return Result;
- }
|