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); 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(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(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_perror_msg("%s", *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_perror_msg("%s", 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_perror_msg("%s", src); 101 status = EXIT_FAILURE; 102 } 103 104 free(src_name); 105 106 } while ((++argv)[1]); 107 108 return status; 109} 110