linkup

Simple symlink farmer
git clone https://git.sinitax.com/sinitax/linkup
Log | Files | Refs | LICENSE | sfeed.txt

commit 6050e79d8069d21f2dd416b30f4fa5096fb5a0f6
parent a286b18428747eafbb6923b86fe5f25c3f70f7bf
Author: Louis Burda <quent.burda@gmail.com>
Date:   Thu, 20 Oct 2022 02:06:37 +0200

Add uninstall option

Diffstat:
Mlinkup.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 90 insertions(+), 49 deletions(-)

diff --git a/linkup.c b/linkup.c @@ -14,6 +14,10 @@ static const char usage[] = "linkup [-h] [-x FILE..] SOURCE DEST"; static bool force; +static const char **ignored; +static int ignorecnt; +static int ignorecap; + bool exists(int dirfd, const char *path) { @@ -23,7 +27,7 @@ exists(int dirfd, const char *path) } void -removeall(int pfd, const char *path) +remove_all(int pfd, const char *path) { struct dirent *ent; struct stat attr; @@ -40,66 +44,22 @@ removeall(int pfd, const char *path) dir = fdopendir(fd); if (!dir) err(1, "opendir"); while ((ent = readdir(dir))) - removeall(fd, ent->d_name); + remove_all(fd, ent->d_name); closedir(dir); } unlinkat(pfd, path, AT_REMOVEDIR); } -int -main(int argc, const char **argv) +void +do_install(const char *spath, const char *dpath) { char spbuf[PATH_MAX], dpbuf[PATH_MAX]; - char spath[PATH_MAX], dpath[PATH_MAX]; struct dirent *ent; struct stat attr; - const char *sarg, *darg; - const char **arg; DIR *sdir, *ddir; - const char **ignored; - int ignorecnt; - int ignorecap; int i; - ignored = NULL; - ignorecap = 0; - ignorecnt = 0; - - force = false; - sarg = darg = NULL; - for (arg = &argv[1]; *arg; arg++) { - if (!strcmp(*arg, "-x")) { - if (ignorecnt == ignorecap) { - ignorecap = (ignorecap + 1) * 2; - ignored = realloc(ignored, - ignorecap * sizeof(const char *)); - } - ignored[ignorecnt] = *arg; - ignorecnt++; - } else if (!strcmp(*arg, "-f")) { - force = true; - } else if (!sarg) { - sarg = *arg; - } else if (!darg) { - darg = *arg; - } else { - printf("Usage: %s\n", usage); - return 0; - } - } - - if (!sarg || !darg) { - fprintf(stderr, "Usage: %s\n", usage); - return 1; - } - - if (!realpath(sarg, spath)) - err(1, "realpath src"); - - if (!realpath(darg, dpath)) - err(1, "realpath dst"); - sdir = opendir(spath); if (!sdir) err(1, "opendir src"); @@ -125,8 +85,8 @@ main(int argc, const char **argv) &attr, AT_SYMLINK_NOFOLLOW)) { if ((attr.st_mode & S_IFMT) != S_IFLNK && !force) errx(1, "dst %s already exists\n", ent->d_name); + remove_all(dirfd(ddir), ent->d_name); } - removeall(dirfd(ddir), ent->d_name); /* create link */ snprintf(spbuf, PATH_MAX, "%s/%s", spath, ent->d_name); @@ -149,5 +109,86 @@ main(int argc, const char **argv) unlinkat(dirfd(ddir), ent->d_name, 0); } + closedir(ddir); + closedir(sdir); +} + +void +do_uninstall(const char *spath, const char *dpath) +{ + struct dirent *ent; + char dpbuf[PATH_MAX]; + DIR *ddir; + + ddir = opendir(dpath); + if (!ddir) err(1, "opendir dst"); + + while ((ent = readdir(ddir))) { + if (ent->d_type != DT_LNK) + continue; + snprintf(dpbuf, PATH_MAX, "%s/%s", dpath, ent->d_name); + if (readlink(dpbuf, dpbuf, PATH_MAX) < 0) + err(1, "readlink"); + realpath(dpbuf, dpbuf); + if (!strncmp(dpbuf, spath, strlen(spath))) + unlinkat(dirfd(ddir), ent->d_name, 0); + } + + closedir(ddir); +} + +int +main(int argc, const char **argv) +{ + char spath[PATH_MAX], dpath[PATH_MAX]; + const char *sarg, *darg; + const char **arg; + bool install; + int i; + + ignored = NULL; + ignorecap = 0; + ignorecnt = 0; + + force = false; + install = true; + sarg = darg = NULL; + for (arg = &argv[1]; *arg; arg++) { + if (!strcmp(*arg, "-x")) { + if (ignorecnt == ignorecap) { + ignorecap = (ignorecap + 1) * 2; + ignored = realloc(ignored, + ignorecap * sizeof(const char *)); + } + ignored[ignorecnt] = *arg; + ignorecnt++; + } else if (!strcmp(*arg, "-u")) { + install = false; + } else if (!strcmp(*arg, "-f")) { + force = true; + } else if (!sarg) { + sarg = *arg; + } else if (!darg) { + darg = *arg; + } else { + printf("Usage: %s\n", usage); + return 0; + } + } + + if (!sarg || !darg) { + fprintf(stderr, "Usage: %s\n", usage); + return 1; + } + + if (!realpath(sarg, spath)) + err(1, "realpath src"); + + if (!realpath(darg, dpath)) + err(1, "realpath dst"); + + if (install) do_install(spath, dpath); + else do_uninstall(spath, dpath); + free(ignored); }