Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Add chmod builtin
- X-seq: zsh-workers 44135
- From: Matthew Martin <phy1729@xxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Add chmod builtin
- Date: Sat, 16 Mar 2019 22:08:44 -0500
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=idVbe9QETdqzDldAFwMkKhqW5/xivdYejHRrw1m+AAo=; b=rTQusmjNvtsJAdYkRTHD+/V9UqN1rBLnJkQS2XLeuseISqmOeJ51tCxa1Feu0NMSN9 UVFIk+5RIHXj6f6DsS8Vz6wEOjrqjk2/u7d5wRw4GG5o0gh7ncL8UFeB21IgQcE+cqFL Qz9eJBCakMUjG76WmbRycqbowB5NsTFTdC/iseUSbPgwXlUjBwdcCRMyJQszoFTrXD/e dORkNdujfSBQ+czN/nwuvK4/l1ncI31zbjH+6ljxkXbRijVYr0rbfaR9d+B9qCdzkINc mcvQLVsooU6YVd9o38uhNZf6kF7iNqLhAHyEJgvW75jdeDYLfAcqRDTxN4OjPw62NvIN r7WQ==
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- List-unsubscribe: <mailto:zsh-workers-unsubscribe@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
Previously in #zsh "so sad that there is no zf_chmod". So here we are.
Since AT_SYMLINK_NOFOLLOW isn't implemented for some fchmodat
implementations (and modifying the mode of a symlink is usually
nonsensical), drop the -h that chgrp/chown support.
I realize Doc/Zsh/mod_files.yo uses behaviour while _chmod uses
behavior. I just matched the zf_chown docs and _chown.
- Matthew Martin
diff --git a/Completion/Unix/Command/_chmod b/Completion/Unix/Command/_chmod
index af64b9eb9..7a9769fd0 100644
--- a/Completion/Unix/Command/_chmod
+++ b/Completion/Unix/Command/_chmod
@@ -1,11 +1,19 @@
-#compdef chmod gchmod
+#compdef chmod gchmod zf_chmod
local curcontext="$curcontext" state line expl ret=1
local -a args privs
args=( '*: :->files' '1: :_file_modes' )
-if _pick_variant gnu=Free\ Soft unix --version; then
+if zmodload -e zsh/files && [[ $words[1] != */* ]]; then
+ # 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'
+ )
+elif _pick_variant gnu=Free\ Soft unix --version; then
args+=(
'(-v --verbose -c --changes)'{-c,--changes}'[report changes made]'
'(-v --verbose -c --changes)'{-v,--verbose}'[output a diagnostic
for every file processed]'
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),
Messages sorted by:
Reverse Date,
Date,
Thread,
Author