bin/67308: ready to import bootstrap_cmds/relpath from Darwin
Cyrille Lefevre
cyrille.lefevre at laposte.net
Fri May 28 13:20:26 PDT 2004
>Number: 67308
>Category: bin
>Synopsis: ready to import bootstrap_cmds/relpath from Darwin
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Fri May 28 13:20:23 PDT 2004
>Closed-Date:
>Last-Modified:
>Originator: Cyrille Lefevre
>Release: FreeBSD 5.2-CURRENT i386
>Organization:
ACME
>Environment:
System: FreeBSD gits 5.2-CURRENT FreeBSD 5.2-CURRENT #28: Thu May 13 00:19:50 CEST 2004 root at gits:/disk3/freebsd/current/obj/disk3/freebsd/current/src/sys/CUSTOM i386
>Description:
Usage: relpath [-d DIR] START_PATH END_PATH
>How-To-Repeat:
$ relpath /usr/local/etc/rc.d /tmp
../../../../tmp
$ relpath -d /usr /usr/local/etc/rc.d /tmp
/tmp
>Fix:
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# usr.bin/relpath/Makefile
# usr.bin/relpath/relpath.c
#
echo x - usr.bin/relpath/Makefile
sed 's/^X//' >usr.bin/relpath/Makefile << 'END-of-usr.bin/relpath/Makefile'
X# $FreeBSD$
X
XPROG= relpath
XWARNS?= 6
XNO_MAN= yes
X
X.include <bsd.prog.mk>
END-of-usr.bin/relpath/Makefile
echo x - usr.bin/relpath/relpath.c
sed 's/^X//' >usr.bin/relpath/relpath.c << 'END-of-usr.bin/relpath/relpath.c'
X/*
X * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
X *
X * @APPLE_LICENSE_HEADER_START@
X *
X * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
X *
X * This file contains Original Code and/or Modifications of Original Code
X * as defined in and that are subject to the Apple Public Source License
X * Version 2.0 (the 'License'). You may not use this file except in
X * compliance with the License. Please obtain a copy of the License at
X * http://www.opensource.apple.com/apsl/ and read it before using this
X * file.
X *
X * The Original Code and all software distributed under the License are
X * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
X * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
X * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
X * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
X * Please see the License for the specific language governing rights and
X * limitations under the License.
X *
X * @APPLE_LICENSE_HEADER_END@
X */
X/*
X * relpath [-d DIR] START_DIR END_PATH
X *
X * Find a relative path from START_DIR to END_PATH.
X * Prints the relative path on standard out.
X *
X * If -d DIR, then only emit a relative path if both
X * START_DIR and END_PATH are sub-directories of DIR;
X * otherwise, emit an absolute path to END_PATH.
X */
X/*
X **********************************************************************
X * HISTORY
X * 27-May-04 Cyrille Lefevre for FreeBSD
X * Make it compile under FreeBSD. modifications are __FreeBSD__ #ifdef'ed.
X **********************************************************************
X */
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/param.h>
X#ifdef __FreeBSD__
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X#define symlink _symlink
X#else
X#include <strings.h>
X#include <libc.h>
X#endif
X
Xstatic int is_prefix(const char *path1, const char *path2);
Xstatic char *abspath(const char *opath, char *absbuf);
X
Xconst char *progname;
X
X#ifdef __FreeBSD__
Xint
X#else
Xvoid
X#endif
Xmain(int argc, const char * const *argv)
X{
X const char *arg;
X const char *base_dir = NULL;
X char start_path[MAXPATHLEN+1];
X char end_path[MAXPATHLEN+1];
X char base_path[MAXPATHLEN+1];
X struct stat st;
X int i;
X int last_elem;
X int prev_path;
X
X unsetenv("PWD");
X
X progname = (arg = rindex(*argv, '/')) != NULL ? arg + 1 : *argv;
X argc -= 1; argv += 1;
X
X for (; argc > 1 && **argv == '-'; argv += 1, argc -= 1) {
X
X arg = &(*argv)[1];
X do {
X switch (*arg) {
X case 'd':
X argc -= 1; argv += 1;
X if (argc <= 0) {
X fprintf(stderr, "%s: -d takes "
X "directory name\n", progname);
X exit(1);
X }
X base_dir = *argv;
X break;
X default:
X fprintf(stderr, "%s: Illegal flag: %c\n",
X progname, *arg);
X exit(1);
X }
X } while (*++arg);
X }
X if (argc < 2) {
X fprintf(stderr, "Usage: %s [-d DIR] START_PATH END_PATH\n",
X progname);
X exit(1);
X }
X (void) abspath(argv[0], start_path);
X (void) abspath(argv[1], end_path);
X if (base_dir) {
X (void) abspath(base_dir, base_path);
X if (!is_prefix(base_path, start_path) ||
X !is_prefix(base_path, end_path)) {
X printf("%s\n", end_path);
X exit(0);
X }
X if (stat(base_path, &st) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(base_path);
X exit(1);
X }
X if ((st.st_mode & S_IFMT) != S_IFDIR) {
X fprintf(stderr, "%s: -d DIR must be directory\n",
X progname);
X exit(1);
X }
X }
X if (stat(start_path, &st) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(start_path);
X exit(1);
X }
X if ((st.st_mode & S_IFMT) != S_IFDIR) {
X fprintf(stderr, "%s: START_PATH must be directory\n",
X progname);
X exit(1);
X }
X if (start_path[strlen(start_path) - 1] != '/')
X strcat(start_path, "/");
X
X if (stat(end_path, &st) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(end_path);
X exit(1);
X }
X if ((st.st_mode & S_IFMT) == S_IFDIR
X && end_path[strlen(end_path) - 1] != '/')
X strcat(end_path, "/");
X
X /* strip common prefix */
X i = 0;
X last_elem = 0;
X while (start_path[i] && start_path[i] == end_path[i]) {
X if (start_path[i] == '/')
X last_elem = i + 1;
X i += 1;
X }
X prev_path = 0;
X for (i = last_elem; start_path[i]; i += 1) {
X if (start_path[i] == '/') {
X if (prev_path)
X putchar('/');
X printf("%s", "..");
X prev_path = 1;
X }
X }
X if (end_path[last_elem]) {
X if (prev_path)
X putchar('/');
X prev_path = 1;
X while (end_path[strlen(end_path) - 1] == '/')
X end_path[strlen(end_path) - 1] = '\0';
X printf("%s", &end_path[last_elem]);
X }
X if (! prev_path)
X putchar('.');
X putchar('\n');
X#ifdef __FreeBSD__
X return(0);
X#else
X exit(0);
X#endif
X}
X
Xstatic int
Xis_prefix(const char *path1, const char *path2)
X{
X while (*path1 && *path1 == *path2) {
X path1 += 1;
X path2 += 1;
X }
X return (*path1 == '\0' && (*path2 == '/' || *path2 == '\0'));
X}
X
Xstatic char *
Xabspath(const char *opath, char *absbuf)
X{
X struct stat st;
X char curdir[MAXPATHLEN+1];
X char symlink[MAXPATHLEN+1];
X char path[MAXPATHLEN+1];
X char file[MAXPATHLEN+1];
X char *cp;
X int cc;
X
X strcpy(path, opath);
X /*
X * resolve last element of path until we know it's not
X * a symbolic link
X */
X while (lstat(path, &st) >= 0
X && (st.st_mode & S_IFMT) == S_IFLNK
X && (cc = readlink(path, symlink, sizeof(symlink)-1)) > 0) {
X symlink[cc] = '\0';
X if ((cp = rindex(path, '/')) != NULL && symlink[0] != '/')
X *++cp = '\0';
X else
X path[0] = '\0';
X strcat(path, symlink);
X }
X /*
X * We cheat a little bit here and let getwd() do the
X * dirty work of resolving everything before the last
X * element of the path
X */
X if (getwd(curdir) == NULL) {
X fprintf(stderr, "%s: %s\n", progname, curdir);
X exit(1);
X }
X if ((st.st_mode & S_IFMT) == S_IFDIR) {
X if (chdir(path) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(path);
X exit(1);
X }
X if (getwd(absbuf) == NULL) {
X fprintf(stderr, "%s: %s\n", progname, absbuf);
X exit(1);
X }
X if (chdir(curdir) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(path);
X exit(1);
X }
X return absbuf;
X }
X if ((cp = rindex(path, '/')) == NULL) {
X /*
X * last element of path is only element and it
X * now not a symbolic link, so we're done
X */
X strcpy(absbuf, curdir);
X if (absbuf[strlen(absbuf) - 1] != '/')
X strcat(absbuf, "/");
X return strcat(absbuf, path);
X }
X *cp++ = 0;
X strcpy(file, cp); /* save last element */
X
X if (chdir(path) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(path);
X exit(1);
X }
X if (getwd(absbuf) == NULL) {
X fprintf(stderr, "%s: %s\n", progname, absbuf);
X exit(1);
X }
X
X if (chdir(curdir) < 0) {
X fprintf(stderr, "%s: ", progname);
X perror(path);
X exit(1);
X }
X if (absbuf[strlen(absbuf)-1] != '/')
X strcat(absbuf, "/");
X return strcat(absbuf, file);
X}
END-of-usr.bin/relpath/relpath.c
exit
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list