ln.c 2.6 KB

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