From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id ba85c61b for ; Sun, 17 Mar 2019 03:09:40 +0000 (UTC) Received: (qmail 16372 invoked by alias); 17 Mar 2019 03:09:29 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 44135 Received: (qmail 16230 invoked by uid 1010); 17 Mar 2019 03:09:29 -0000 X-Qmail-Scanner-Diagnostics: from mail-ed1-f51.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.100.2/25384. spamassassin: 3.4.2. Clear:RC:0(209.85.208.51):SA:0(-1.8/5.0):. Processed in 0.731375 secs); 17 Mar 2019 03:09:29 -0000 X-Envelope-From: phy1729@gmail.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _netblocks.google.com designates 209.85.208.51 as permitted sender) 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== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=idVbe9QETdqzDldAFwMkKhqW5/xivdYejHRrw1m+AAo=; b=mP6rxc0bvgpikwdyBrQjyiJLznPxUf6Fjx6kkOeGHOo99s9ItAOGuGJbdXHm5mpSYj bBvF92JISX1yceD0Udkiei0aMXdI31XKlTgqMr8rDe3JcgTrssix7zV2Wd4syi/uXJrA qtXAfqFrwHAnnNdhjLUIdfhza8+BxdEODE8gh+QhtXbdZYo1XnEL2OYUXhwu9xIQPMQA vABzUPRvtLdbOm3grVaSvxh60r68D34g5PSsbwv/Xhoili6EgWdH/BcwI8blI4nQv0yn sknJrnGaI3JIYgF8hiTzwoAX/731IBb56IoH2NR4qrRJjWH+cyz8OuOK1zzwsOrlazxp Qndw== X-Gm-Message-State: APjAAAWowZycGoymkozsuQiSth68n9tGufbt3AUAmgY3fOH/5hKccxrM rDMh7+ZrpPWVFgos7rYWfQoGhNknwY1X3sGeLIMdo7hE X-Google-Smtp-Source: APXvYqy+reo3g3WbV55CMxmfUHjVh4v3RHf7O56XHU1Ac1VqjGzLjsKbYmnaFzie5A3U1hkOrP7eIfLXF7epyTdX/f0= X-Received: by 2002:a17:906:4819:: with SMTP id w25mr6835812ejq.150.1552792135152; Sat, 16 Mar 2019 20:08:55 -0700 (PDT) MIME-Version: 1.0 From: Matthew Martin Date: Sat, 16 Mar 2019 22:08:44 -0500 Message-ID: Subject: Add chmod builtin To: zsh-workers@zsh.org Content-Type: text/plain; charset="UTF-8" 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),