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