*: make GNU licensing statement forms more regular
[oweals/busybox.git] / coreutils / ln.c
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 }