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, 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_SYMLINK_NOFOLLOW) < 0) { 74 if (errno != ENOENT) { 75 weprintf("fstatat %s %s:", targetdir, target); 76 ret = 1; 77 continue; 78 } 79 } else if (st.st_dev == tst.st_dev && st.st_ino == tst.st_ino) { 80 if (!fflag) { 81 weprintf("%s and %s/%s are the same file\n", 82 *argv, targetdir, target); 83 ret = 1; 84 } 85 continue; 86 } 87 } 88 89 if (fflag && unlinkat(dirfd, target, 0) < 0 && errno != ENOENT) { 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, flags)) < 0) { 96 weprintf("%s %s <- %s/%s:", sflag ? "symlinkat" : "linkat", 97 *argv, targetdir, target); 98 ret = 1; 99 } 100 } 101 102 return ret; 103 }