From 6331772c5b35ff9d4deb80ff9461d04b5e0d2db5 Mon Sep 17 00:00:00 2001 From: Matthew Martin Date: Mon, 18 Mar 2019 22:14:37 -0500 Subject: 44135: Add chmod builtin --- ChangeLog | 5 +++++ Completion/Unix/Command/_chmod | 13 +++++++++++-- Doc/Zsh/mod_files.yo | 20 ++++++++++++++++++++ Src/Modules/files.c | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index e23cb061e..0677bf36f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2019-03-18 Matthew Martin + + * 44135: Completion/Unix/Command/_chmod, Doc/Zsh/mod_files.yo, + Src/Modules/files.c: Add chmod builtin. + 2019-03-15 Jun-ichi Takimoto * 44118: configure.ac: use /usr/include/tirpc/ if headers for diff --git a/Completion/Unix/Command/_chmod b/Completion/Unix/Command/_chmod index 6a44a4ef1..43c515485 100644 --- a/Completion/Unix/Command/_chmod +++ b/Completion/Unix/Command/_chmod @@ -1,12 +1,21 @@ -#compdef chmod gchmod +#compdef chmod gchmod zf_chmod local curcontext="$curcontext" state line expl ret=1 variant local -a args privs args=( '*: :->files' '1: :_file_modes' ) -_pick_variant -r variant gnu=Free\ Soft $OSTYPE --version +_pick_variant -r variant -b zsh gnu=Free\ Soft $OSTYPE --version case "$variant" in + zsh) + # Assign, not append because zf_chmod only supports octal modes. + args=( + '-R[change files and directories recursively]' + '-s[enable paranoid behavior]' + '1:octal mode:' + '*: :->files' + ) + ;; gnu) args+=( '(-v --verbose -c --changes)'{-c,--changes}'[report changes made]' diff --git a/Doc/Zsh/mod_files.yo b/Doc/Zsh/mod_files.yo index 90e988474..3cf7b61e3 100644 --- a/Doc/Zsh/mod_files.yo +++ b/Doc/Zsh/mod_files.yo @@ -23,6 +23,26 @@ item(tt(chgrp) [ tt(-hRs) ] var(group) var(filename) ...)( Changes group of files specified. This is equivalent to tt(chown) with a var(user-spec) argument of `tt(:)var(group)'. ) +findex(chmod) +item(tt(chmod) [ tt(-Rs) ] var(mode) var(filename) ...)( +Changes mode of files specified. + +The specified var(mode) must be in octal. + +The tt(-R) option causes tt(chmod) to recursively descend into directories, +changing the mode of all files in the directory after +changing the mode of the directory itself. + +The tt(-s) option is a zsh extension to tt(chmod) functionality. It enables +paranoid behaviour, intended to avoid security problems involving +a tt(chmod) being tricked into affecting files other than the ones +intended. It will refuse to follow symbolic links, so that (for example) +``tt(chmod 600 /tmp/foo/passwd)'' can't accidentally chmod tt(/etc/passwd) +if tt(/tmp/foo) happens to be a link to tt(/etc). It will also check +where it is after leaving directories, so that a recursive chmod of +a deep directory tree can't end up recursively chmoding tt(/usr) as +a result of directories being moved up the tree. +) findex(chown) item(tt(chown) [ tt(-hRs) ] var(user-spec) var(filename) ...)( Changes ownership and group of files specified. diff --git a/Src/Modules/files.c b/Src/Modules/files.c index 6f816bac0..85764d55e 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -619,6 +619,45 @@ bin_rm(char *nam, char **args, Options ops, UNUSED(int func)) return OPT_ISSET(ops,'f') ? 0 : err; } +/* chmod builtin */ + +struct chmodmagic { + char *nam; + mode_t mode; +}; + +/**/ +static int +chmod_dochmod(char *arg, char *rp, UNUSED(struct stat const *sp), void *magic) +{ + struct chmodmagic *chm = magic; + + if(chmod(rp, chm->mode)) { + zwarnnam(chm->nam, "%s: %e", arg, errno); + return 1; + } + return 0; +} + +/**/ +static int +bin_chmod(char *nam, char **args, Options ops, int func) +{ + struct chmodmagic chm; + char *str = args[0], *ptr; + + chm.nam = nam; + + chm.mode = zstrtol(str, &ptr, 8); + if(!*str || *ptr) { + zwarnnam(nam, "invalid mode `%s'", str); + return 1; + } + + return recursivecmd(nam, 0, OPT_ISSET(ops,'R'), OPT_ISSET(ops,'s'), + args + 1, chmod_dochmod, recurse_donothing, chmod_dochmod, &chm); +} + /* chown builtin */ struct chownmagic { @@ -754,6 +793,7 @@ static struct builtin bintab[] = { /* The names which overlap commands without necessarily being * fully compatible. */ BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs", NULL), + BUILTIN("chmod", 0, bin_chmod, 2, -1, 0, "Rs", NULL), BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs", NULL), BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL), BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm:", NULL), @@ -763,6 +803,7 @@ static struct builtin bintab[] = { BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL), /* The "safe" zsh-only names */ BUILTIN("zf_chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs", NULL), + BUILTIN("zf_chmod", 0, bin_chmod, 2, -1, 0, "Rs", NULL), BUILTIN("zf_chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs", NULL), BUILTIN("zf_ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL), BUILTIN("zf_mkdir", 0, bin_mkdir, 1, -1, 0, "pm:", NULL), -- cgit 1.4.1