Hello, I have implemented two options for ln(1).
[Problem] The ln(1) makes a wrong symbolic link in some cases. (It is not a bug but a spec of ln(1).) For example: % cd /usr % ln -s src/bin /tmp/bin % cd /tmp/bin /tmp/bin: No such file or directory. % ls -l /tmp/bin lrwxrwxrwx 1 shigio wheel 7 Jan 10 22:10 /tmp/bin -> src/bin ~~~~~~~ It's wrong! [Solution] I have made a patch for ln(1) to make right symbolic links. New ln(1) has additional two options: -a(--absolute) If the -s option is specified, make absolute symbolic link. -r(--relative) If the -s option is specified, make relative symbolic link. The -a and -r options override each other; the last one specified determines the method used. New ln(1) with -r or -a option makes right symbolic link like this: % cd /usr % ln -sr src/bin /tmp/bin # relative symbolic link % cd /tmp/bin lrwxrwxrwx 1 shigio wheel 14 Jan 10 22:12 /tmp/bin -> ../usr/src/bin ~~~~~~~~~~~~~~ Right! or % cd /usr % ln -sa src/bin /tmp/bin # absolute symbolic link % cd /tmp/bin lrwxrwxrwx 1 shigio wheel 12 Jan 10 22:13 /tmp/bin -> /usr/src/bin ~~~~~~~~~~~~ Right! [Files] Here is a patch for fileutils-4.1.7. This patch calls two external functions: abs2rel() and rel2abs(). You can get the source code from http://www.tamacom.com/pathconvert/. If you include this patch, abs2rel and rel2abs into fileutils, I will transfer all of them to FSF and write a disclaimer paper for it. Thanks! /* * This file is placed into the public domain by the author, * Shigio Yamaguchi <[EMAIL PROTECTED]> */ diff -c -r -N fileutils-4.1.7-/man/ln.1 fileutils-4.1.7/man/ln.1 *** fileutils-4.1.7-/man/ln.1 Fri Mar 29 12:49:23 2002 --- fileutils-4.1.7/man/ln.1 Fri Mar 29 12:56:18 2002 *************** *** 20,28 **** --- 20,32 ---- than one TARGET, the last argument must be a directory; create links in DIRECTORY to each TARGET. Create hard links by default, symbolic links with \fB\-\-symbolic\fR. When creating hard links, each TARGET must exist. + The \fB\-\-absolute\fR and \fB\-\-relative\fR options override each other; the last +one specified determines .PP Mandatory arguments to long options are mandatory for short options too. .TP + \fB\-a\fR, \fB\-\-absolute\fR + If \fB\-\-symbolic\fR option is specified, make absolute symbolic link. + .TP \fB\-\-backup\fR[=\fICONTROL\fR] make a backup of each existing destination file .TP *************** *** 41,46 **** --- 45,53 ---- .TP \fB\-i\fR, \fB\-\-interactive\fR prompt whether to remove destinations + .TP + \fB\-r\fR, \fB\-\-relative\fR + If \fB\-\-symbolic\fR option is specified, make relative symbolic link. .TP \fB\-s\fR, \fB\-\-symbolic\fR make symbolic links instead of hard links diff -c -r -N fileutils-4.1.7-/src/ln.c fileutils-4.1.7/src/ln.c *** fileutils-4.1.7-/src/ln.c Fri Mar 29 12:49:21 2002 --- fileutils-4.1.7/src/ln.c Fri Mar 29 12:24:48 2002 *************** *** 119,131 **** --- 119,139 ---- symlink-to-dir before creating the new link. */ static int dereference_dest_dir_symlinks = 1; + /* If nonzero, make absolute symbolic links. */ + static int absolute = 0; + + /* If nonzero, make relative symbolic links. */ + static int relative = 0; + static struct option const long_options[] = { + {"absolute", no_argument, NULL, 'a'}, {"backup", optional_argument, NULL, 'b'}, {"directory", no_argument, NULL, 'F'}, {"no-dereference", no_argument, NULL, 'n'}, {"force", no_argument, NULL, 'f'}, {"interactive", no_argument, NULL, 'i'}, + {"relative", no_argument, NULL, 'r'}, {"suffix", required_argument, NULL, 'S'}, {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, {"symbolic", no_argument, NULL, 's'}, *************** *** 149,154 **** --- 157,165 ---- char *dest_backup = NULL; int lstat_status; int backup_succeeded = 0; + char base[PATH_MAX]; + char abssource[PATH_MAX]; + char relsource[PATH_MAX]; /* Use stat here instead of lstat. On SVR4, link does not follow symlinks, so this check disallows *************** *** 212,217 **** --- 223,264 ---- } } + /* If -a or -r option specified, do path conversion. */ + if (symbolic_link && (absolute || relative)) + { + /* convert source directory into absolute name */ + if (*source != '/') { + if (getcwd(base, PATH_MAX) == NULL) + error(1, errno, "couldn't get current directory."); + if (rel2abs(source, base, abssource, PATH_MAX) == NULL) + error(1, errno, "couldn't convert path"); + source = abssource; + } + /* convert source directory into relative name */ + if (relative) { + char path[PATH_MAX]; + const char *p; + + if (!S_ISDIR (dest_stats.st_mode)) { + if ((p = strrchr(dest, '/')) != NULL) { + int col = p - dest + 1; + strncpy(path, dest, col); + path[col] = 0; + } else { + path[0] = '.'; + path[1] = 0; + } + p = path; + } else + p = dest; + if (realpath(p, base) == NULL) + error(1, errno, p); + if (abs2rel(source, base, relsource, PATH_MAX) == NULL) + error(1, errno, "couldn't convert path"); + source = relsource; + } + } + /* If --force (-f) has been specified without --backup, then before making a link ln must remove the destination file if it exists. (with --backup, it just renames any existing destination file) *************** *** 355,360 **** --- 402,408 ---- Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); fputs (_("\ + -a, --absolute make absolute symbolic link\n\ --backup[=CONTROL] make a backup of each existing destination file\n\ -b like --backup but does not accept an argument\n\ -d, -F, --directory hard link directories (super-user only)\n\ *************** *** 363,368 **** --- 411,417 ---- fputs (_("\ -n, --no-dereference treat destination that is a symlink to a\n\ directory as if it were a normal file\n\ + -r, --relative make relative symbolic link\n\ -i, --interactive prompt whether to remove destinations\n\ -s, --symbolic make symbolic links instead of hard links\n\ "), stdout); *************** *** 421,427 **** = hard_dir_link = 0; errors = 0; ! while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL)) != -1) { switch (c) --- 470,476 ---- = hard_dir_link = 0; errors = 0; ! while ((c = getopt_long (argc, argv, "abdfinrsvFS:V:", long_options, NULL)) != -1) { switch (c) *************** *** 436,441 **** --- 485,493 ---- ), optarg); /* Fall through. */ + case 'a': + absolute = 1; + break; case 'b': make_backups = 1; if (optarg) *************** *** 455,460 **** --- 507,515 ---- break; case 'n': dereference_dest_dir_symlinks = 0; + break; + case 'r': + relative = 1; break; case 's': #ifdef S_ISLNK -- Shigio Yamaguchi - Tama Communications Corporation _______________________________________________ Bug-fileutils mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-fileutils