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//config:config LN 10//config: bool "ln (4.9 kb)" 11//config: default y 12//config: help 13//config: ln is used to create hard or soft links between files. 14 15//applet:IF_LN(APPLET_NOEXEC(ln, ln, BB_DIR_BIN, BB_SUID_DROP, ln)) 16 17//kbuild:lib-$(CONFIG_LN) += ln.o 18 19/* BB_AUDIT SUSv3 compliant */ 20/* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */ 21/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */ 22 23//usage:#define ln_trivial_usage 24//usage: "[-sfnbtv] [-S SUF] TARGET... LINK|DIR" 25//usage:#define ln_full_usage "\n\n" 26//usage: "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" 27//usage: "\n -s Make symlinks instead of hardlinks" 28//usage: "\n -f Remove existing destinations" 29//usage: "\n -n Don't dereference symlinks - treat like normal file" 30//usage: "\n -b Make a backup of the target (if exists) before link operation" 31//usage: "\n -S SUF Use suffix instead of ~ when making backup files" 32//usage: "\n -T Treat LINK as a file, not DIR" 33//usage: "\n -v Verbose" 34//usage: 35//usage:#define ln_example_usage 36//usage: "$ ln -s BusyBox /tmp/ls\n" 37//usage: "$ ls -l /tmp/ls\n" 38//usage: "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" 39 40#include "libbb.h" 41 42/* This is a NOEXEC applet. Be very careful! */ 43 44#define LN_SYMLINK (1 << 0) 45#define LN_FORCE (1 << 1) 46#define LN_NODEREFERENCE (1 << 2) 47#define LN_BACKUP (1 << 3) 48#define LN_SUFFIX (1 << 4) 49#define LN_VERBOSE (1 << 5) 50#define LN_LINKFILE (1 << 6) 51 52int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 53int ln_main(int argc, char **argv) 54{ 55 int status = EXIT_SUCCESS; 56 int opts; 57 char *last; 58 char *src_name; 59 char *src; 60 char *suffix = (char*)"~"; 61 struct stat statbuf; 62 int (*link_func)(const char *, const char *); 63 64 opts = getopt32(argv, "^" "sfnbS:vT" "\0" "-1", &suffix); 65/* 66 -s, --symbolic make symbolic links instead of hard links 67 -f, --force remove existing destination files 68 -n, --no-dereference treat LINK_NAME as a normal file if it is a symbolic link to a directory 69 -b like --backup but does not accept an argument 70 --backup[=CONTROL] make a backup of each existing destination file 71 -S, --suffix=SUFFIX override the usual backup suffix 72 -v, --verbose 73 -T, --no-target-directory 74 -d, -F, --directory allow the superuser to attempt to hard link directories 75 -i, --interactive prompt whether to remove destinations 76 -L, --logical dereference TARGETs that are symbolic links 77 -P, --physical make hard links directly to symbolic links 78 -r, --relative create symbolic links relative to link location 79 -t, --target-directory=DIRECTORY specify the DIRECTORY in which to create the links 80 */ 81 last = argv[argc - 1]; 82 argv += optind; 83 argc -= optind; 84 85 if ((opts & LN_LINKFILE) && argc > 2) { 86 bb_simple_error_msg_and_die("-T accepts 2 args max"); 87 } 88 89 if (!argv[1]) { 90 /* "ln PATH/TO/FILE" -> "ln PATH/TO/FILE FILE" */ 91 *--argv = last; 92 /* xstrdup is needed: "ln -s PATH/TO/FILE/" is equivalent to 93 * "ln -s PATH/TO/FILE/ FILE", not "ln -s PATH/TO/FILE FILE" 94 */ 95 last = bb_get_last_path_component_strip(xstrdup(last)); 96 } 97 98 do { 99 src_name = NULL; 100 src = last; 101 102 if (is_directory(src, 103 /*followlinks:*/ !(opts & (LN_NODEREFERENCE|LN_LINKFILE)) 104 /* Why LN_LINKFILE does not follow links: 105 * -T/--no-target-directory implies -n/--no-dereference 106 */ 107 ) 108 ) { 109 if (opts & LN_LINKFILE) { 110 bb_error_msg_and_die("'%s' is a directory", src); 111 } 112 src_name = xstrdup(*argv); 113 src = concat_path_file(src, bb_get_last_path_component_strip(src_name)); 114 free(src_name); 115 src_name = src; 116 } 117 if (!(opts & LN_SYMLINK) && stat(*argv, &statbuf)) { 118 // coreutils: "ln dangling_symlink new_hardlink" works 119 if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) { 120 bb_simple_perror_msg(*argv); 121 status = EXIT_FAILURE; 122 free(src_name); 123 continue; 124 } 125 } 126 127 if (opts & LN_BACKUP) { 128 char *backup; 129 backup = xasprintf("%s%s", src, suffix); 130 if (rename(src, backup) < 0 && errno != ENOENT) { 131 bb_simple_perror_msg(src); 132 status = EXIT_FAILURE; 133 free(backup); 134 continue; 135 } 136 free(backup); 137 /* 138 * When the source and dest are both hard links to the same 139 * inode, a rename may succeed even though nothing happened. 140 * Therefore, always unlink(). 141 */ 142 unlink(src); 143 } else if (opts & LN_FORCE) { 144 unlink(src); 145 } 146 147 link_func = link; 148 if (opts & LN_SYMLINK) { 149 link_func = symlink; 150 } 151 152 if (opts & LN_VERBOSE) { 153 printf("'%s' -> '%s'\n", src, *argv); 154 } 155 156 if (link_func(*argv, src) != 0) { 157 bb_simple_perror_msg(src); 158 status = EXIT_FAILURE; 159 } 160 161 free(src_name); 162 } while ((++argv)[1]); 163 164 return status; 165} 166