xref: /third_party/toybox/toys/posix/ln.c (revision 0f66f451)
10f66f451Sopenharmony_ci/* ln.c - Create filesystem links
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * See http://opengroup.org/onlinepubs/9699919799/utilities/ln.html
60f66f451Sopenharmony_ci
70f66f451Sopenharmony_ciUSE_LN(NEWTOY(ln, "<1t:Tvnfs", TOYFLAG_BIN))
80f66f451Sopenharmony_ci
90f66f451Sopenharmony_ciconfig LN
100f66f451Sopenharmony_ci  bool "ln"
110f66f451Sopenharmony_ci  default y
120f66f451Sopenharmony_ci  help
130f66f451Sopenharmony_ci    usage: ln [-sfnv] [-t DIR] [FROM...] TO
140f66f451Sopenharmony_ci
150f66f451Sopenharmony_ci    Create a link between FROM and TO.
160f66f451Sopenharmony_ci    One/two/many arguments work like "mv" or "cp".
170f66f451Sopenharmony_ci
180f66f451Sopenharmony_ci    -s	Create a symbolic link
190f66f451Sopenharmony_ci    -f	Force the creation of the link, even if TO already exists
200f66f451Sopenharmony_ci    -n	Symlink at TO treated as file
210f66f451Sopenharmony_ci    -t	Create links in DIR
220f66f451Sopenharmony_ci    -T	TO always treated as file, max 2 arguments
230f66f451Sopenharmony_ci    -v	Verbose
240f66f451Sopenharmony_ci*/
250f66f451Sopenharmony_ci
260f66f451Sopenharmony_ci#define FOR_ln
270f66f451Sopenharmony_ci#include "toys.h"
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ciGLOBALS(
300f66f451Sopenharmony_ci  char *t;
310f66f451Sopenharmony_ci)
320f66f451Sopenharmony_ci
330f66f451Sopenharmony_civoid ln_main(void)
340f66f451Sopenharmony_ci{
350f66f451Sopenharmony_ci  char *dest = TT.t ? TT.t : toys.optargs[--toys.optc], *new;
360f66f451Sopenharmony_ci  struct stat buf;
370f66f451Sopenharmony_ci  int i;
380f66f451Sopenharmony_ci
390f66f451Sopenharmony_ci  // With one argument, create link in current directory.
400f66f451Sopenharmony_ci  if (!toys.optc) {
410f66f451Sopenharmony_ci    toys.optc++;
420f66f451Sopenharmony_ci    dest=".";
430f66f451Sopenharmony_ci  }
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_ci  if (FLAG(T) && toys.optc>1) help_exit("Max 2 arguments");
460f66f451Sopenharmony_ci  // Is destination a directory?
470f66f451Sopenharmony_ci  if (!((FLAG(n)||FLAG(T)) ? lstat : stat)(dest, &buf)) {
480f66f451Sopenharmony_ci    i = S_ISDIR(buf.st_mode);
490f66f451Sopenharmony_ci
500f66f451Sopenharmony_ci    if ((FLAG(T) && i) || (!i && (toys.optc>1 || TT.t)))
510f66f451Sopenharmony_ci      error_exit("'%s' %s a directory", dest, i ? "is" : "not");
520f66f451Sopenharmony_ci  } else buf.st_mode = 0;
530f66f451Sopenharmony_ci
540f66f451Sopenharmony_ci  for (i=0; i<toys.optc; i++) {
550f66f451Sopenharmony_ci    int rc;
560f66f451Sopenharmony_ci    char *oldnew, *try = toys.optargs[i];
570f66f451Sopenharmony_ci
580f66f451Sopenharmony_ci    if (S_ISDIR(buf.st_mode)) new = xmprintf("%s/%s", dest, basename(try));
590f66f451Sopenharmony_ci    else new = dest;
600f66f451Sopenharmony_ci
610f66f451Sopenharmony_ci    // Force needs to unlink the existing target (if any). Do that by creating
620f66f451Sopenharmony_ci    // a temp version and renaming it over the old one, so we can retain the
630f66f451Sopenharmony_ci    // old file in cases we can't replace it (such as hardlink between mounts).
640f66f451Sopenharmony_ci    oldnew = new;
650f66f451Sopenharmony_ci    if (FLAG(f)) {
660f66f451Sopenharmony_ci      new = xmprintf("%s_XXXXXX", new);
670f66f451Sopenharmony_ci      rc = mkstemp(new);
680f66f451Sopenharmony_ci      if (rc >= 0) {
690f66f451Sopenharmony_ci        close(rc);
700f66f451Sopenharmony_ci        if (unlink(new)) perror_msg("unlink '%s'", new);
710f66f451Sopenharmony_ci      }
720f66f451Sopenharmony_ci    }
730f66f451Sopenharmony_ci
740f66f451Sopenharmony_ci    rc = FLAG(s) ? symlink(try, new) : link(try, new);
750f66f451Sopenharmony_ci    if (FLAG(f)) {
760f66f451Sopenharmony_ci      if (!rc) {
770f66f451Sopenharmony_ci        int temp;
780f66f451Sopenharmony_ci
790f66f451Sopenharmony_ci        rc = rename(new, oldnew);
800f66f451Sopenharmony_ci        temp = errno;
810f66f451Sopenharmony_ci        if (rc && unlink(new)) perror_msg("unlink '%s'", new);
820f66f451Sopenharmony_ci        errno = temp;
830f66f451Sopenharmony_ci      }
840f66f451Sopenharmony_ci      free(new);
850f66f451Sopenharmony_ci      new = oldnew;
860f66f451Sopenharmony_ci    }
870f66f451Sopenharmony_ci    if (rc) perror_msg("cannot create %s link from '%s' to '%s'",
880f66f451Sopenharmony_ci                       FLAG(s) ? "symbolic" : "hard", try, new);
890f66f451Sopenharmony_ci    else if (FLAG(v)) fprintf(stderr, "'%s' -> '%s'\n", new, try);
900f66f451Sopenharmony_ci
910f66f451Sopenharmony_ci    if (new != dest) free(new);
920f66f451Sopenharmony_ci  }
930f66f451Sopenharmony_ci}
94