sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 9fd4a745f8f3d51e18d7528118fbbf9dca1d66d6
parent 3b187f482653da01f59a9f37344d20ad7fcf3447
Author: FRIGN <dev@frign.de>
Date:   Fri Mar 13 00:25:32 +0100

Add history and config-struct to recurse

For loop detection, a history is mandatory. In the process of also
adding a flexible struct to recurse, the recurse-definition was moved
to fs.h.
The motivation behind the struct is to allow easy extensions to the
recurse-function without having to change the prototypes of all
functions in the process.
Adding flags is really simple as well now.

Using the recursor-struct, it's also easier to see which defaults
apply to a program (for instance, which type of follow, ...).

Another change was to add proper stat-lstat-usage in recurse. It
was wrong before.

Diffstat:
chgrp.c | 16+++++++++-------
chmod.c | 12+++++++-----
chown.c | 17++++++++++-------
du.c | 24+++++++++++++-----------
fs.h | 26+++++++++++++++++++++++++-
libutil/recurse.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
libutil/rm.c | 4++--
mv.c | 4+++-
rm.c | 6++++--
tar.c | 12+++++++-----
util.h | 3---
11 files changed, 130 insertions(+), 65 deletions(-)
diff --git a/chgrp.c b/chgrp.c @@ -5,6 +5,7 @@ #include <grp.h> #include <unistd.h> +#include "fs.h" #include "util.h" static struct stat st; @@ -14,12 +15,12 @@ static gid_t gid = -1; static int ret = 0; static void -chgrp(const char *path, int depth, void *data) +chgrp(const char *path, void *data, struct recursor *r) { char *chownf_name; int (*chownf)(const char *, uid_t, gid_t); - if (recurse_follow == 'P' || (recurse_follow == 'H' && depth) || (hflag && !depth)) { + if (r->follow == 'P' || (r->follow == 'H' && r->depth) || (hflag && !(r->depth))) { chownf_name = "lchown"; chownf = lchown; } else { @@ -31,7 +32,7 @@ chgrp(const char *path, int depth, void *data) weprintf("%s %s:", chownf_name, path); ret = 1; } else if (Rflag) { - recurse(path, chgrp, depth, NULL); + recurse(path, NULL, r); } } @@ -45,6 +46,7 @@ int main(int argc, char *argv[]) { struct group *gr; + struct recursor r = { .fn = chgrp, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0 }; ARGBEGIN { case 'h': @@ -56,7 +58,7 @@ main(int argc, char *argv[]) case 'H': case 'L': case 'P': - recurse_follow = ARGC(); + r.follow = ARGC(); break; default: usage(); @@ -74,14 +76,14 @@ main(int argc, char *argv[]) } gid = gr->gr_gid; - for (; *argv; argc--, argv++) { + for (argc--, argv++; *argv; argc--, argv++) { if (stat(*argv, &st) < 0) { weprintf("stat %s:", *argv); ret = 1; continue; } - chgrp(*argv, 0, NULL); + chgrp(*argv, NULL, &r); } - return ret; + return ret || recurse_status; } diff --git a/chmod.c b/chmod.c @@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include <sys/stat.h> +#include "fs.h" #include "util.h" static int Rflag = 0; @@ -9,7 +10,7 @@ static mode_t mask = 0; static int ret = 0; static void -chmodr(const char *path, int depth, void *data) +chmodr(const char *path, void *data, struct recursor *r) { struct stat st; mode_t m; @@ -25,7 +26,7 @@ chmodr(const char *path, int depth, void *data) weprintf("chmod %s:", path); ret = 1; } else if (Rflag) - recurse(path, chmodr, depth, NULL); + recurse(path, NULL, r); } static void @@ -37,6 +38,7 @@ usage(void) int main(int argc, char *argv[]) { + struct recursor r = { .fn = chmodr, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0}; size_t i; argv0 = *(argv++); @@ -52,7 +54,7 @@ main(int argc, char *argv[]) case 'H': case 'L': case 'P': - recurse_follow = (*argv)[i]; + r.follow = (*argv)[i]; break; case 'r': case 'w': case 'x': case 's': case 't': /* -[rwxst] are valid modes, so we're done */ @@ -80,7 +82,7 @@ done: usage(); for (--argc, ++argv; *argv; argc--, argv++) - chmodr(*argv, 0, NULL); + chmodr(*argv, NULL, &r); - return ret; + return ret || recurse_status; } diff --git a/chown.c b/chown.c @@ -7,6 +7,7 @@ #include <string.h> #include <unistd.h> +#include "fs.h" #include "util.h" static int hflag = 0; @@ -16,12 +17,12 @@ static gid_t gid = -1; static int ret = 0; static void -chownpwgr(const char *path, int depth, void *data) +chownpwgr(const char *path, void *data, struct recursor *r) { char *chownf_name; int (*chownf)(const char *, uid_t, gid_t); - if (recurse_follow == 'P' || (recurse_follow == 'H' && depth) || (hflag && !depth)) { + if (r->follow == 'P' || (r->follow == 'H' && r->depth) || (hflag && !(r->depth))) { chownf_name = "lchown"; chownf = lchown; } else { @@ -33,7 +34,7 @@ chownpwgr(const char *path, int depth, void *data) weprintf("%s %s:", chownf_name, path); ret = 1; } else if (Rflag) { - recurse(path, chownpwgr, depth, NULL); + recurse(path, NULL, r); } } @@ -46,10 +47,12 @@ usage(void) int main(int argc, char *argv[]) { - struct passwd *pw; struct group *gr; + struct passwd *pw; + struct recursor r = { .fn = chownpwgr, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0}; char *owner, *group; + ARGBEGIN { case 'h': hflag = 1; @@ -61,7 +64,7 @@ main(int argc, char *argv[]) case 'H': case 'L': case 'P': - recurse_follow = ARGC(); + r.follow = ARGC(); break; default: usage(); @@ -97,7 +100,7 @@ main(int argc, char *argv[]) } } for (argc--, argv++; *argv; argc--, argv++) - chownpwgr(*argv, 0, NULL); + chownpwgr(*argv, NULL, &r); - return ret; + return ret || recurse_status; } diff --git a/du.c b/du.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include <stdio.h> +#include "fs.h" #include "util.h" static size_t maxdepth = SIZE_MAX; @@ -34,24 +35,24 @@ nblks(blkcnt_t blocks) } void -du(const char *path, int depth, void *total) +du(const char *path, void *total, struct recursor *r) { struct stat st; size_t subtotal = 0; if (lstat(path, &st) < 0) { - if (!depth || errno != ENOENT) + if (!(r->depth) || errno != ENOENT) weprintf("stat %s:", path); - if (!depth) + if (!(r->depth)) ret = 1; return; } if (S_ISDIR(st.st_mode)) - recurse(path, du, depth, &subtotal); + recurse(path, &subtotal, r); *((size_t *)total) += subtotal + nblks(st.st_blocks); - if (!sflag && depth <= maxdepth && (S_ISDIR(st.st_mode) || aflag)) + if (!sflag && r->depth <= maxdepth && (S_ISDIR(st.st_mode) || aflag)) printpath(subtotal + nblks(st.st_blocks), path); } @@ -64,8 +65,9 @@ usage(void) int main(int argc, char *argv[]) { - int kflag = 0, dflag = 0; + struct recursor r = { .fn = du, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0}; size_t n = 0; + int kflag = 0, dflag = 0; char *bsize; ARGBEGIN { @@ -86,12 +88,12 @@ main(int argc, char *argv[]) sflag = 1; break; case 'x': - recurse_samedev = 1; + r.flags |= SAMEDEV; break; case 'H': case 'L': case 'P': - recurse_follow = ARGC(); + r.follow = ARGC(); break; default: usage(); @@ -107,16 +109,16 @@ main(int argc, char *argv[]) blksize = 1024; if (!argc) { - du(".", 0, &n); + du(".", &n, &r); if (sflag && !ret) printpath(nblks(n), "."); } else { for (; *argv; argc--, argv++) { - du(argv[0], 0, &n); + du(argv[0], &n, &r); if (sflag && !ret) printpath(n, argv[0]); } } - return ret; + return ret || recurse_status; } diff --git a/fs.h b/fs.h @@ -1,4 +1,24 @@ /* See LICENSE file for copyright and license details. */ +#include <sys/types.h> + +struct history { + struct history *prev; + dev_t dev; + ino_t ino; +}; + +struct recursor { + void (*fn)(const char *, void *, struct recursor *); + struct history *hist; + int depth; + int follow; + int flags; +}; + +enum { + SAMEDEV = 1 << 0, +}; + extern int cp_aflag; extern int cp_fflag; extern int cp_pflag; @@ -11,5 +31,9 @@ extern int rm_fflag; extern int rm_rflag; extern int rm_status; +extern int recurse_status; + +void recurse(const char *, void *, struct recursor *); + int cp(const char *, const char *, int); -void rm(const char *, int, void *); +void rm(const char *, void *, struct recursor *); diff --git a/libutil/recurse.c b/libutil/recurse.c @@ -9,37 +9,61 @@ #include <sys/types.h> #include <unistd.h> +#include "../fs.h" #include "../util.h" -int recurse_follow = 'P'; -int recurse_samedev = 0; +int recurse_status = 0; void -recurse(const char *path, void (*fn)(const char *, int, void *), int depth, void *data) +recurse(const char *path, void *data, struct recursor *r) { struct dirent *d; - struct stat lst, st, dst; + struct history *new, *h; + struct stat st, dst; DIR *dp; - char subpath[PATH_MAX]; + int (*statf)(const char *, struct stat *); + char subpath[PATH_MAX], *statf_name; - if (lstat(path, &lst) < 0) { - if (errno != ENOENT) - weprintf("lstat %s:", path); - return; + if (r->follow == 'P' || (r->follow == 'H' && r->depth)) { + statf_name = "lstat"; + statf = lstat; + } else { + statf_name = "stat"; + statf = stat; } - if (stat(path, &st) < 0) { - if (errno != ENOENT) - weprintf("stat %s:", path); + + if (statf(path, &st) < 0) { + if (errno != ENOENT) { + weprintf("%s %s:", statf_name, path); + recurse_status = 1; + } return; } - if (!S_ISDIR(lst.st_mode) && !(S_ISLNK(lst.st_mode) && S_ISDIR(st.st_mode) && - !(recurse_follow == 'P' || (recurse_follow == 'H' && depth > 0)))) + if (!S_ISDIR(st.st_mode)) return; - if (!(dp = opendir(path))) - eprintf("opendir %s:", path); + new = emalloc(sizeof(struct history)); + + new->prev = r->hist; + r->hist = new; + new->dev = st.st_dev; + new->ino = st.st_ino; + + for (h = new->prev; h; h = h->prev) + if (h->dev == st.st_dev && h->ino == st.st_ino) + return; + + if (!(dp = opendir(path))) { + weprintf("opendir %s:", path); + recurse_status = 1; + return; + } while ((d = readdir(dp))) { + if (r->follow == 'H') { + statf_name = "lstat"; + statf = lstat; + } if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; if (strlcpy(subpath, path, PATH_MAX) >= PATH_MAX) @@ -48,11 +72,16 @@ recurse(const char *path, void (*fn)(const char *, int, void *), int depth, void eprintf("strlcat: path too long\n"); if (strlcat(subpath, d->d_name, PATH_MAX) >= PATH_MAX) eprintf("strlcat: path too long\n"); - if (recurse_samedev && lstat(subpath, &dst) < 0) { - if (errno != ENOENT) - weprintf("stat %s:", subpath); - } else if (!(recurse_samedev && dst.st_dev != lst.st_dev)) - fn(subpath, depth + 1, data); + if ((r->flags & SAMEDEV) && statf(subpath, &dst) < 0) { + if (errno != ENOENT) { + weprintf("%s %s:", statf_name, subpath); + recurse_status = 1; + } + } else if (!((r->flags & SAMEDEV) && dst.st_dev != st.st_dev)) { + r->depth++; + (r->fn)(subpath, data, r); + r->depth--; + } } closedir(dp); diff --git a/libutil/rm.c b/libutil/rm.c @@ -10,10 +10,10 @@ int rm_rflag = 0; int rm_status = 0; void -rm(const char *path, int depth, void *data) +rm(const char *path, void *data, struct recursor *r) { if (rm_rflag) - recurse(path, rm, depth, NULL); + recurse(path, NULL, r); if (remove(path) < 0) { if (!rm_fflag) weprintf("remove %s:", path); diff --git a/mv.c b/mv.c @@ -12,6 +12,8 @@ static int mv_status = 0; static int mv(const char *s1, const char *s2, int depth) { + struct recursor r = { .fn = rm, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0}; + if (!rename(s1, s2)) return (mv_status = 0); if (errno == EXDEV) { @@ -19,7 +21,7 @@ mv(const char *s1, const char *s2, int depth) cp_HLPflag = 'P'; rm_rflag = 1; cp(s1, s2, depth); - rm(s1, 0, NULL); + rm(s1, NULL, &r); return (mv_status = cp_status || rm_status); } mv_status = 1; diff --git a/rm.c b/rm.c @@ -11,6 +11,8 @@ usage(void) int main(int argc, char *argv[]) { + struct recursor r = { .fn = rm, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0}; + ARGBEGIN { case 'f': rm_fflag = 1; @@ -31,7 +33,7 @@ main(int argc, char *argv[]) } for (; *argv; argc--, argv++) - rm(*argv, 0, NULL); + rm(*argv, NULL, &r); - return rm_status; + return rm_status || recurse_status; } diff --git a/tar.c b/tar.c @@ -9,6 +9,7 @@ #include <string.h> #include <unistd.h> +#include "fs.h" #include "util.h" struct header { @@ -234,10 +235,10 @@ print(char * fname, int l, char b[BLKSIZ]) } static void -c(const char *path, int depth, void *data) +c(const char *path, void *data, struct recursor *r) { archive(path); - recurse(path, c, depth, NULL); + recurse(path, NULL, r); } static void @@ -266,6 +267,7 @@ int main(int argc, char *argv[]) { FILE *fp; + struct recursor r = { .fn = c, .hist = NULL, .depth = 0, .follow = 'P', .flags = 0}; struct stat st; char *file = NULL, *dir = ".", mode = '\0'; @@ -293,7 +295,7 @@ main(int argc, char *argv[]) filtermode = ARGC(); break; case 'h': - recurse_follow = 'L'; + r.follow = 'L'; break; default: usage(); @@ -316,7 +318,7 @@ main(int argc, char *argv[]) tarfile = stdout; } chdir(dir); - c(argv[0], 0, NULL); + c(argv[0], NULL, &r); break; case 't': case 'x': @@ -342,5 +344,5 @@ main(int argc, char *argv[]) break; } - return 0; + return recurse_status; } diff --git a/util.h b/util.h @@ -65,9 +65,6 @@ mode_t getumask(void); char *humansize(double); mode_t parsemode(const char *, mode_t, mode_t); void putword(const char *); -extern int recurse_follow; -extern int recurse_samedev; -void recurse(const char *, void (*)(const char *, int, void *), int, void *); #undef strtonum long long strtonum(const char *, long long, long long, const char **); long long enstrtonum(int, const char *, long long, long long);