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 } |