busybox/coreutils/ln.c
<<
>>
Prefs
   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 tarball for details.
   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
  25int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  26int ln_main(int argc, char **argv)
  27{
  28        int status = EXIT_SUCCESS;
  29        int flag;
  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        flag = getopt32(argv, "sfnbS:", &suffix);
  38
  39        if (argc == optind) {
  40                bb_show_usage();
  41        }
  42
  43        last = argv[argc - 1];
  44        argv += optind;
  45
  46        if (argc == optind + 1) {
  47                *--argv = last;
  48                last = bb_get_last_path_component_strip(xstrdup(last));
  49        }
  50
  51        do {
  52                src_name = NULL;
  53                src = last;
  54
  55                if (is_directory(src,
  56                                (flag & LN_NODEREFERENCE) ^ LN_NODEREFERENCE,
  57                                NULL)
  58                ) {
  59                        src_name = xstrdup(*argv);
  60                        src = concat_path_file(src, bb_get_last_path_component_strip(src_name));
  61                        free(src_name);
  62                        src_name = src;
  63                }
  64                if (!(flag & LN_SYMLINK) && stat(*argv, &statbuf)) {
  65                        // coreutils: "ln dangling_symlink new_hardlink" works
  66                        if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) {
  67                                bb_simple_perror_msg(*argv);
  68                                status = EXIT_FAILURE;
  69                                free(src_name);
  70                                continue;
  71                        }
  72                }
  73
  74                if (flag & LN_BACKUP) {
  75                        char *backup;
  76                        backup = xasprintf("%s%s", src, suffix);
  77                        if (rename(src, backup) < 0 && errno != ENOENT) {
  78                                bb_simple_perror_msg(src);
  79                                status = EXIT_FAILURE;
  80                                free(backup);
  81                                continue;
  82                        }
  83                        free(backup);
  84                        /*
  85                         * When the source and dest are both hard links to the same
  86                         * inode, a rename may succeed even though nothing happened.
  87                         * Therefore, always unlink().
  88                         */
  89                        unlink(src);
  90                } else if (flag & LN_FORCE) {
  91                        unlink(src);
  92                }
  93
  94                link_func = link;
  95                if (flag & LN_SYMLINK) {
  96                        link_func = symlink;
  97                }
  98
  99                if (link_func(*argv, src) != 0) {
 100                        bb_simple_perror_msg(src);
 101                        status = EXIT_FAILURE;
 102                }
 103
 104                free(src_name);
 105
 106        } while ((++argv)[1]);
 107
 108        return status;
 109}
 110