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