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 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} 107