~tom-gall/linaro/busybox

« back to all changes in this revision

Viewing changes to coreutils/ln.c

  • Committer: Tom Gall
  • Date: 2011-03-01 21:57:28 UTC
  • Revision ID: tom.gall@linaro.org-20110301215728-1anly2d6ewgcwwnl
initial import based on busybox 1.18.3 release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}