mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-03 10:21:46 +02:00
zsh-workers/8982
This commit is contained in:
parent
015e22c141
commit
4f9b1b9804
5 changed files with 310 additions and 69 deletions
|
@ -4,6 +4,43 @@ cindex(files, manipulating)
|
||||||
The tt(files) module makes some standard commands available as builtins:
|
The tt(files) module makes some standard commands available as builtins:
|
||||||
|
|
||||||
startitem()
|
startitem()
|
||||||
|
findex(chgrp)
|
||||||
|
item(tt(chgrp) [ tt(-Rs) ] 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(chown)
|
||||||
|
item(tt(chown) [ tt(-Rs) ] var(user-spec) var(filename) ...)(
|
||||||
|
Changes ownership and group of files specified.
|
||||||
|
|
||||||
|
The var(user-spec) can be in four forms:
|
||||||
|
|
||||||
|
startsitem()
|
||||||
|
sitem(var(user))(change owner to var(user); do not change group)
|
||||||
|
sitem(var(user)tt(:))(change owner to var(user); change group to var(user)'s primary group)
|
||||||
|
sitem(var(user)tt(:)var(group))(change owner to var(user); change group to var(group))
|
||||||
|
sitem(tt(:)var(group))(do not change owner; change group to var(group))
|
||||||
|
endsitem()
|
||||||
|
|
||||||
|
In each case, the `tt(:)' may instead be a `tt(.)'.
|
||||||
|
Each of var(user) and var(group) may be either a username (or group name, as
|
||||||
|
appropriate) or a decimal user ID (group ID). Interpretation as a name
|
||||||
|
takes precedence, if there is an all-numeric username (or group name).
|
||||||
|
|
||||||
|
The tt(-R) option causes tt(chown) to recursively descend into directories,
|
||||||
|
changing the ownership of all files in the directory after
|
||||||
|
changing the ownership of the directory itself.
|
||||||
|
|
||||||
|
The tt(-s) option is a zsh extension to tt(chown) functionality. It enables
|
||||||
|
paranoid behaviour, intended to avoid security problems involving
|
||||||
|
a tt(chown) being tricked into affecting files other than the ones
|
||||||
|
intended. It will refuse to follow symbolic links, so that (for example)
|
||||||
|
``tt(chown luser /tmp/foo/passwd)'' can't accidentally chown 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 chown of
|
||||||
|
a deep directory tree can't end up recursively chowning tt(/usr) as
|
||||||
|
a result of directories being moved up the tree.
|
||||||
|
)
|
||||||
findex(ln)
|
findex(ln)
|
||||||
xitem(tt(ln) [ tt(-dfis) ] var(filename) var(dest))
|
xitem(tt(ln) [ tt(-dfis) ] var(filename) var(dest))
|
||||||
item(tt(ln) [ tt(-dfis) ] var(filename) ... var(dir))(
|
item(tt(ln) [ tt(-dfis) ] var(filename) ... var(dir))(
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "files.mdh"
|
#include "files.mdh"
|
||||||
|
|
||||||
typedef int (*MoveFunc) _((char const *, char const *));
|
typedef int (*MoveFunc) _((char const *, char const *));
|
||||||
|
typedef int (*RecurseFunc) _((char *, char *, struct stat const *, void *));
|
||||||
|
|
||||||
#ifndef STDC_HEADERS
|
#ifndef STDC_HEADERS
|
||||||
extern int link _((const char *, const char *));
|
extern int link _((const char *, const char *));
|
||||||
|
@ -37,6 +38,8 @@ extern int symlink _((const char *, const char *));
|
||||||
extern int rename _((const char *, const char *));
|
extern int rename _((const char *, const char *));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct recursivecmd;
|
||||||
|
|
||||||
#include "files.pro"
|
#include "files.pro"
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -312,20 +315,42 @@ domove(char *nam, MoveFunc move, char *p, char *q, int flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rm builtin */
|
/* general recursion */
|
||||||
|
|
||||||
|
struct recursivecmd {
|
||||||
|
char *nam;
|
||||||
|
int opt_noerr;
|
||||||
|
int opt_recurse;
|
||||||
|
int opt_safe;
|
||||||
|
RecurseFunc dirpre_func;
|
||||||
|
RecurseFunc dirpost_func;
|
||||||
|
RecurseFunc leaf_func;
|
||||||
|
void *magic;
|
||||||
|
};
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static int
|
static int
|
||||||
bin_rm(char *nam, char **args, char *ops, int func)
|
recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe,
|
||||||
|
char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func,
|
||||||
|
RecurseFunc leaf_func, void *magic)
|
||||||
{
|
{
|
||||||
int err = 0, len;
|
int err = 0, len;
|
||||||
char *rp, *s;
|
char *rp, *s;
|
||||||
struct dirsav ds;
|
struct dirsav ds;
|
||||||
|
struct recursivecmd reccmd;
|
||||||
|
|
||||||
|
reccmd.nam = nam;
|
||||||
|
reccmd.opt_noerr = opt_noerr;
|
||||||
|
reccmd.opt_recurse = opt_recurse;
|
||||||
|
reccmd.opt_safe = opt_safe;
|
||||||
|
reccmd.dirpre_func = dirpre_func;
|
||||||
|
reccmd.dirpost_func = dirpost_func;
|
||||||
|
reccmd.leaf_func = leaf_func;
|
||||||
|
reccmd.magic = magic;
|
||||||
ds.ino = ds.dev = 0;
|
ds.ino = ds.dev = 0;
|
||||||
ds.dirname = NULL;
|
ds.dirname = NULL;
|
||||||
ds.dirfd = ds.level = -1;
|
ds.dirfd = ds.level = -1;
|
||||||
if (ops['r'] || ops['s']) {
|
if (opt_recurse || opt_safe) {
|
||||||
if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 &&
|
if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 &&
|
||||||
zgetdir(&ds) && *ds.dirname != '/')
|
zgetdir(&ds) && *ds.dirname != '/')
|
||||||
ds.dirfd = open("..", O_RDONLY|O_NOCTTY);
|
ds.dirfd = open("..", O_RDONLY|O_NOCTTY);
|
||||||
|
@ -333,7 +358,7 @@ bin_rm(char *nam, char **args, char *ops, int func)
|
||||||
for(; !errflag && !(err & 2) && *args; args++) {
|
for(; !errflag && !(err & 2) && *args; args++) {
|
||||||
rp = ztrdup(*args);
|
rp = ztrdup(*args);
|
||||||
unmetafy(rp, &len);
|
unmetafy(rp, &len);
|
||||||
if (ops['s']) {
|
if (opt_safe) {
|
||||||
s = strrchr(rp, '/');
|
s = strrchr(rp, '/');
|
||||||
if (s && !s[1]) {
|
if (s && !s[1]) {
|
||||||
while (*s == '/' && s > rp)
|
while (*s == '/' && s > rp)
|
||||||
|
@ -353,16 +378,16 @@ bin_rm(char *nam, char **args, char *ops, int func)
|
||||||
d.ino = d.dev = 0;
|
d.ino = d.dev = 0;
|
||||||
d.dirname = NULL;
|
d.dirname = NULL;
|
||||||
d.dirfd = d.level = -1;
|
d.dirfd = d.level = -1;
|
||||||
err |= dorm(nam, *args, s + 1, ops, &d, 0);
|
err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0);
|
||||||
zsfree(d.dirname);
|
zsfree(d.dirname);
|
||||||
if (restoredir(&ds))
|
if (restoredir(&ds))
|
||||||
err |= 2;
|
err |= 2;
|
||||||
} else
|
} else if(!opt_noerr)
|
||||||
zwarnnam(nam, "%s: %e", *args, errno);
|
zwarnnam(nam, "%s: %e", *args, errno);
|
||||||
} else
|
} else
|
||||||
err |= dorm(nam, *args, rp, ops, &ds, 0);
|
err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0);
|
||||||
} else
|
} else
|
||||||
err |= dorm(nam, *args, rp, ops, &ds, 1);
|
err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1);
|
||||||
zfree(rp, len + 1);
|
zfree(rp, len + 1);
|
||||||
}
|
}
|
||||||
if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) {
|
if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) {
|
||||||
|
@ -373,76 +398,55 @@ bin_rm(char *nam, char **args, char *ops, int func)
|
||||||
if (ds.dirfd >= 0)
|
if (ds.dirfd >= 0)
|
||||||
close(ds.dirfd);
|
close(ds.dirfd);
|
||||||
zsfree(ds.dirname);
|
zsfree(ds.dirname);
|
||||||
return ops['f'] ? 0 : !!err;
|
return !!err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static int
|
static int
|
||||||
dorm(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
|
recursivecmd_doone(struct recursivecmd const *reccmd,
|
||||||
|
char *arg, char *rp, struct dirsav *ds, int first)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st, *sp = NULL;
|
||||||
|
|
||||||
if((!ops['d'] || !ops['f']) && !lstat(rp, &st)) {
|
if(reccmd->opt_recurse && !lstat(rp, &st)) {
|
||||||
if(!ops['d'] && S_ISDIR(st.st_mode)) {
|
if(S_ISDIR(st.st_mode))
|
||||||
if(ops['r'])
|
return recursivecmd_dorec(reccmd, arg, rp, &st, ds, first);
|
||||||
return dormr(nam, arg, rp, ops, ds, first);
|
sp = &st;
|
||||||
if(!ops['f'])
|
|
||||||
zwarnnam(nam, "%s: %e", arg, EISDIR);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
if(!ops['f'] && ops['i']) {
|
return reccmd->leaf_func(arg, rp, sp, reccmd->magic);
|
||||||
nicezputs(nam, stderr);
|
|
||||||
fputs(": remove `", stderr);
|
|
||||||
nicezputs(arg, stderr);
|
|
||||||
fputs("'? ", stderr);
|
|
||||||
fflush(stderr);
|
|
||||||
if(!ask())
|
|
||||||
return 0;
|
|
||||||
} else if(!ops['f'] &&
|
|
||||||
!S_ISLNK(st.st_mode) &&
|
|
||||||
access(rp, W_OK)) {
|
|
||||||
nicezputs(nam, stderr);
|
|
||||||
fputs(": remove `", stderr);
|
|
||||||
nicezputs(arg, stderr);
|
|
||||||
fprintf(stderr, "', overriding mode %04o? ",
|
|
||||||
mode_to_octal(st.st_mode));
|
|
||||||
fflush(stderr);
|
|
||||||
if(!ask())
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!unlink(rp))
|
|
||||||
return 0;
|
|
||||||
if(!ops['f'])
|
|
||||||
zwarnnam(nam, "%s: %e", arg, errno);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static int
|
static int
|
||||||
dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
|
recursivecmd_dorec(struct recursivecmd const *reccmd,
|
||||||
|
char *arg, char *rp, struct stat const *sp, struct dirsav *ds, int first)
|
||||||
{
|
{
|
||||||
char *fn;
|
char *fn;
|
||||||
DIR *d;
|
DIR *d;
|
||||||
int err;
|
int err, err1;
|
||||||
struct dirsav dsav;
|
struct dirsav dsav;
|
||||||
char *files = NULL;
|
char *files = NULL;
|
||||||
int fileslen = 0;
|
int fileslen = 0;
|
||||||
|
|
||||||
|
err1 = reccmd->dirpre_func(arg, rp, sp, reccmd->magic);
|
||||||
|
if(err1 & 2)
|
||||||
|
return 2;
|
||||||
|
|
||||||
err = -lchdir(rp, ds, !first);
|
err = -lchdir(rp, ds, !first);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (!ops['f'])
|
if(!reccmd->opt_noerr)
|
||||||
zwarnnam(nam, "%s: %e", arg, errno);
|
zwarnnam(reccmd->nam, "%s: %e", arg, errno);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
err = err1;
|
||||||
|
|
||||||
dsav.ino = dsav.dev = 0;
|
dsav.ino = dsav.dev = 0;
|
||||||
dsav.dirname = NULL;
|
dsav.dirname = NULL;
|
||||||
dsav.dirfd = dsav.level = -1;
|
dsav.dirfd = dsav.level = -1;
|
||||||
d = opendir(".");
|
d = opendir(".");
|
||||||
if(!d) {
|
if(!d) {
|
||||||
if(!ops['f'])
|
if(!reccmd->opt_noerr)
|
||||||
zwarnnam(nam, "%s: %e", arg, errno);
|
zwarnnam(reccmd->nam, "%s: %e", arg, errno);
|
||||||
err = 1;
|
err = 1;
|
||||||
} else {
|
} else {
|
||||||
int arglen = strlen(arg) + 1;
|
int arglen = strlen(arg) + 1;
|
||||||
|
@ -462,7 +466,7 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
|
||||||
narg[arglen-1] = '/';
|
narg[arglen-1] = '/';
|
||||||
strcpy(narg + arglen, fn);
|
strcpy(narg + arglen, fn);
|
||||||
unmetafy(fn, NULL);
|
unmetafy(fn, NULL);
|
||||||
err |= dorm(nam, narg, fn, ops, &dsav, 0);
|
err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0);
|
||||||
fn += l;
|
fn += l;
|
||||||
}
|
}
|
||||||
hrealloc(files, fileslen, 0);
|
hrealloc(files, fileslen, 0);
|
||||||
|
@ -471,25 +475,219 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
|
||||||
if (err & 2)
|
if (err & 2)
|
||||||
return 2;
|
return 2;
|
||||||
if (restoredir(ds)) {
|
if (restoredir(ds)) {
|
||||||
if(!ops['f'])
|
if(!reccmd->opt_noerr)
|
||||||
zwarnnam(nam, "failed to return to previous directory: %e",
|
zwarnnam(reccmd->nam, "failed to return to previous directory: %e",
|
||||||
NULL, errno);
|
NULL, errno);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if(!ops['f'] && ops['i']) {
|
return err | reccmd->dirpost_func(arg, rp, sp, reccmd->magic);
|
||||||
nicezputs(nam, stderr);
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
recurse_donothing(char *arg, char *rp, struct stat const *sp, void *magic)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rm builtin */
|
||||||
|
|
||||||
|
struct rmmagic {
|
||||||
|
char *nam;
|
||||||
|
int opt_force;
|
||||||
|
int opt_interact;
|
||||||
|
int opt_unlinkdir;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
rm_leaf(char *arg, char *rp, struct stat const *sp, void *magic)
|
||||||
|
{
|
||||||
|
struct rmmagic *rmm = magic;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(!rmm->opt_unlinkdir || !rmm->opt_force) {
|
||||||
|
if(!sp) {
|
||||||
|
if(!lstat(rp, &st))
|
||||||
|
sp = &st;
|
||||||
|
}
|
||||||
|
if(sp) {
|
||||||
|
if(!rmm->opt_unlinkdir && S_ISDIR(sp->st_mode)) {
|
||||||
|
if(rmm->opt_force)
|
||||||
|
return 0;
|
||||||
|
zwarnnam(rmm->nam, "%s: %e", arg, EISDIR);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(rmm->opt_interact) {
|
||||||
|
nicezputs(rmm->nam, stderr);
|
||||||
fputs(": remove `", stderr);
|
fputs(": remove `", stderr);
|
||||||
nicezputs(arg, stderr);
|
nicezputs(arg, stderr);
|
||||||
fputs("'? ", stderr);
|
fputs("'? ", stderr);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
if(!ask())
|
if(!ask())
|
||||||
return err;
|
return 0;
|
||||||
|
} else if(!rmm->opt_force &&
|
||||||
|
!S_ISLNK(sp->st_mode) &&
|
||||||
|
access(rp, W_OK)) {
|
||||||
|
nicezputs(rmm->nam, stderr);
|
||||||
|
fputs(": remove `", stderr);
|
||||||
|
nicezputs(arg, stderr);
|
||||||
|
fprintf(stderr, "', overriding mode %04o? ",
|
||||||
|
mode_to_octal(sp->st_mode));
|
||||||
|
fflush(stderr);
|
||||||
|
if(!ask())
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if(!rmdir(rp))
|
}
|
||||||
return err;
|
}
|
||||||
if(!ops['f'])
|
if(unlink(rp) && !rmm->opt_force) {
|
||||||
zwarnnam(nam, "%s: %e", arg, errno);
|
zwarnnam(rmm->nam, "%s: %e", arg, errno);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
rm_dirpost(char *arg, char *rp, struct stat const *sp, void *magic)
|
||||||
|
{
|
||||||
|
struct rmmagic *rmm = magic;
|
||||||
|
|
||||||
|
if(rmm->opt_interact) {
|
||||||
|
nicezputs(rmm->nam, stderr);
|
||||||
|
fputs(": remove `", stderr);
|
||||||
|
nicezputs(arg, stderr);
|
||||||
|
fputs("'? ", stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
if(!ask())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(rmdir(rp) && !rmm->opt_force) {
|
||||||
|
zwarnnam(rmm->nam, "%s: %e", arg, errno);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
bin_rm(char *nam, char **args, char *ops, int func)
|
||||||
|
{
|
||||||
|
struct rmmagic rmm;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
rmm.nam = nam;
|
||||||
|
rmm.opt_force = ops['f'];
|
||||||
|
rmm.opt_interact = ops['i'] && !ops['f'];
|
||||||
|
rmm.opt_unlinkdir = ops['d'];
|
||||||
|
err = recursivecmd(nam, ops['f'], ops['r'] && !ops['d'], ops['s'],
|
||||||
|
args, recurse_donothing, rm_dirpost, rm_leaf, &rmm);
|
||||||
|
return ops['f'] ? 0 : err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chown builtin */
|
||||||
|
|
||||||
|
struct chownmagic {
|
||||||
|
char *nam;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
chown_dochown(char *arg, char *rp, struct stat const *sp, void *magic)
|
||||||
|
{
|
||||||
|
struct chownmagic *chm = magic;
|
||||||
|
|
||||||
|
if(lchown(rp, chm->uid, chm->gid)) {
|
||||||
|
zwarnnam(chm->nam, "%s: %e", arg, errno);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static unsigned long getnumeric(char *p, int *errp)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
if(*p < '0' || *p > '9') {
|
||||||
|
*errp = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret = strtoul(p, &p, 10);
|
||||||
|
*errp = !!*p;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { BIN_CHOWN, BIN_CHGRP };
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
bin_chown(char *nam, char **args, char *ops, int func)
|
||||||
|
{
|
||||||
|
struct chownmagic chm;
|
||||||
|
char *uspec = ztrdup(*args), *p = uspec;
|
||||||
|
|
||||||
|
chm.nam = nam;
|
||||||
|
if(func == BIN_CHGRP) {
|
||||||
|
chm.uid = -1;
|
||||||
|
goto dogroup;
|
||||||
|
}
|
||||||
|
if(*p == ':' || *p == '.') {
|
||||||
|
chm.uid = -1;
|
||||||
|
p++;
|
||||||
|
goto dogroup;
|
||||||
|
} else {
|
||||||
|
struct passwd *pwd;
|
||||||
|
char *end = strchr(p, ':');
|
||||||
|
if(!end)
|
||||||
|
end = strchr(p, '.');
|
||||||
|
if(end)
|
||||||
|
*end = 0;
|
||||||
|
pwd = getpwnam(p);
|
||||||
|
if(pwd)
|
||||||
|
chm.uid = pwd->pw_uid;
|
||||||
|
else {
|
||||||
|
int err;
|
||||||
|
chm.uid = getnumeric(p, &err);
|
||||||
|
if(err) {
|
||||||
|
zwarnnam(nam, "%s: no such user", p, 0);
|
||||||
|
free(uspec);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(end) {
|
||||||
|
p = end+1;
|
||||||
|
if(!*p) {
|
||||||
|
if(!pwd && !(pwd = getpwuid(chm.uid))) {
|
||||||
|
zwarnnam(nam, "%s: no such user", uspec, 0);
|
||||||
|
free(uspec);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
chm.gid = pwd->pw_gid;
|
||||||
|
} else {
|
||||||
|
struct group *grp;
|
||||||
|
dogroup:
|
||||||
|
grp = getgrnam(p);
|
||||||
|
if(grp)
|
||||||
|
chm.gid = grp->gr_gid;
|
||||||
|
else {
|
||||||
|
int err;
|
||||||
|
chm.gid = getnumeric(p, &err);
|
||||||
|
if(err) {
|
||||||
|
zwarnnam(nam, "%s: no such group", p, 0);
|
||||||
|
free(uspec);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
chm.gid = -1;
|
||||||
|
}
|
||||||
|
free(uspec);
|
||||||
|
return recursivecmd(nam, 0, ops['R'], ops['s'],
|
||||||
|
args + 1, chown_dochown, recurse_donothing, chown_dochown, &chm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* module paraphernalia */
|
/* module paraphernalia */
|
||||||
|
@ -501,6 +699,8 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct builtin bintab[] = {
|
static struct builtin bintab[] = {
|
||||||
|
BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "Rs", NULL),
|
||||||
|
BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "Rs", NULL),
|
||||||
BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
|
BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
|
||||||
BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL),
|
BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL),
|
||||||
BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
|
BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
autobins="ln mkdir mv rm rmdir sync"
|
autobins="chgrp chown ln mkdir mv rm rmdir sync"
|
||||||
|
|
||||||
objects="files.o"
|
objects="files.o"
|
||||||
|
|
|
@ -583,6 +583,10 @@ struct timezone {
|
||||||
# define R_OK 4
|
# define R_OK 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_LCHOWN
|
||||||
|
# define lchown chown
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_MEMCPY
|
#ifndef HAVE_MEMCPY
|
||||||
# define memcpy memmove
|
# define memcpy memmove
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -784,7 +784,7 @@ zsh_STRUCT_MEMBER([
|
||||||
dnl need to integrate this function
|
dnl need to integrate this function
|
||||||
dnl AC_FUNC_STRFTIME
|
dnl AC_FUNC_STRFTIME
|
||||||
|
|
||||||
AC_CHECK_FUNCS(memcpy memmove \
|
AC_CHECK_FUNCS(lchown memcpy memmove \
|
||||||
strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \
|
strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \
|
||||||
getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \
|
getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \
|
||||||
sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \
|
sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \
|
||||||
|
|
Loading…
Reference in a new issue