4.4BSD/usr/src/contrib/mkmf/src/mksymlink.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1991 Peter J. Nicklin.
 * Copyright (c) 1991 Version Technology.
 * All Rights Reserved.
 *
 * $License: VT.1.1 $
 * Redistribution and use in source and binary forms,  with or without
 * modification,  are permitted provided that the following conditions
 * are met:  (1) Redistributions of source code must retain the  above
 * copyright  notice,  this  list  of  conditions  and  the  following
 * disclaimer.  (2) Redistributions in binary form must reproduce  the
 * above  copyright notice,  this list of conditions and the following
 * disclaimer in the  documentation  and/or other  materials  provided
 * with  the  distribution.  (3) All advertising materials  mentioning
 * features or  use  of  this  software  must  display  the  following
 * acknowledgement:  ``This  product  includes  software  developed by
 * Version Technology.''  Neither the name of Version  Technology  nor
 * the  name  of  Peter J. Nicklin  may  be used to endorse or promote
 * products derived from this software without specific prior  written
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY VERSION TECHNOLOGY ``AS IS''  AND  ANY
 * EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO, THE
 * IMPLIED  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL  VERSION  TECHNOLOGY  BE
 * LIABLE  FOR ANY DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR  CONSEQUENTIAL DAMAGES   (INCLUDING,   BUT   NOT   LIMITED   TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT LIABILITY,  OR  TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING  IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE,  EVEN  IF  ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * Report problems and direct questions to nicklin@netcom.com
 *
 * $Header: mksymlink.c,v 4.10 91/11/25 19:44:59 nicklin Exp $
 *
 * Author: Peter J. Nicklin
 */
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "Mkmf.h"
#include "config.h"
#include "hash.h"
#include "macro.h"
#include "null.h"
#include "path.h"
#include "slist.h"
#include "yesno.h"

#ifdef _HasSymLinks

#define NOT_SYMLINK	1		/* not a symbolic link */
#define UNV_SYMLINK	2		/* unverified symbolic link */
#define VER_SYMLINK	3		/* verified symbolic link */

extern int errno;			/* error indicator for system calls */
extern SLIST *SRCLIST;			/* source file name list */
extern SLIST *HEADLIST;			/* header file name list */
extern HASH *MDEFTABLE;			/* macro definition table */

static int addsrctable();		/* add file to source hash table */
static int addvsrctable();		/* add virtual file to hash table */
static int  hashtolist();		/* convert hash table file list */
static HASH *SRCTABLE = NULL;		/* source file hash table */
static HASH *HDRTABLE = NULL;		/* header file hash table */

static struct stat CURDIRSTAT;		/* current directory status */

/*
 * mksymlink() creates symbolic links from foreign directories into
 * the current directory. Return YES if successful, otherwise NO.
 *
 * Given the following state of the current directory and a virtual path:
 *
 * ./a.c -----> dangling reference
 * ./b.c        ordinary file
 * ./c.c ----->	a/c.c
 *		a/d.c
 * ./d.c ----->	b/d.c
 * ./e.c ----->	b/e.c
 * ./f.c ----->	c/f.c
 *
 * VPATH = a b
 *
 * mksymlink() needs to delete a.c, shift the link for d.c from directory b
 * to directory a, and issue a warning that f.c is linked to a file in an
 * external directory.
 */
mksymlink(needsrc, needhdr)
	int needsrc;			/* need source file names */
	int needhdr;			/* need header file names */
{
	char *getpath();		/* get next path */
	char *vp;			/* virtual path buffer pointer */
	char vpath[PATHSIZE];		/* virtual directory path buffer */
	int read_dir();			/* read dir for source and headers */
	struct stat statbuf;		/* virtual path stat buffer */

	if ((HDRTABLE = htinit(SOURCETABLESIZE)) == NULL)
		return(NO);
	if ((SRCTABLE = htinit(SOURCETABLESIZE)) == NULL)
		return(NO);

	if (stat(CURDIR, &CURDIRSTAT) < 0)
		{
		pperror(CURDIR);
		return(NO);
		}

	if (read_dir(CURDIR, addsrctable, needsrc, needhdr) == NO)
		return(NO);

	/*
	 * merge source/header files in other directories into hash table
	 * source list
	 */
	if (htlookup(MVPATH, MDEFTABLE) != NULL)
		{
		vp = htdef(MDEFTABLE);		
		while ((vp = getpath(vpath, vp)) != NULL)
			{
			if (stat(vpath, &statbuf) < 0)
				{
				pperror(vpath);
				continue;
				}

			if (!S_ISDIR(statbuf.st_mode))
				{
				warns("(warning) %s in VPATH not a directory", vpath);
				continue;
				}

			if (CURDIRSTAT.st_dev == statbuf.st_dev &&
			    CURDIRSTAT.st_ino == statbuf.st_ino)
				{
				warns("(warning) current directory %s included in VPATH", vpath);
				continue;
				}

			if (read_dir(vpath, addvsrctable, needsrc, needhdr) == NO)
				return(NO);
			}
		}

	/*
	 * convert hash table source file entries to singly-linked source list
	 */
	if (hashtolist(SRCTABLE, SRCLIST) == NO)
		{
		htrm(NULL, SRCTABLE);
		return(NO);
		}
	htrm(NULL, SRCTABLE);

	/*
	 * convert hash table header file entries to singly-linked header list
	 */
	if (hashtolist(HDRTABLE, HEADLIST) == NO)
		{
		htrm(NULL, HDRTABLE);
		return(NO);
		}
	htrm(NULL, HDRTABLE);

	return(YES);
}



/*
 * addsrctable() adds a file to a source/header file hash table. Returns
 * YES if successful, otherwise NO.
 */
static int
addsrctable(dirname, filename, tswitch)
	char *dirname;			/* directory name */
	char *filename;			/* file name to add to source table */
	int tswitch;			/* source/header table switch */
{
	char symbuf[PATHSIZE];		/* symbolic link pathname buffer */

if (readlink(filename, symbuf, PATHSIZE) < 0)
		{
#ifdef _HasEnxioReadlinkReturn		/* ugly hack around apollo bug */
		if (errno == EINVAL || errno == ENXIO)
#else
                if (errno == EINVAL)
#endif
			{
			if (htinstall(filename, NULL, NOT_SYMLINK,
			   (tswitch == 's') ? SRCTABLE : HDRTABLE) == NULL)
				return(NO);
			}
		else	{
			pperror(filename);
			return(NO);
			}
		}
	else	{
		if (htinstall(filename, pathhead(symbuf), UNV_SYMLINK,
		   (tswitch == 's') ? SRCTABLE : HDRTABLE) == NULL)
			return(NO);
		}
	return(YES);
}



/*
 * addvsrctable() merges source/header files from directories in the virtual
 * path into a source or header file hash table. If a file in the current
 * directory is linked to a file in a yet unseen directory, then the link
 * is broken and reestabished to a file in the current virtual directory.
 * Returns YES if successful, otherwise NO.
 */
static int
addvsrctable(dirname, filename, tswitch)
	char *dirname;			/* directory name */
	char *filename;			/* file name to add to source table */
	int tswitch;			/* source/header table switch */
{
	char path[PATHSIZE];		/* path to foreign source file */
	HASH *table;			/* pointer to source/header file table */

	table = (tswitch == 's') ? SRCTABLE : HDRTABLE;
	if (htlookup(filename, table) != NULL)
		{
		if (htval(table) == UNV_SYMLINK)
			{
			if (!EQUAL(dirname, htdef(table)))
				{	/* link file from dirname */
				if(unlink(filename) < 0)
					{
					warns("(error) failed to remove symbolic link %s", filename);
					return(NO);
					}
				else if (symlink(pathcat(path, dirname, filename), filename) < 0)
					{
					pperror(filename);
					return(NO);
					}
				else	{
					char oldpath[PATHSIZE];	/* extra pathname buffer */
					pathcat(oldpath, htdef(table), filename);
					warn2("(warning) symbolic link %s replaced by %s", oldpath, path);
					}
				}
			htval(table) = VER_SYMLINK;
			}
		else	{
			warn2("(warning) duplicate file %s/%s ignored", htdef(table), filename);
			}
		}
	else	{
		if (htinstall(filename, NULL, VER_SYMLINK, table) == NULL)
			return(NO);
		pathcat(path, dirname, filename);
		if (symlink(path, filename) < 0)
			{
			pperror(filename);
			return(NO);
			}
		}
	return(YES);
}



/*
 * hashtolist() converts the file entries stored in a hash table to a
 * singly-linked list. Also removes dangling symbolic links, and complains
 * about rogue links that are not in VPATH. Returns YES if successful,
 * otherwise NO.
 */
static int
hashtolist(table, list)
	HASH *table;			/* hash table */
        SLIST *list;			/* pointer to list head block */
{
        extern int MKSYMLINK;           /* clobber rogue links if > 1 */

	htrewind(table);
	while (htnext(table))
		{
		if (htval(table) == UNV_SYMLINK)
			{
			if (MKSYMLINK > 1 || !FILEXIST(htkey(table)))
				{
				if(unlink(htkey(table)) < 0)
					{
					warns("Failed to remove symbolic link %s", htkey(table));
					}
				}
			else	{
				warns("%s linked to directory not in VPATH", htkey(table));
				if (slappend(htkey(table), list) == NULL)
					return(NO);
				}
			}
		else 	{
			if (slappend(htkey(table), list) == NULL)
				return(NO);
			}
		}
	return(YES);
}

#else

/*
 * mksymlink() dummy routine always returns NO.
 */
mksymlink(needsrc, needhdr)
	int needsrc;			/* need source file names */
	int needhdr;			/* need header file names */
{
	warn("symbolic links not available");
	return(NO);
}

#endif /* _HasSymLinks */