I recently had a need for the "-r" option to ln while using Busybox, and it
turned out to be easy enough to add, so here's a patch against v1.24.2.
This is the first time I've poked at the BB source so it's possible I
overlooked something helpful in libbb, or am not using approved style, or
whatever. Suggestions welcome!
Thanks,
R
--- busybox-1.24.2/coreutils/ln.c.orig 2016-06-18 07:56:12.821783032 -0700
+++ busybox-1.24.2/coreutils/ln.c 2016-06-18 07:58:34.309778849 -0700
@@ -18,6 +18,7 @@
//usage: "\n -s Make symlinks instead of hardlinks"
//usage: "\n -f Remove existing destinations"
//usage: "\n -n Don't dereference symlinks - treat like normal file"
+//usage: "\n -r Create symlinks relative to link location"
//usage: "\n -b Make a backup of the target (if exists) before link operation"
//usage: "\n -S suf Use suffix instead of ~ when making backup files"
//usage: "\n -T 2nd arg must be a DIR"
@@ -40,6 +41,74 @@
#define LN_SUFFIX (1 << 4)
#define LN_VERBOSE (1 << 5)
#define LN_LINKFILE (1 << 6)
+#define LN_RELATIVE (1 << 7)
+
+
+static int common_prefix_length(const char *path1, const char *path2)
+{
+ const char *start1 = path1;
+
+ /* NB: Function assumes absolute paths */
+
+ /* Find common string prefix */
+
+ while (*path1 && *path2 && *path1 == *path2) {
+ path1++;
+ path2++;
+ }
+
+ /* Search backwards to common path-component prefix */
+
+ while (path1 > start1 && *path1 != '/') {
+ path1--;
+ }
+
+ return (path1 + 1) - start1;
+}
+
+static char *xmalloc_relativized_target(const char *target, const char *src)
+{
+ const char *target_abs, *src_abs, *src_last, *sp;
+ char *out, *op;
+ int out_len, common_len;
+
+ /* Absolutize both inputs */
+
+ target_abs = bb_simplify_path(target);
+ src_abs = bb_simplify_path(src);
+
+ /* Output can't be longer than twice the longest absolutized input */
+
+ out_len = 1 + 2 * MAX(strlen(target_abs), strlen(src_abs));
+ out = op = xmalloc(out_len);
+
+ /* Skip common leading components */
+
+ common_len = common_prefix_length(target_abs, src_abs);
+ sp = src_abs + common_len;
+
+ /* Output "../" for each non-tail component remaining in src */
+
+ src_last = bb_get_last_path_component_nostrip(src_abs);
+ while (sp < src_last) {
+ if ('/' == *sp) {
+ *op++ = '.';
+ *op++ = '.';
+ *op++ = '/';
+ }
+ sp++;
+ }
+
+ /* Append target postfix */
+
+ strcpy(op, target_abs + common_len);
+
+ free((char *)target_abs);
+ free((char *)src_abs);
+
+ return out;
+}
+
int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int ln_main(int argc, char **argv)
@@ -49,12 +118,13 @@
char *last;
char *src_name;
char *src;
+ char *target;
char *suffix = (char*)"~";
struct stat statbuf;
int (*link_func)(const char *, const char *);
opt_complementary = "-1"; /* min one arg */
- opts = getopt32(argv, "sfnbS:vT", &suffix);
+ opts = getopt32(argv, "sfnbS:vTr", &suffix);
last = argv[argc - 1];
argv += optind;
@@ -120,19 +190,28 @@
}
link_func = link;
+ target = *argv;
if (opts & LN_SYMLINK) {
link_func = symlink;
+ if (opts & LN_RELATIVE) {
+ target = xmalloc_relativized_target(*argv, src);
+ }
}
if (opts & LN_VERBOSE) {
- printf("'%s' -> '%s'\n", src, *argv);
+ printf("'%s' -> '%s'\n", src, target);
}
- if (link_func(*argv, src) != 0) {
+ if (link_func(target, src) != 0) {
bb_simple_perror_msg(src);
status = EXIT_FAILURE;
}
+ if (target != *argv) {
+ free(target);
+ target = NULL;
+ }
+
free(src_name);
} while ((++argv)[1]);
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox