Blame config/util/lndir.c

Packit b099d7
/* $TOG: lndir.c /main/17 1998/02/06 11:23:50 kaleb $ */
Packit b099d7
/* Create shadow link tree (after X11R4 script of the same name)
Packit b099d7
   Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */
Packit b099d7
Packit b099d7
/* 
Packit b099d7
Packit b099d7
 * Motif
Packit b099d7
 *
Packit b099d7
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are free software; you can
Packit b099d7
 * redistribute them and/or modify them under the terms of the GNU
Packit b099d7
 * Lesser General Public License as published by the Free Software
Packit b099d7
 * Foundation; either version 2 of the License, or (at your option)
Packit b099d7
 * any later version.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are distributed in the hope that
Packit b099d7
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
Packit b099d7
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Packit b099d7
 * PURPOSE. See the GNU Lesser General Public License for more
Packit b099d7
 * details.
Packit b099d7
 *
Packit b099d7
 * You should have received a copy of the GNU Lesser General Public
Packit b099d7
 * License along with these librararies and programs; if not, write
Packit b099d7
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
Packit b099d7
 * Floor, Boston, MA 02110-1301 USA
Packit b099d7
Packit b099d7
*/
Packit b099d7
Packit b099d7
#ifdef HAVE_CONFIG_H
Packit b099d7
#include <config.h>
Packit b099d7
#endif
Packit b099d7
Packit b099d7
Packit b099d7
/* From the original /bin/sh script:
Packit b099d7
Packit b099d7
  Used to create a copy of the a directory tree that has links for all
Packit b099d7
  non-directories (except those named RCS, SCCS or CVS.adm).  If you are
Packit b099d7
  building the distribution on more than one machine, you should use
Packit b099d7
  this technique.
Packit b099d7
Packit b099d7
  If your master sources are located in /usr/local/src/X and you would like
Packit b099d7
  your link tree to be in /usr/local/src/new-X, do the following:
Packit b099d7
Packit b099d7
   	%  mkdir /usr/local/src/new-X
Packit b099d7
	%  cd /usr/local/src/new-X
Packit b099d7
   	%  lndir ../X
Packit b099d7
*/
Packit b099d7
Packit b099d7
#include <X11/Xos.h>
Packit b099d7
#include <X11/Xfuncproto.h>
Packit b099d7
#include <stdio.h>
Packit b099d7
#include <sys/stat.h>
Packit b099d7
#include <sys/param.h>
Packit b099d7
#include <errno.h>
Packit b099d7
Packit b099d7
#ifndef X_NOT_POSIX
Packit b099d7
#include <dirent.h>
Packit b099d7
#else
Packit b099d7
#ifdef SYSV
Packit b099d7
#include <dirent.h>
Packit b099d7
#else
Packit b099d7
#ifdef USG
Packit b099d7
#include <dirent.h>
Packit b099d7
#else
Packit b099d7
#include <sys/dir.h>
Packit b099d7
#ifndef dirent
Packit b099d7
#define dirent direct
Packit b099d7
#endif
Packit b099d7
#endif
Packit b099d7
#endif
Packit b099d7
#endif
Packit b099d7
#ifndef MAXPATHLEN
Packit b099d7
#define MAXPATHLEN 2048
Packit b099d7
#endif
Packit b099d7
Packit b099d7
#if NeedVarargsPrototypes
Packit b099d7
#include <stdarg.h>
Packit b099d7
#endif
Packit b099d7
Packit b099d7
#ifdef X_NOT_STDC_ENV
Packit b099d7
extern int errno;
Packit b099d7
#endif
Packit b099d7
int silent = 0;			/* -silent */
Packit b099d7
int ignore_links = 0;		/* -ignorelinks */
Packit b099d7
Packit b099d7
char *rcurdir;
Packit b099d7
char *curdir;
Packit b099d7
Packit b099d7
void
Packit b099d7
quit (
Packit b099d7
#if NeedVarargsPrototypes
Packit b099d7
    int code, char * fmt, ...)
Packit b099d7
#else
Packit b099d7
    code, fmt, a1, a2, a3)
Packit b099d7
    char *fmt;
Packit b099d7
#endif
Packit b099d7
{
Packit b099d7
#if NeedVarargsPrototypes
Packit b099d7
    va_list args;
Packit b099d7
    va_start(args, fmt);
Packit b099d7
    vfprintf (stderr, fmt, args);
Packit b099d7
    va_end(args);
Packit b099d7
#else
Packit b099d7
    fprintf (stderr, fmt, a1, a2, a3);
Packit b099d7
#endif
Packit b099d7
    putc ('\n', stderr);
Packit b099d7
    exit (code);
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
quiterr (code, s)
Packit b099d7
    char *s;
Packit b099d7
{
Packit b099d7
    perror (s);
Packit b099d7
    exit (code);
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
msg (
Packit b099d7
#if NeedVarargsPrototypes
Packit b099d7
    char * fmt, ...)
Packit b099d7
#else
Packit b099d7
    fmt, a1, a2, a3)
Packit b099d7
    char *fmt;
Packit b099d7
#endif
Packit b099d7
{
Packit b099d7
#if NeedVarargsPrototypes
Packit b099d7
    va_list args;
Packit b099d7
#endif
Packit b099d7
    if (curdir) {
Packit b099d7
	fprintf (stderr, "%s:\n", curdir);
Packit b099d7
	curdir = 0;
Packit b099d7
    }
Packit b099d7
#if NeedVarargsPrototypes
Packit b099d7
    va_start(args, fmt);
Packit b099d7
    vfprintf (stderr, fmt, args);
Packit b099d7
    va_end(args);
Packit b099d7
#else
Packit b099d7
    fprintf (stderr, fmt, a1, a2, a3);
Packit b099d7
#endif
Packit b099d7
    putc ('\n', stderr);
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
mperror (s)
Packit b099d7
    char *s;
Packit b099d7
{
Packit b099d7
    if (curdir) {
Packit b099d7
	fprintf (stderr, "%s:\n", curdir);
Packit b099d7
	curdir = 0;
Packit b099d7
    }
Packit b099d7
    perror (s);
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7
int equivalent(lname, rname)
Packit b099d7
    char *lname;
Packit b099d7
    char *rname;
Packit b099d7
{
Packit b099d7
    char *s;
Packit b099d7
Packit b099d7
    if (!strcmp(lname, rname))
Packit b099d7
	return 1;
Packit b099d7
    for (s = lname; *s && (s = strchr(s, '/')); s++) {
Packit b099d7
	while (s[1] == '/')
Packit b099d7
	    strcpy(s+1, s+2);
Packit b099d7
    }
Packit b099d7
    return !strcmp(lname, rname);
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7
/* Recursively create symbolic links from the current directory to the "from"
Packit b099d7
   directory.  Assumes that files described by fs and ts are directories. */
Packit b099d7
Packit b099d7
dodir (fn, fs, ts, rel)
Packit b099d7
char *fn;			/* name of "from" directory, either absolute or
Packit b099d7
				   relative to cwd */
Packit b099d7
struct stat *fs, *ts;		/* stats for the "from" directory and cwd */
Packit b099d7
int rel;			/* if true, prepend "../" to fn before using */
Packit b099d7
{
Packit b099d7
    DIR *df;
Packit b099d7
    struct dirent *dp;
Packit b099d7
    char buf[MAXPATHLEN + 1], *p;
Packit b099d7
    char symbuf[MAXPATHLEN + 1];
Packit b099d7
    char basesym[MAXPATHLEN + 1];
Packit b099d7
    struct stat sb, sc;
Packit b099d7
    int n_dirs;
Packit b099d7
    int symlen;
Packit b099d7
    int basesymlen = -1;
Packit b099d7
    char *ocurdir;
Packit b099d7
Packit b099d7
    if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
Packit b099d7
	msg ("%s: From and to directories are identical!", fn);
Packit b099d7
	return 1;
Packit b099d7
    }
Packit b099d7
Packit b099d7
    if (rel)
Packit b099d7
	strcpy (buf, "../");
Packit b099d7
    else
Packit b099d7
	buf[0] = '\0';
Packit b099d7
    strcat (buf, fn);
Packit b099d7
    
Packit b099d7
    if (!(df = opendir (buf))) {
Packit b099d7
	msg ("%s: Cannot opendir", buf);
Packit b099d7
	return 1;
Packit b099d7
    }
Packit b099d7
Packit b099d7
    p = buf + strlen (buf);
Packit b099d7
    *p++ = '/';
Packit b099d7
    n_dirs = fs->st_nlink;
Packit b099d7
    while (dp = readdir (df)) {
Packit b099d7
	if (dp->d_name[strlen(dp->d_name) - 1] == '~')
Packit b099d7
	    continue;
Packit b099d7
	strcpy (p, dp->d_name);
Packit b099d7
Packit b099d7
	if (n_dirs > 0) {
Packit b099d7
	    if (stat (buf, &sb) < 0) {
Packit b099d7
		mperror (buf);
Packit b099d7
		continue;
Packit b099d7
	    }
Packit b099d7
Packit b099d7
#ifdef S_ISDIR
Packit b099d7
	    if(S_ISDIR(sb.st_mode))
Packit b099d7
#else
Packit b099d7
	    if (sb.st_mode & S_IFDIR) 
Packit b099d7
#endif
Packit b099d7
	    {
Packit b099d7
		/* directory */
Packit b099d7
		n_dirs--;
Packit b099d7
		if (dp->d_name[0] == '.' &&
Packit b099d7
		    (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
Packit b099d7
					       dp->d_name[2] == '\0')))
Packit b099d7
		    continue;
Packit b099d7
		if (!strcmp (dp->d_name, "RCS"))
Packit b099d7
		    continue;
Packit b099d7
		if (!strcmp (dp->d_name, "SCCS"))
Packit b099d7
		    continue;
Packit b099d7
		if (!strcmp (dp->d_name, "CVS"))
Packit b099d7
		    continue;
Packit b099d7
		if (!strcmp (dp->d_name, "CVS.adm"))
Packit b099d7
		    continue;
Packit b099d7
		ocurdir = rcurdir;
Packit b099d7
		rcurdir = buf;
Packit b099d7
		curdir = silent ? buf : (char *)0;
Packit b099d7
		if (!silent)
Packit b099d7
		    printf ("%s:\n", buf);
Packit b099d7
		if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
Packit b099d7
		    if (mkdir (dp->d_name, 0777) < 0 ||
Packit b099d7
			stat (dp->d_name, &sc) < 0) {
Packit b099d7
			mperror (dp->d_name);
Packit b099d7
			curdir = rcurdir = ocurdir;
Packit b099d7
			continue;
Packit b099d7
		    }
Packit b099d7
		}
Packit b099d7
		if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
Packit b099d7
		    msg ("%s: is a link instead of a directory", dp->d_name);
Packit b099d7
		    curdir = rcurdir = ocurdir;
Packit b099d7
		    continue;
Packit b099d7
		}
Packit b099d7
		if (chdir (dp->d_name) < 0) {
Packit b099d7
		    mperror (dp->d_name);
Packit b099d7
		    curdir = rcurdir = ocurdir;
Packit b099d7
		    continue;
Packit b099d7
		}
Packit b099d7
		dodir (buf, &sb, &sc, (buf[0] != '/'));
Packit b099d7
		if (chdir ("..") < 0)
Packit b099d7
		    quiterr (1, "..");
Packit b099d7
		curdir = rcurdir = ocurdir;
Packit b099d7
		continue;
Packit b099d7
	    }
Packit b099d7
	}
Packit b099d7
Packit b099d7
	/* non-directory */
Packit b099d7
	symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
Packit b099d7
	if (symlen >= 0)
Packit b099d7
	    symbuf[symlen] = '\0';
Packit b099d7
Packit b099d7
	/* The option to ignore links exists mostly because
Packit b099d7
	   checking for them slows us down by 10-20%.
Packit b099d7
	   But it is off by default because this really is a useful check. */
Packit b099d7
	if (!ignore_links) {
Packit b099d7
	    /* see if the file in the base tree was a symlink */
Packit b099d7
	    basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
Packit b099d7
	    if (basesymlen >= 0)
Packit b099d7
		basesym[basesymlen] = '\0';
Packit b099d7
	}
Packit b099d7
Packit b099d7
	if (symlen >= 0) {
Packit b099d7
	    /* Link exists in new tree.  Print message if it doesn't match. */
Packit b099d7
	    if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf))
Packit b099d7
		msg ("%s: %s", dp->d_name, symbuf);
Packit b099d7
	} else {
Packit b099d7
	    if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
Packit b099d7
		mperror (dp->d_name);
Packit b099d7
	}
Packit b099d7
    }
Packit b099d7
Packit b099d7
    closedir (df);
Packit b099d7
    return 0;
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7
main (ac, av)
Packit b099d7
int ac;
Packit b099d7
char **av;
Packit b099d7
{
Packit b099d7
    char *prog_name = av[0];
Packit b099d7
    char *fn, *tn;
Packit b099d7
    struct stat fs, ts;
Packit b099d7
Packit b099d7
    while (++av, --ac) {
Packit b099d7
	if (strcmp(*av, "-silent") == 0)
Packit b099d7
	    silent = 1;
Packit b099d7
	else if (strcmp(*av, "-ignorelinks") == 0)
Packit b099d7
	    ignore_links = 1;
Packit b099d7
	else if (strcmp(*av, "--") == 0) {
Packit b099d7
	    ++av, --ac;
Packit b099d7
	    break;
Packit b099d7
	}
Packit b099d7
	else
Packit b099d7
	    break;
Packit b099d7
    }
Packit b099d7
Packit b099d7
    if (ac < 1 || ac > 2)
Packit b099d7
	quit (1, "usage: %s [-silent] [-ignorelinks] fromdir [todir]",
Packit b099d7
	      prog_name);
Packit b099d7
Packit b099d7
    fn = av[0];
Packit b099d7
    if (ac == 2)
Packit b099d7
	tn = av[1];
Packit b099d7
    else
Packit b099d7
	tn = ".";
Packit b099d7
Packit b099d7
    /* to directory */
Packit b099d7
    if (stat (tn, &ts) < 0)
Packit b099d7
	quiterr (1, tn);
Packit b099d7
#ifdef S_ISDIR
Packit b099d7
    if (!(S_ISDIR(ts.st_mode)))
Packit b099d7
#else
Packit b099d7
    if (!(ts.st_mode & S_IFDIR))
Packit b099d7
#endif
Packit b099d7
	quit (2, "%s: Not a directory", tn);
Packit b099d7
    if (chdir (tn) < 0)
Packit b099d7
	quiterr (1, tn);
Packit b099d7
Packit b099d7
    /* from directory */
Packit b099d7
    if (stat (fn, &fs) < 0)
Packit b099d7
	quiterr (1, fn);
Packit b099d7
#ifdef S_ISDIR
Packit b099d7
    if (!(S_ISDIR(fs.st_mode)))
Packit b099d7
#else
Packit b099d7
    if (!(fs.st_mode & S_IFDIR))
Packit b099d7
#endif
Packit b099d7
	quit (2, "%s: Not a directory", fn);
Packit b099d7
Packit b099d7
    exit (dodir (fn, &fs, &ts, 0));
Packit b099d7
}