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 | #include "libbb.h"
|
---|
15 |
|
---|
16 | /* This is a NOEXEC applet. Be very careful! */
|
---|
17 |
|
---|
18 |
|
---|
19 | #define LN_SYMLINK 1
|
---|
20 | #define LN_FORCE 2
|
---|
21 | #define LN_NODEREFERENCE 4
|
---|
22 | #define LN_BACKUP 8
|
---|
23 | #define LN_SUFFIX 16
|
---|
24 |
|
---|
25 | int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
---|
26 | int ln_main(int argc, char **argv)
|
---|
27 | {
|
---|
28 | int status = EXIT_SUCCESS;
|
---|
29 | int opts;
|
---|
30 | char *last;
|
---|
31 | char *src_name;
|
---|
32 | char *src;
|
---|
33 | char *suffix = (char*)"~";
|
---|
34 | struct stat statbuf;
|
---|
35 | int (*link_func)(const char *, const char *);
|
---|
36 |
|
---|
37 | opt_complementary = "-1"; /* min one arg */
|
---|
38 | opts = getopt32(argv, "sfnbS:", &suffix);
|
---|
39 |
|
---|
40 | last = argv[argc - 1];
|
---|
41 | argv += optind;
|
---|
42 |
|
---|
43 | if (argc == optind + 1) {
|
---|
44 | *--argv = last;
|
---|
45 | last = bb_get_last_path_component_strip(xstrdup(last));
|
---|
46 | }
|
---|
47 |
|
---|
48 | do {
|
---|
49 | src_name = NULL;
|
---|
50 | src = last;
|
---|
51 |
|
---|
52 | if (is_directory(src,
|
---|
53 | (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE,
|
---|
54 | NULL)
|
---|
55 | ) {
|
---|
56 | src_name = xstrdup(*argv);
|
---|
57 | src = concat_path_file(src, bb_get_last_path_component_strip(src_name));
|
---|
58 | free(src_name);
|
---|
59 | src_name = src;
|
---|
60 | }
|
---|
61 | if (!(opts & LN_SYMLINK) && stat(*argv, &statbuf)) {
|
---|
62 | // coreutils: "ln dangling_symlink new_hardlink" works
|
---|
63 | if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) {
|
---|
64 | bb_simple_perror_msg(*argv);
|
---|
65 | status = EXIT_FAILURE;
|
---|
66 | free(src_name);
|
---|
67 | continue;
|
---|
68 | }
|
---|
69 | }
|
---|
70 |
|
---|
71 | if (opts & LN_BACKUP) {
|
---|
72 | char *backup;
|
---|
73 | backup = xasprintf("%s%s", src, suffix);
|
---|
74 | if (rename(src, backup) < 0 && errno != ENOENT) {
|
---|
75 | bb_simple_perror_msg(src);
|
---|
76 | status = EXIT_FAILURE;
|
---|
77 | free(backup);
|
---|
78 | continue;
|
---|
79 | }
|
---|
80 | free(backup);
|
---|
81 | /*
|
---|
82 | * When the source and dest are both hard links to the same
|
---|
83 | * inode, a rename may succeed even though nothing happened.
|
---|
84 | * Therefore, always unlink().
|
---|
85 | */
|
---|
86 | unlink(src);
|
---|
87 | } else if (opts & LN_FORCE) {
|
---|
88 | unlink(src);
|
---|
89 | }
|
---|
90 |
|
---|
91 | link_func = link;
|
---|
92 | if (opts & LN_SYMLINK) {
|
---|
93 | link_func = symlink;
|
---|
94 | }
|
---|
95 |
|
---|
96 | if (link_func(*argv, src) != 0) {
|
---|
97 | bb_simple_perror_msg(src);
|
---|
98 | status = EXIT_FAILURE;
|
---|
99 | }
|
---|
100 |
|
---|
101 | free(src_name);
|
---|
102 |
|
---|
103 | } while ((++argv)[1]);
|
---|
104 |
|
---|
105 | return status;
|
---|
106 | }
|
---|