| ln.c - sbase - suckless unix tools | |
| git clone git://git.suckless.org/sbase | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| ln.c (2256B) | |
| --- | |
| 1 /* See LICENSE file for copyright and license details. */ | |
| 2 #include <sys/stat.h> | |
| 3 | |
| 4 #include <errno.h> | |
| 5 #include <fcntl.h> | |
| 6 #include <libgen.h> | |
| 7 #include <string.h> | |
| 8 #include <unistd.h> | |
| 9 | |
| 10 #include "util.h" | |
| 11 | |
| 12 static void | |
| 13 usage(void) | |
| 14 { | |
| 15 eprintf("usage: %s [-f] [-L | -P | -s] target [name]\n" | |
| 16 " %s [-f] [-L | -P | -s] target ... dir\n", argv0,… | |
| 17 } | |
| 18 | |
| 19 int | |
| 20 main(int argc, char *argv[]) | |
| 21 { | |
| 22 char *targetdir = ".", *target = NULL; | |
| 23 int ret = 0, sflag = 0, fflag = 0, dirfd = AT_FDCWD, | |
| 24 hastarget = 0, flags = AT_SYMLINK_FOLLOW; | |
| 25 struct stat st, tst; | |
| 26 | |
| 27 ARGBEGIN { | |
| 28 case 'f': | |
| 29 fflag = 1; | |
| 30 break; | |
| 31 case 'L': | |
| 32 flags |= AT_SYMLINK_FOLLOW; | |
| 33 break; | |
| 34 case 'P': | |
| 35 flags &= ~AT_SYMLINK_FOLLOW; | |
| 36 break; | |
| 37 case 's': | |
| 38 sflag = 1; | |
| 39 break; | |
| 40 default: | |
| 41 usage(); | |
| 42 } ARGEND | |
| 43 | |
| 44 if (!argc) | |
| 45 usage(); | |
| 46 | |
| 47 if (argc > 1) { | |
| 48 if (!stat(argv[argc - 1], &st) && S_ISDIR(st.st_mode)) { | |
| 49 if ((dirfd = open(argv[argc - 1], O_RDONLY)) < 0) | |
| 50 eprintf("open %s:", argv[argc - 1]); | |
| 51 targetdir = argv[argc - 1]; | |
| 52 if (targetdir[strlen(targetdir) - 1] == '/') | |
| 53 targetdir[strlen(targetdir) - 1] = '\0'; | |
| 54 } else if (argc == 2) { | |
| 55 hastarget = 1; | |
| 56 target = argv[argc - 1]; | |
| 57 } else { | |
| 58 eprintf("%s: not a directory\n", argv[argc - 1]); | |
| 59 } | |
| 60 argv[argc - 1] = NULL; | |
| 61 argc--; | |
| 62 } | |
| 63 | |
| 64 for (; *argv; argc--, argv++) { | |
| 65 if (!hastarget) | |
| 66 target = basename(*argv); | |
| 67 | |
| 68 if (!sflag) { | |
| 69 if (stat(*argv, &st) < 0) { | |
| 70 weprintf("stat %s:", *argv); | |
| 71 ret = 1; | |
| 72 continue; | |
| 73 } else if (fstatat(dirfd, target, &tst, AT_SYMLI… | |
| 74 if (errno != ENOENT) { | |
| 75 weprintf("fstatat %s %s:", targe… | |
| 76 ret = 1; | |
| 77 continue; | |
| 78 } | |
| 79 } else if (st.st_dev == tst.st_dev && st.st_ino … | |
| 80 if (!fflag) { | |
| 81 weprintf("%s and %s/%s are the s… | |
| 82 *argv, targetdir… | |
| 83 ret = 1; | |
| 84 } | |
| 85 continue; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 if (fflag && unlinkat(dirfd, target, 0) < 0 && errno != … | |
| 90 weprintf("unlinkat %s %s:", targetdir, target); | |
| 91 ret = 1; | |
| 92 continue; | |
| 93 } | |
| 94 if ((sflag ? symlinkat(*argv, dirfd, target) : | |
| 95 linkat(AT_FDCWD, *argv, dirfd, target, flag… | |
| 96 weprintf("%s %s <- %s/%s:", sflag ? "symlinkat" … | |
| 97 *argv, targetdir, target); | |
| 98 ret = 1; | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 return ret; | |
| 103 } |