/*
* Mini ln implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
/* BB_AUDIT SUSv3 compliant */
-/* BB_AUDIT GNU options missing: -b, -d, -F, -i, -S, and -v. */
+/* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
- *
- * Fixed bug involving -n option. Essentially, -n was always in effect.
- */
-
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <errno.h>
#include "busybox.h"
#define LN_SYMLINK 1
#define LN_FORCE 2
#define LN_NODEREFERENCE 4
+#define LN_BACKUP 8
+#define LN_SUFFIX 16
-extern int ln_main(int argc, char **argv)
+int ln_main(int argc, char **argv)
{
int status = EXIT_SUCCESS;
int flag;
char *last;
char *src_name;
char *src;
+ char *suffix = "~";
struct stat statbuf;
int (*link_func)(const char *, const char *);
- flag = bb_getopt_ulflags(argc, argv, "sfn");
+ flag = bb_getopt_ulflags(argc, argv, "sfnbS:", &suffix);
if (argc == optind) {
bb_show_usage();
free(src_name);
src_name = src;
}
-
- if (stat(*argv, &statbuf)) {
- bb_perror_msg(*argv);
+ if (!(flag & LN_SYMLINK) && stat(*argv, &statbuf)) {
+ bb_perror_msg("%s", *argv);
status = EXIT_FAILURE;
free(src_name);
continue;
}
- if (flag & LN_FORCE) {
+ if (flag & LN_BACKUP) {
+ char *backup;
+ backup = bb_xasprintf("%s%s", src, suffix);
+ if (rename(src, backup) < 0 && errno != ENOENT) {
+ bb_perror_msg("%s", src);
+ status = EXIT_FAILURE;
+ free(backup);
+ continue;
+ }
+ free(backup);
+ /*
+ * When the source and dest are both hard links to the same
+ * inode, a rename may succeed even though nothing happened.
+ * Therefore, always unlink().
+ */
+ unlink(src);
+ } else if (flag & LN_FORCE) {
unlink(src);
}
if (flag & LN_SYMLINK) {
link_func = symlink;
}
-
+
if (link_func(*argv, src) != 0) {
- bb_perror_msg(src);
+ bb_perror_msg("%s", src);
status = EXIT_FAILURE;
}
free(src_name);
-
+
} while ((++argv)[1]);
return status;
}
-
-
-
-
-
-
-
-
-
-