1/* ln.c - Create filesystem links 2 * 3 * Copyright 2012 Andre Renaud <andre@bluewatersys.com> 4 * 5 * See http://opengroup.org/onlinepubs/9699919799/utilities/ln.html 6 7USE_LN(NEWTOY(ln, "<1t:Tvnfs", TOYFLAG_BIN)) 8 9config LN 10 bool "ln" 11 default y 12 help 13 usage: ln [-sfnv] [-t DIR] [FROM...] TO 14 15 Create a link between FROM and TO. 16 One/two/many arguments work like "mv" or "cp". 17 18 -s Create a symbolic link 19 -f Force the creation of the link, even if TO already exists 20 -n Symlink at TO treated as file 21 -t Create links in DIR 22 -T TO always treated as file, max 2 arguments 23 -v Verbose 24*/ 25 26#define FOR_ln 27#include "toys.h" 28 29GLOBALS( 30 char *t; 31) 32 33void ln_main(void) 34{ 35 char *dest = TT.t ? TT.t : toys.optargs[--toys.optc], *new; 36 struct stat buf; 37 int i; 38 39 // With one argument, create link in current directory. 40 if (!toys.optc) { 41 toys.optc++; 42 dest="."; 43 } 44 45 if (FLAG(T) && toys.optc>1) help_exit("Max 2 arguments"); 46 // Is destination a directory? 47 if (!((FLAG(n)||FLAG(T)) ? lstat : stat)(dest, &buf)) { 48 i = S_ISDIR(buf.st_mode); 49 50 if ((FLAG(T) && i) || (!i && (toys.optc>1 || TT.t))) 51 error_exit("'%s' %s a directory", dest, i ? "is" : "not"); 52 } else buf.st_mode = 0; 53 54 for (i=0; i<toys.optc; i++) { 55 int rc; 56 char *oldnew, *try = toys.optargs[i]; 57 58 if (S_ISDIR(buf.st_mode)) new = xmprintf("%s/%s", dest, basename(try)); 59 else new = dest; 60 61 // Force needs to unlink the existing target (if any). Do that by creating 62 // a temp version and renaming it over the old one, so we can retain the 63 // old file in cases we can't replace it (such as hardlink between mounts). 64 oldnew = new; 65 if (FLAG(f)) { 66 new = xmprintf("%s_XXXXXX", new); 67 rc = mkstemp(new); 68 if (rc >= 0) { 69 close(rc); 70 if (unlink(new)) perror_msg("unlink '%s'", new); 71 } 72 } 73 74 rc = FLAG(s) ? symlink(try, new) : link(try, new); 75 if (FLAG(f)) { 76 if (!rc) { 77 int temp; 78 79 rc = rename(new, oldnew); 80 temp = errno; 81 if (rc && unlink(new)) perror_msg("unlink '%s'", new); 82 errno = temp; 83 } 84 free(new); 85 new = oldnew; 86 } 87 if (rc) perror_msg("cannot create %s link from '%s' to '%s'", 88 FLAG(s) ? "symbolic" : "hard", try, new); 89 else if (FLAG(v)) fprintf(stderr, "'%s' -> '%s'\n", new, try); 90 91 if (new != dest) free(new); 92 } 93} 94