#	@(#):mknodes	35.6
MAKE=${MAKE:-make}
NODOG=nodog
TABLE=nodes.tbl
PWD=`pwd`
trap "rm -f ${PWD}/${NODOG}.c ${PWD}/${NODOG}; exit 1" 1 2 15
cat > ${NODOG}.c << !!
/*
 * nodog - Node Output Generator
 *    -b    Take device path names on stdin and print device table on stdout
 *    -c    Take device table on stdin and generate device nodes
 */
#include	<stdio.h>
#include	<pwd.h>
#include	<grp.h>
#include	<ctype.h>
#include	<errno.h>
#include	<sys/types.h>
#include	<sys/stat.h>

#define		ERROR		-1

#define		BUILD		0
#define		CREATE		1
#define		DATABASE	0
#define		SHELL		1
#define		LINK		0
#define		MKNOD		1

#define		MAJOR(m)	((m&0xFF00)>>8)
#define		MINOR(m)	(m&0xFF)
#define		ISBLK(m)	((m&S_IFMT)==S_IFBLK)
#define		ISCHR(m)	((m&S_IFMT)==S_IFCHR)

struct lnk {
	dev_t	l_dev;
	ushort	l_ino;
	char	*l_nam;
	struct lnk	*l_next;
};

struct lnk	*Lhead;

/* Variables for reading device table */
char	d_cmd;
char	d_path1[128], d_path2[128];
char	d_type;
int	d_maj, d_min;
char	d_own[32], d_grp[32];
int	d_mode;

char	*c_fmt = "%c %s %c %d %d %s %s %o";
char	*l_fmt = "%c %s %s";

char	cbuf[1024];
char	*Name;

extern FILE	*freopen();
extern char	*gets();
extern char	*malloc();

extern int	errno;
extern char	*sys_errlist[];

extern int	optind;
extern char	*optarg;

main(argc, argv)
int	argc;
char	*argv[];
{

	int	errflg = 0;
	int	mode = BUILD;
	int	type = DATABASE;
	int	c, ret = 1;

	Name = argv[0];
	while ((c = getopt(argc,argv,"bcf:s")) != EOF) {
		switch (c) {
		    case 'b':
			mode = BUILD;
			break;
		    case 'c':
			mode = CREATE;
			break;
		    case 's':
			type = SHELL;
			break;
		    case 'f':
			if (freopen(optarg, "r", stdin) == NULL) {
				fprintf(stderr, "%s: cannot open %s\n",
				    argv[0], optarg);
				errflg++;
			}
			break;
		    case '?':
			errflg++;
			break;
		}
	}

	if (errflg || argc < optind) {
		fprintf(stderr,
		    "Usage: %s [-bc ] [ file ]\n", argv[0]);
		exit(1);
	}

	if (mode == BUILD) {
		ret = build_db(type);
	}
	else if (mode == CREATE) {
		if (getuid() != 0) {
			fprintf(stderr, "warning - nodog should not run around without his super-user powers\n");
		}
		ret = create_nodes(type);
	}
	exit(ret);
}

build_db(type)
int	type;
{
	struct stat	s;
	int	action;
	char	*src;
	char	*getname(), *getgrp(), *resolve_links();

	while (gets(cbuf) != NULL) {
		if (stat(cbuf, &s) == ERROR) {
			fprintf(stderr, "%s: stat(%s) failed: %s\n",
			    Name, cbuf, sys_errlist[errno]);
			continue;
		}
		if (! ISBLK(s.st_mode) && ! ISCHR(s.st_mode) ) {
			continue;
		}

		if ( s.st_nlink > 1 && (src=resolve_links(cbuf, &s)) ) {
			dispent(LINK, type, src, cbuf, &s);
		}
		else {
			dispent(MKNOD, type, src, cbuf, &s);
		}
	}
}

dispent(act, otyp, src, dst, s)
int	act, otyp;
char	*src, *dst;
struct stat	*s;
{
	if (act == LINK) {
		if (otyp == DATABASE) {
			printf("l %-25s %-25s\n", src, dst);
		}
		else {	/* SHELL */
			printf("if [ ! -d \`dirname %s\` ]\nthen\tmkdir -p \`dirname %s\`\nfi\n",
			       dst, dst);
			printf("rm -f %s\nln %s %s\n\n", dst, src, dst);
		}
	}
	else {	/* MKNOD */
		if (otyp == DATABASE) {
			printf("c %-25s %c %4d %4d    %-10s %-10s %04o\n",
			       dst,
			       ISBLK(s->st_mode) ? 'b' : 'c',
			       MAJOR(s->st_rdev),
			       MINOR(s->st_rdev),
			       getname(s->st_uid),
			       getgrp(s->st_gid),
			       s->st_mode & 0777);
		}
		else {	/* SHELL */
			printf("if [ ! -d \`dirname %s\` ]\nthen\tmkdir -p \`dirname %s\`\nfi\n",
			    dst, dst);
			printf("rm -f %s\nmknod %s %c %d %d\nchown %s %s\nchgrp %s %s\nchmod %o %s\n\n",
			       dst,
			       dst,
			       ISBLK(s->st_mode) ? 'b' : 'c',
			       MAJOR(s->st_rdev),
			       MINOR(s->st_rdev),
			       getname(s->st_uid),
			       dst,
			       getgrp(s->st_gid),
			       dst,
			       s->st_mode & 0777,
			       dst);
		}
	}
}

char *
resolve_links(nam, s)
char	*nam;
struct stat	*s;
{
	struct lnk	*l, *last, *newlnk;

	for (l=Lhead, last = NULL; l; l = l->l_next) {
		last = l;
		if (s->st_dev == l->l_dev && s->st_ino == l->l_ino) {
			return(l->l_nam);
		}
	}

	/* not found, add to current list */
	if ( (newlnk=(struct lnk *)malloc(sizeof(struct lnk))) == NULL ||
	     (newlnk->l_nam=malloc(strlen(nam)+1)) == NULL ) {
		/* This is real bad */
		fprintf(stderr, "%s: Unable to malloc enough memory\n", Name);
		exit(1);
	}

	/* create new entry */
	strcpy(newlnk->l_nam, nam);
	newlnk->l_dev = s->st_dev;
	newlnk->l_ino = s->st_ino;
	newlnk->l_next = NULL;

	/* link it on the list */
	if (last == NULL) {
		Lhead = newlnk;		/* first on link list */
	}
	else {
		last->l_next = newlnk;	/* add it to the end */
	}

	return((char *)NULL);		/* no match found */
}

char	*
getname(id)
int	id;
{
	struct passwd	*pw,
			*getpwuid();
	char		num[16];

	if ((pw=getpwuid(id)) != NULL) {
		return(pw->pw_name);
	}
	else {
		sscanf(num, "%d", id);
		return(num);
	}
}

char	*
getgrp(id)
int	id;
{
	struct group	*gp,
			*getgrgid();
	char		num[16];

	if ( (gp=getgrgid(id)) != NULL) {
		return(gp->gr_name);
	}
	else {
		sscanf(num, "%d", id);
		return(num);
	}
}

create_nodes(type)
int	type;
{
	char	*p;

	umask(0);

	while (gets(cbuf) != NULL) {
		p = cbuf;

		if (*p == '#') {
			continue;
		}

		for ( ; *p == ' ' || *p == '\t'; p++) {
		}

		switch(*p) {
		    case 'c':
			make_node(cbuf);
			break;
		    case 'l':
			link_node(cbuf);
			break;
		    default:
			fprintf(stderr, "%s: invalid entry type %c\n",Name,*p);
		}
	}
}

make_node(info)
char	*info;
{
	int	devmode;

	if ( sscanf(info, c_fmt, &d_cmd, d_path1, &d_type, &d_maj, &d_min, d_own, d_grp, &d_mode) != 8 ) {
		fprintf(stderr,
		    "%s: mknode command with wrong number of fields\n", Name);
		return;
	}

	if (chkdir(d_path1) == ERROR) {
		fprintf(stderr, "%s: cannot create directory for %s\n", Name,
		    d_path1);
		return;
	}

	if (unlink(d_path1) == ERROR) {
		if (errno != ENOENT) {
			fprintf(stderr,
			    "%s: unlink of node %s failed: %s\n",
			    Name, d_path1, sys_errlist[errno]);
			return;
		}
	}

	d_mode = ((d_mode&0777) | (d_type == 'b' ? S_IFBLK : S_IFCHR));
	devmode = (((d_maj<<8)|(d_min&0xFF))&0xFFFF);
	if (mknod(d_path1, d_mode, devmode) == ERROR) {
		fprintf(stderr,
		    "%s: mknod of  %s failed: %s\n",
		    Name, d_path1, sys_errlist[errno]);
		return;
	}

	setowner(d_path1, d_own, d_grp);
}

chkdir(path)
char	*path;
{
	char	buf[128];
	char	*slash, *p, *strchr();
	struct stat	s;

	strcpy(buf, path);		/* make local copy */
	p = (*buf == '/') ? buf+1 : buf;
	for (; (slash=strchr(p, '/')); p = slash + 1) {
		*slash = NULL;
		if (access(buf, 00) == ERROR) {
			if (mkdir(buf, 0755) == ERROR) {
				*slash = '/';
				return(ERROR);
			}
		}
		*slash = '/';
	}
	return(0);
}

setowner(path, own, grp)
char	*path, *own, *grp;
{
	int	oid, gid;
	struct passwd	*pw, *getpwnam();
	struct group	*gr, *getgrnam();

	if (isdigit(*own)) {
		oid = atoi(own);
	}
	else {
		if ( (pw=getpwnam(own)) == NULL ) {
			fprintf(stderr,
			    "warning - unknown user id, setting to 60002\n");
			oid = 60002;
		}
		else {
			oid = pw->pw_uid;
		}
	}

	if (isdigit(*grp)) {
		gid = atoi(grp);
	}
	else {
		if ( (gr=getgrnam(grp)) == NULL ) {
			fprintf(stderr,
			    "warning - unknown group id, setting to 60002\n");
			gid = 60002;
		}
		else {
			gid = gr->gr_gid;
		}
	}

	if (chown(path, oid, gid) == ERROR) {
		fprintf(stderr,
		    "warning - unable to set owner and group on %s: %s\n",
		    path, sys_errlist[errno]);
	}
}

link_node(info)
char	*info;
{
	if ( sscanf(info, l_fmt, &d_cmd, d_path1, d_path2) != 3 ) {
		fprintf(stderr,
		    "%s: link command with wrong number of fields\n", Name);
		return;
	}

	if (access(d_path1, 00) == ERROR) {
		fprintf(stderr, "%s: source device for link missing: %s\n",
		    Name, d_path1);
		return;
	}

	if (unlink(d_path2) == ERROR) {
		if (errno != ENOENT) {
			fprintf(stderr,
			    "warning - unlink of destination %s failed: %s\n",
			    d_path2, sys_errlist[errno]);
			/* continue on and hope for the best */
		}
	}

	if (link(d_path1, d_path2) == ERROR) {
		fprintf(stderr, "%s: link %s to %s failed: %s\n",
		    Name, d_path1, d_path2, sys_errlist[errno]);
		return;
	}
}
!!

echo "Begin build of node install program..."
${MAKE} ${NODOG}
echo "Begin node installation..."
if [ -f ${NODOG} ]
then
	# This runs in $ROOT/usr/src so $ROOT is relative as ../..
	cd ../..
	usr/src/${NODOG} -c < usr/src/${TABLE}
	STAT=$?
	cd usr/src
	if [ ${STAT} != 0 ]
	then
		echo "*** :mknodes: Can't make nodes ****"
		exit 1
	fi
else
	echo "*** :mknodes: Can't make node install program ****"
	exit 1
fi
rm -f ${PWD}/${NODOG} ${PWD}/${NODOG}.c
