toybox/toys/posix/ln.c
<<
>>
Prefs
   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, "<1rt: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    -r  Create relative symlink from -> to
  22    -t  Create links in DIR
  23    -T  TO always treated as file, max 2 arguments
  24    -v  Verbose
  25*/
  26
  27#define FOR_ln
  28#include "toys.h"
  29
  30GLOBALS(
  31  char *t;
  32)
  33
  34void ln_main(void)
  35{
  36  char *dest = TT.t ? TT.t : toys.optargs[--toys.optc], *new;
  37  struct stat buf;
  38  int i, rc;
  39
  40  if (FLAG(T) && toys.optc>1) help_exit("Max 2 arguments");
  41
  42  // With one argument, create link in current directory.
  43  if (!toys.optc) {
  44    toys.optc++;
  45    dest = ".";
  46  }
  47
  48  // Is destination a directory?
  49  if (!((FLAG(n)||FLAG(T)) ? lstat : stat)(dest, &buf)) {
  50    if ((i = S_ISDIR(buf.st_mode)) ? FLAG(T) : (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    char *oldnew = 0, *try = toys.optargs[i];
  56
  57    if (S_ISDIR(buf.st_mode)) new = xmprintf("%s/%s", dest, basename(try));
  58    else new = dest;
  59
  60    if (FLAG(r)) {
  61      try = relative_path(new, try);
  62      if (!try) {
  63        if (new != dest) free(new);
  64        continue;
  65      }
  66      toys.optflags |= FLAG_s;
  67    }
  68
  69    // Force needs to unlink the existing target (if any). Do that by creating
  70    // a temp version and renaming it over the old one, so we can retain the
  71    // old file in cases we can't replace it (such as hardlink between mounts).
  72    oldnew = new;
  73    if (FLAG(f)) {
  74      new = xmprintf("%s_XXXXXX", new);
  75      rc = mkstemp(new);
  76      if (rc >= 0) {
  77        close(rc);
  78        if (unlink(new)) perror_msg("unlink '%s'", new);
  79      }
  80    }
  81
  82    rc = FLAG(s) ? symlink(try, new) : link(try, new);
  83    if (FLAG(f)) {
  84      if (!rc) {
  85        int temp;
  86
  87        rc = rename(new, oldnew);
  88        temp = errno;
  89        if (rc && unlink(new)) perror_msg("unlink '%s'", new);
  90        errno = temp;
  91      }
  92      free(new);
  93      new = oldnew;
  94    }
  95    if (rc) perror_msg("cannot create %s link from '%s' to '%s'",
  96                       FLAG(s) ? "symbolic" : "hard", try, new);
  97    else if (FLAG(v)) fprintf(stderr, "'%s' -> '%s'\n", new, try);
  98
  99    if (try != toys.optargs[i]) free(try);
 100    if (new != dest) free(new);
 101  }
 102}
 103