blob: 3b822e8c7fa0b2f92bc48dcf66f7dadb62021baf
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Mini ln implementation for busybox |
4 | * |
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
8 | */ |
9 | |
10 | /* BB_AUDIT SUSv3 compliant */ |
11 | /* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */ |
12 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */ |
13 | |
14 | //usage:#define ln_trivial_usage |
15 | //usage: "[OPTIONS] TARGET... LINK|DIR" |
16 | //usage:#define ln_full_usage "\n\n" |
17 | //usage: "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" |
18 | //usage: "\n -s Make symlinks instead of hardlinks" |
19 | //usage: "\n -f Remove existing destinations" |
20 | //usage: "\n -n Don't dereference symlinks - treat like normal file" |
21 | //usage: "\n -b Make a backup of the target (if exists) before link operation" |
22 | //usage: "\n -S suf Use suffix instead of ~ when making backup files" |
23 | //usage: "\n -T 2nd arg must be a DIR" |
24 | //usage: "\n -v Verbose" |
25 | //usage: |
26 | //usage:#define ln_example_usage |
27 | //usage: "$ ln -s BusyBox /tmp/ls\n" |
28 | //usage: "$ ls -l /tmp/ls\n" |
29 | //usage: "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" |
30 | |
31 | #include "libbb.h" |
32 | |
33 | /* This is a NOEXEC applet. Be very careful! */ |
34 | |
35 | |
36 | #define LN_SYMLINK (1 << 0) |
37 | #define LN_FORCE (1 << 1) |
38 | #define LN_NODEREFERENCE (1 << 2) |
39 | #define LN_BACKUP (1 << 3) |
40 | #define LN_SUFFIX (1 << 4) |
41 | #define LN_VERBOSE (1 << 5) |
42 | #define LN_LINKFILE (1 << 6) |
43 | |
44 | int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
45 | int ln_main(int argc, char **argv) |
46 | { |
47 | int status = EXIT_SUCCESS; |
48 | int opts; |
49 | char *last; |
50 | char *src_name; |
51 | char *src; |
52 | char *suffix = (char*)"~"; |
53 | struct stat statbuf; |
54 | int (*link_func)(const char *, const char *); |
55 | |
56 | opt_complementary = "-1"; /* min one arg */ |
57 | opts = getopt32(argv, "sfnbS:vT", &suffix); |
58 | |
59 | last = argv[argc - 1]; |
60 | argv += optind; |
61 | argc -= optind; |
62 | |
63 | if ((opts & LN_LINKFILE) && argc > 2) { |
64 | bb_error_msg_and_die("-T accepts 2 args max"); |
65 | } |
66 | |
67 | if (!argv[1]) { |
68 | /* "ln PATH/TO/FILE" -> "ln PATH/TO/FILE FILE" */ |
69 | *--argv = last; |
70 | /* xstrdup is needed: "ln -s PATH/TO/FILE/" is equivalent to |
71 | * "ln -s PATH/TO/FILE/ FILE", not "ln -s PATH/TO/FILE FILE" |
72 | */ |
73 | last = bb_get_last_path_component_strip(xstrdup(last)); |
74 | } |
75 | |
76 | do { |
77 | src_name = NULL; |
78 | src = last; |
79 | |
80 | if (is_directory(src, |
81 | (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE |
82 | ) |
83 | ) { |
84 | if (opts & LN_LINKFILE) { |
85 | bb_error_msg_and_die("'%s' is a directory", src); |
86 | } |
87 | src_name = xstrdup(*argv); |
88 | src = concat_path_file(src, bb_get_last_path_component_strip(src_name)); |
89 | free(src_name); |
90 | src_name = src; |
91 | } |
92 | if (!(opts & LN_SYMLINK) && stat(*argv, &statbuf)) { |
93 | // coreutils: "ln dangling_symlink new_hardlink" works |
94 | if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) { |
95 | bb_simple_perror_msg(*argv); |
96 | status = EXIT_FAILURE; |
97 | free(src_name); |
98 | continue; |
99 | } |
100 | } |
101 | |
102 | if (opts & LN_BACKUP) { |
103 | char *backup; |
104 | backup = xasprintf("%s%s", src, suffix); |
105 | if (rename(src, backup) < 0 && errno != ENOENT) { |
106 | bb_simple_perror_msg(src); |
107 | status = EXIT_FAILURE; |
108 | free(backup); |
109 | continue; |
110 | } |
111 | free(backup); |
112 | /* |
113 | * When the source and dest are both hard links to the same |
114 | * inode, a rename may succeed even though nothing happened. |
115 | * Therefore, always unlink(). |
116 | */ |
117 | unlink(src); |
118 | } else if (opts & LN_FORCE) { |
119 | unlink(src); |
120 | } |
121 | |
122 | link_func = link; |
123 | if (opts & LN_SYMLINK) { |
124 | link_func = symlink; |
125 | } |
126 | |
127 | if (opts & LN_VERBOSE) { |
128 | printf("'%s' -> '%s'\n", src, *argv); |
129 | } |
130 | |
131 | if (link_func(*argv, src) != 0) { |
132 | bb_simple_perror_msg(src); |
133 | status = EXIT_FAILURE; |
134 | } |
135 | |
136 | free(src_name); |
137 | |
138 | } while ((++argv)[1]); |
139 | |
140 | return status; |
141 | } |
142 |