source: MondoRescue/branches/3.3/mindi-busybox/coreutils/ln.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 3.7 KB
Line 
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
44int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
45int 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 } while ((++argv)[1]);
138
139 return status;
140}
Note: See TracBrowser for help on using the repository browser.