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