Ultrix-3.1/sys/distr/setup_osl.c

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

static char Sccsid[] = "@(#)setup_osl.c	3.1	3/28/87";

/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 * TODO:
 *
 *	LIST command overflows screen on a CRT. Add Press <RETURN>
 *	for more: (if tty is a CRT).
 *
 * NICE:
 *
 *	Show the user a blocks to be loaded summary before starting the
 *	load. Allow the user to delete items from the to be loaded list,
 *	if it all will not fit in the available free space. Do a free
 *	command to show available free space.
 *
 *	All the load functions [f_*()] should return status and doload()
 *	should check status and print a load failed error if necessary.
 *
 */
/*
 *
 *  File name:
 *
 *	setup_osl.c
 *
 *  Source file description:
 *
 *	ULTRIX-11 initial setup program (optional software load).
 *
 *	TBS, when I figger it out!
 *	Created by mundging osload.c.
 *	loads opt sw, called by setup phase 2 or 3.
 *	target vs current cpu stuff.
 *
 *  Functions:
 *
 *	main()		The main is the main!
 *
 *	pmsg()		Prints a message from an array of character pointers.
 *
 *	yes(NOHELP)		Return YES, NO, HELP, depending on how the user
 *			answered a question.
 *
 *	intr()		Handles interrupt signal (<CTRL/C>).
 *
 *	retry()		Ask the user if a failed function should be retried.
 *
 *	prtc()		Handles "Press <RETURN> to continue: "
 *
 *	OTHERS?		Check above also.
 *
 *  Usage:
 *
 *	/.setup/setup_osl cpu loadev rxtype rxunit rd2
 *		cpu    - Target processsor type
 *		loadev - Distribution load device ?? (rx rl rc ht tm ts tk tu)
 *		rxtype - Floppy disk drive type (RX50 or RX33).
 *		rxunit - Floppy diak unit number (if load medis is RX50).
 *		rd2    - Second winchester disk present (changes RX unit #).
 *
 *	Called by the setup program, not intended for direct user access.
 *
 *  Compile:
 *
 *	cd /usr/sys/distr; make setup_osl
 *
 *  Modification history:
 *
 *	06 April 1985
 *		File created -- Fred Canter
 *
 *	04 May 1985
 *		Version 1.0  -- Fred Canter
 *
 *		Initial SCCS delta crated.
 *
 *	04 May 1985
 *		Version 2.0 -- Fred Canter
 *
 *		Changed SCCS delta to 2.0 and added support for loading
 *		optional software from RX50 diskettes.
 *		TODO: other?????
 *
 */

#include <sys/param.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/ra_info.h>
#include <stdio.h>
#include <a.out.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>

struct	stat	statb;
struct	stat	lstatb;

jmp_buf savej;

/*
 * General use defines.
 */
#define	SID	1
#define	NSID	0
#define	YES	1
#define	NO	0
#define	NOHELP	0
#define	YHELP	1
#define	ROOT	0
#define	USR	1
#define	SUP1	1
#define	SUP2	2
#define	SUP3	3
#define	TCSTART	0
#define	TCEND	1
#define	SINGLE	0
#define	MULTI	1

/*
 * Processor type info table.
 */
int	cputype;
int	tpi;
struct	cputyp {
	int	p_type;		/* processor type */
	int	p_sid;		/* Separate I & D space ? */
} cputyp[] = {
	23,	NSID,
	24,	NSID,
	34,	NSID,
	40,	NSID,
	44,	SID,
	45,	SID,
	53,	SID,
	55,	SID,
	60,	SID,
	70,	SID,
	73,	SID,
	83,	SID,
	84,	SID,
	0
};
/* TODO: what to do if cpu not found in table ??? */

#define	NARG	25	/* number of items allowed (very large) */

char	*cmd;		/* command to execute */
int	argp;		/* index into following list */
char	*args[NARG+1];	/* list of items for command to act on */
int	cbsetup;	/* setup_osl called by setup */
/* TODO: check size really needed! */
char	syscmd[1250];
#define	LBSIZE	250
char	lbuf[LBSIZE+1];
char	line[LBSIZE+1];
#define	GLBSIZE	20
char	glbuf[GLBSIZE];
char	*loadev;	/* Load device (rmt0 rht0 rgt0 rtk0 rrl0? rrc0?) */
int	ld_tape;	/* Load device is magtape */
int	ld_rl02;	/* Load device is RL02 */
int	ld_rx50;	/* Load device is RX50 floppy disk */
int	rxunit;		/* RX50/RX33 unit number */
int	rxtype;		/* Floppy disk drive type (RX33 or RX50) */
int	rd2;		/* Second RD disk present (needed by rxpos()) */
char	ddfile[25];	/* file name used by ddopen() and doload() */
char	mtscmd[100];	/* magtape position command used by ddopen() */

#define	EXIT	1
#define	FREE	2
#define	HELP	3
#define	RXUNIT	4
#define	RXDIR	5
#define	LIST	6
#define	LOAD	7
#define	UNLOAD	8
#define	BADCMD	-1
struct	cmdtyp {
	char	*cmd_name;	/* name of command */
	int	cmd_id;		/* command ID */
} cmdtyp[] = {
	"exit",		EXIT,
	"e",		EXIT,
	"ex",		EXIT,
	"bye",		EXIT,
	"b",		EXIT,
	"quit",		EXIT,
	"q",		EXIT,
	"free",		FREE,
	"f",		FREE,
	"fr",		FREE,
	"help",		HELP,
	"?",		HELP,
	"h",		HELP,
	"rxunit",	RXUNIT,
	"rxu",		RXUNIT,
	"rxdir",	RXDIR,
	"rxd",		RXDIR,
	"list",		LIST,
	"li",		LIST,
	"load",		LOAD,
	"lo",		LOAD,
	"unload",	UNLOAD,
	"u",		UNLOAD,
	"un",		UNLOAD,
	0,		BADCMD,
};

/*
 * Optional software load/unload control flags.
 */

#define	OS_SEL	01	/* Item selected for loading or unloading */
#define	OS_SYM	02	/* Item to be loaded with a symbolic link */

int	f_dict(), f_docprep(), f_f77(), f_games(), f_learn(), f_libsa();
int	f_plot(), f_saprog(), f_sccs(), f_spell(), f_sysgen();
int	f_usat(), f_usep(), f_uucp(), f_tcpip(), f_orphan(), f_manuals();
int	f_pascal(), f_userdev();

struct	os_info {
	char	*os_name;	/* Item name string */
	int	os_size;	/* Loading cost in Kbytes (1K blocks) */
	char	os_slink[DIRSIZ+2];	/* Symbolic link directory name */
	int	os_flags;	/* Control flags (SELECT, SYMLINK) */
	char	os_filsys;	/* Where loaded (ROOT or /USR) */
	char	os_offset;	/* Magtape file number (skip this many) */
	char	*os_tarfs;	/* TAR image name for loading optsw from RL/RC */
	int	(*os_func)();	/* Call this function to load/unload item */
	char	*os_flop;	/* Name of first diskette (may be a second) */
	char	*os_desc1;	/* First line of description */
	char	*os_desc2;	/* Optional second line of description */
} os_info[] = {
	"dict",		210,	{0}, 0,	USR,	27,  "ucmds",	f_dict,
		"DICTIONARY",
		"Spell dictionary and hash lists",
		"(Not needed unless remaking spell dictionary)",
	"docprep",	980,	{0}, 0,	USR,	24,  "ucmds",	f_docprep,
		"DOCPREP #1",
		"Document prepration software: nroff troff roff",
		"refer (+ dict/papers) tbl eqn fonts macros",
	"f77",		350,	{0}, 0,	USR,	14,  "ucmds",	f_f77,
		"F77",
		"Fortran 77 programs and libraries",
		"(f77, ratfor, structure and beautify)",
	"games",	300,	{0}, 0,	USR,	29,  "ucmds",	f_games,
		"GAMES",
		"Games (Programmer's Manual, Vol. 1, Section 6)",
		0,
	"learn",	860,	{0}, 0,	USR,	25,  "ucmds",	f_learn,
		"LEARN #1",
		"Learn scripts (Computer Aided Instruction)",
		0,
	"libsa",	60,	{0}, 0,	USR,	26,  "ucmds",	f_libsa,
		"PASCAL",
		"Library for building stand-alone programs",
		0,
	"manuals",	2100,	{0}, 0,	USR,	30,  "ucmds",	f_manuals,
		"MANUALS #1",
		"On-line ULTRIX-11 Programmer's Manual, Volume 1",
		"(for use with man(1) and catman(8) commands)",
	"orphans",	360,	{0}, 0,	USR,	28,  "ucmds",	f_orphan,
		"ORPHANS",
		"ORPHAN files: old versions of some software",
		"(refer to /usr/orphan/README for help)",
	"pascal",	250,	{0}, 0,	USR,	15,  "ucmds",	f_pascal,
		"PASCAL",
		"PASCAL interpreter, executer, and profiler",
		"(University of California at Berkeley 2.9 BSD)",
	"plot",		185,	{0}, 0,	USR,	16,  "ucmds",	f_plot,
		"PLOT",
		"Plot libraries (graphics filters and programs)",
		0,
	"saprog",	125,	{0}, 0,	ROOT,	13,  "rcmds",	f_saprog,
		"BOOT",
		"Stand-alone programs in /sas directory: scat",
		"copy icheck mkfs restor bads rabads dskinit",
	"sccs",		300,	{0}, 0,	USR,	17,  "ucmds",	f_sccs,
		"SCCS",
		"Source Code Control System",
		0,
	"spell",	175,	{0}, 0,	USR,	22,  "ucmds",	f_spell,
		"SPELL",
		"Spelling checker and associated programs",
		"(programs to rebuild hlists from dictionary)",
	"sysgen",	890,	{0}, 0,	USR,	31,  "sysgen",	f_sysgen,
		"SYSGEN #1",
		"System generation programs and files",
		0,
	"tcpip",	410,	{0}, 0,	USR,	20,  "ucmds",	f_tcpip,
		"TCP/IP",
		"TCP/IP ethernet networking software",
		"(for local area network over an ethernet)",
	"usat",		205,	{0}, 0,	USR,	18,  "ucmds",	f_usat,
		"USAT",
		"ULTRIX-11 System Acceptance Test",
		"(verifies the system is installed and working)",
	"usep",		400,	{0}, 0,	USR,	19,  "ucmds",	f_usep,
		"USEP",
		"User-mode System Exerciser Package",
		"(verifes system hardware working properly)",
	"userdev",	140,	{0}, 0, USR,	23,  "ucmds",	f_userdev,
		"DICTIONARY",
		"User written device driver sources and documentation",
		0,
	"uucp",		340,	{0}, 0,	USR,	21,  "ucmds",	f_uucp,
		"UUCP",
		"UUCP (unix to unix copy)",
		"(connect to other systems via phone or hardwire)",
	0
};

/*
 * General use strings
 */

/* TODO: remove after debug
char	*gs_more = "\nPress <RETURN> for more:";
*/
char	*gs_prtc = "\nPress <RETURN> to continue:";
char	*sl_make = "Making symbolic link";
char	gs_txerr[50];	/* TAR extract of ? files */
char	*gs_usr = "/usr";

/*
 * All help messages moved to setup_help.
 */

char	*rx_dir[] =
{
	"",
	"Diskette(s)  Contents",
	"-----------  ------------------------------------------------------",
	"BOOT         FILSYS: boot, auto-install, & stand-alone programs.",
	"ROOT 1-9     DUMP:   ULTRIX-11 ROOT file system.",
	"USR  1-9     DUMP:   ULTRIX-11 /USR file system.",
	"SYSGEN 1-4   MIXED:  (1&3 TAR, 2&4 FILSYS) System generation.",
	"USEP         TAR:    User-mode System Exerciser Package.",
	"UUCP         TAR:    UUCP store and forward networking Software.",
	"TCP/IP       TAR:    TCP/IP networking software.",
	"F77          TAR:    Fortran 77 compiler/libraries & ratfor.",
	"PASCAL       TAR:    PASCAL interpreter/executer/profiler, libsa.a.",
	"SCCS         TAR:    Source Code Control System (part of TCP/IP).",
	"PLOT         TAR:    Graphics filters and libraries (part of UUCP).",
	"USAT         TAR:    USAT, Fortran structure and beautify.",
	"DOCPREP 1-3  TAR:    Document preparation programs & libraries.",
	"SPELL        TAR:    Spelling checker & hashed dictionary files.",
	"DICTIONARY   TAR:    Spell dictionary source & user driver sources.",
	"LEARN 1&2    FILSYS: Learn programs and lesson script archives.",
	"ORPHANS      TAR:    Obsolete software, for backward compatibility.",
	"GAMES        TAR:    Games programs.",
	"MANUALS 1-5  TAR:    On-line manuals, for man(1) and catman(8).",
	"",
	0
};

struct hsub {
	char	*hs_name;
	char	*hs_msg;
} hsub[] = {
	"CTRL/C",	"h_ctrlc",
	"ctrlc",	"h_ctrlc",
	"ctrl/c",	"h_ctrlc",
	"^C",		"h_ctrlc",
	"^c",		"h_ctrlc",
	"abort",	"h_ctrlc",
	"help",		"h_help",
	"?",		"h_help",
	"usage",	"h_usage",
	"commands",	"h_cmds",
	"exit",		"h_exit",
	"bye",		"h_exit",
	"quit",		"h_exit",
	"free",		"h_free",
	"rxunit",	"h_rxunit",
	"rxdir",	"h_rxdir",
	"list",		"h_list",
	"load",		"h_load",
	"unload",	"h_unload",
	0
};

main(argc, argv)
int	argc;
char	*argv[];
{
	int	cleanup();
	register int i, j;
	int mem, cc;
	char c;
	char *p;

	if(getuid() != 0) {
		printf("\nsetup_osl: must be super-user!\n");
		xit(1);
	}
	if(argc != 6) {
		printf("\nsetup_osl: bad argument count!\n");
		xit(1);
	}
	cputype = atoi(argv[1]);
	for(tpi=0; cputyp[tpi].p_type; tpi++)
		if(cputype == cputyp[tpi].p_type)
			break;
	if(cputyp[tpi].p_type == 0) {
		printf("\nPDP11/%d processor not supported!\n", cputype);
		xit(1);
	}
/*
 * Determine if setup_osl was called by setup
 * or osload shell script. Changes the way we
 * deal with mounting file systems (symbolic links).
 */
	if(strcmp("/.setup/setup_osl", argv[0]) == 0)
		cbsetup = NO;
	else
		cbsetup = YES;
/*
 * Find out what the load device is and
 * get the density if it is magtape.
 */
	ld_rx50 = NO;
	ld_tape = NO;
	ld_rl02 = NO;
	if(strcmp("rl", argv[2]) == 0) {
		loadev = "rrl17";	/* May be changed later! */
		ld_rl02 = YES;
	} else if(strcmp("rc", argv[2]) == 0) {
		loadev = "rrc04";
	} else if(strcmp("rx", argv[2]) == 0) {
		rxtype = atoi(argv[3]);
		i = atoi(argv[4]);
		if((i < 0) || (i > 7)) {
		    printf("\nsetup_osl: bad floppy disk unit number!\n");
		    xit(1);
		}
		loadev = "rrx0";
		loadev[3] = i + '0';
		rxunit = i;
		ld_rx50 = YES;
		rd2 = atoi(argv[5]);	/*  see setup.c */
	} else if(strcmp("tk", argv[2]) == 0) {
		ld_tape = YES;
		loadev = "rtk0";
	} else if(strcmp("ht", argv[2]) == 0) {
		ld_tape = YES;
		loadev = 0;	/* set later, see getden() */
	} else if(strcmp("tm", argv[2]) == 0) {
		ld_tape = YES;
		loadev = "rmt0";
	} else if(strcmp("ts", argv[2]) == 0) {
		ld_tape = YES;
		loadev = "rht0";
	} else if(strcmp("tu", argv[2]) == 0) {
		ld_tape = YES;
		loadev = "rht0";	/* NO PLANS FOR 6250 DISTRIBUTION */
	} else {
	    printf("\nsetup_osl: bad load device!\n");
	    xit(1);
	}
	printf("\n\nULTRIX-11 SETUP: Optional Software Load Program.\n");
	printf("\nFor instructions type `help', then press <RETURN>.\n");
	/*
	 * Force all file system to be mounted.
	 * Do a mount -a, but ignore errors.
	 * All file systems must be mounted in case
	 * symbolic links used.
	 * If called by setup, no need to tell user about
	 * mounting file systems because setup will unmount them.
	 */
	if(cbsetup == NO) {
	    printf("\n\7\7\7OSLOAD: ");
	    printf("forcing mounting of all file systems!\n");
	}
	system("/etc/mount -a >/dev/null 2>&1");
	while(1) {		/* Command decode loop */
	    setjmp(savej);
	    signal(SIGINT, cleanup);
	    chdir("/");	/* make sure not in directory we are going to work on */
	    printf("\nCommand <help free rxunit rxdir list load unload exit>: ");
	    cc = getline(lbuf);
	    if(cc == 1)
		continue;
	    for(i=0; os_info[i].os_name; i++)
		os_info[i].os_flags = 0;
	    for(i=0; i<NARG+1; i++)
		args[i] = 0;
	    argp = 0;
	    cmd = lbuf;
	    for(p=lbuf; ; p++) {
		c = *p;
		if((c == ' ') || (c == '\n')) {
		    *p = '\0';
		    if(c == '\n')
			break;
		    if(c == ' ') {
			while(*++p == ' ') ;
			if(*p == '\n')
			    break;
			if(argp >= NARG) {
			    printf("\nItem limit reached - truncating line!\n");
			    break;
			}
			args[argp++] = p;
		    }
		}
	    }
	    for(i=0; cmdtyp[i].cmd_name; i++)
		if(strcmp(cmdtyp[i].cmd_name, cmd) == 0)
		    break;
	    switch(cmdtyp[i].cmd_id) {
	    case EXIT:
		xit(0);
	    case HELP:
		dohelp();
		break;
	    case FREE:
		dofree();
		break;
/* TODO: (2nd rd, top left right lower) ???? */
	    case RXUNIT:
		if(args[0] == 0)
		    rxunit = 0;
		else
		    rxunit = atoi(args[0]);
		while(1) {
		    if(rxunit == 0) {
			do
			    printf("\nFloppy disk unit number < 1 2 3 > ? ");
			while(gline("h_rx_un") <= 0);
			rxunit = atoi(glbuf);
		    }
		    if((rxunit < 0) || (rxunit > 3)) {
			rxunit = 0;
			printf("\n%d - bad unit number!\n", rxunit);
			continue;
		    }
		    break;
		}
		loadev[3] = rxunit + '0';
		break;
	    case RXDIR:
		pmsg(rx_dir);
		break;
	    case LIST:
		chklist(LIST);
		dolist();
		break;
	    case LOAD:
		getlist(LOAD);
		if(chklist(LOAD))
		    break;	/* bad or empty item list */
		sblink();
		ddmnt();
		getden();
		doload(LOAD);
		break;
	    case UNLOAD:
		getlist(UNLOAD);
		if(chklist(UNLOAD))
		    break;	/* bad or empty item list */
		doload(UNLOAD);
		break;
	    default:
		printf("\n%s - invalid command!\n", cmd);
		break;
	    }
	}
}

/*
 * Print help message.
 * Look up message name in hsub[] table,
 * then call setup_help to print message.
 */

dohelp()
{
	register int i, j;

	if(args[0] == 0)
		args[0] = "help";
	for(i=0; hsub[i].hs_name; i++)
		if(strcmp(args[0], hsub[i].hs_name) == 0)
			break;
	if(hsub[i].hs_name == 0) {
		printf("\nNo help available for `%s' subject.\n", args[0]);
		return(1);
	}
	phelp(hsub[i].hs_msg);
/*
 * TODO: remove after debug
	for(j=0; hsub[i].hs_msg[j]; j++) {
		if(hsub[i].hs_msg[j] == -1) {
			printf("%s", gs_more);
			while(getchar() != '\n') ;
			continue;
		}
		printf("\n%s", hsub[i].hs_msg[j]);
	}
 * TODO: end
 */
}

dofree()
{
	printf("\nFREE DISK SPACE (/ = ROOT, /usr = /USR):\n\n");
	system("df");
}

doload(com)
{
	register struct os_info *osp;

	for(osp=os_info; osp->os_name; osp++) {
	    if((osp->os_flags&OS_SEL) == 0)
		continue;
	    /*
	     * If item on disk, force unload for two reasons:
	     * Forces user to preserve files he/she doesn't want
	     * overwritten, and to make things clean in case item
	     * is being loaded via symbolic links.
	     */
	    if((com == LOAD) && (*osp->os_func)(LIST, osp) == YES) {
		printf("\n****** UNLOADING (%s) ******\n", osp->os_name);
		(*osp->os_func)(UNLOAD, osp);
		sync();
		chngdir("/.setup");
	    }
	    printf("\n****** %s (%s) ******\n",
		(com==LOAD) ? "LOADING" : "UNLOADING", osp->os_name);
	    sprintf(gs_txerr, "TAR extract of %s files", osp->os_name);
	    (*osp->os_func)(com, osp);	/* call f_????? to do actual work */
	    chngdir("/.setup");	/* always want to end up in /.setup directory */
	    sync();		/* can't hert */
	    /*
	     * If command was LOAD, and loading from RL02/RC25
	     * must dismount the tar image file system from /mnt.
	     * Device name loaded into `ddfile' in ddopen().
	     */
	    if((com == LOAD) && (ld_tape == NO) && (ld_rx50 == NO)) {
		if(umount(ddfile) != 0) {
		    printf("\nWARNING: dismount of distribution disk ");
		    printf("from /mnt directory failed!\n");
		}
	    }
	}
}

dolist()
{
	register struct os_info *osp;

	printf("\nItem    # K- On-  Load  Item");
	printf("\nName    Byte Disk Dir.  Description");
	printf("\n------- ---- ---- ----  -----------");
	printf("-----------------------------------");
	for(osp=os_info; osp->os_name; osp++) {
	    if((osp->os_flags&OS_SEL) == 0)
		continue;
	    printf("\n%-7s %4d ", osp->os_name, osp->os_size);
	    printf("%4s ", ((*osp->os_func)(LIST, osp) == YES) ? "yes" : "no");
	    printf("%4s  ", (osp->os_filsys == ROOT) ? "ROOT" : "/USR");
	    printf("%s", osp->os_desc1);
	    if(osp->os_desc2)
		printf("\n\t\t\t%s", osp->os_desc2);
	}
	printf("\n");
}

pmsg(str)
char	**str;
{
	register int i;

	for(i=0; str[i]; i++)
		printf("\n%s", str[i]);
}

/*
 * Print a help message.
 * Call setup_help and pass along the message name.
 */

phelp(str)
char	*str;
{
	register int i;

	i = fork();
	if(i == -1) {
	    printf("\nCan't call setup_help (fork failed)!\n");
	    return;
	}
	if(i == 0) {
	    execl("/.setup/setup_help", "setup_help", str, (char *)0);
	    exit();
	}
	while(wait(0) != -1) ;
}

char	*yn_err = "\nPlease answer yes or no ? ";
#define	YNLSIZE	10
char	yn_line[YNLSIZE];

yes(hlp)
{
	register int i;

	while(1) {
	    fflush(stdout);
	    for(i=0; i<YNLSIZE; i++) {
		yn_line[i] = getchar();
		if(yn_line[i] == '\n') {
			yn_line[i] = '\0';
			break;
		}
	    }
	    if(i > 4) {
		printf("%s", yn_err);
		continue;
	    }
	    if((strcmp(yn_line, "yes") == 0) || (strcmp(yn_line, "y") == 0))
		return(YES);
	    else if((strcmp(yn_line, "no") == 0) || (strcmp(yn_line, "n") == 0))
		return(NO);
	    else if((hlp == YHELP) &&
		    ((yn_line[0] == '?') ||
		     (strcmp(yn_line, "help") == 0) ||
		     (strcmp(yn_line, "h") == 0)))
			return(HELP);
	    else
		printf("%s", yn_err);
	}
}

/*
 * Get a line of text from the terminal,
 * replace the newline with a NULL.
 * Return the string length (not counting the NULL).
 * Use glbuf[] as the buffer and GLBSIZE as limit.
 * If ? or help is typed, print the help message, if
 * one is available, appologize if not. Return -1 after help.
 */

char	*badline = "\n\7\7\7Bad input line, please try again!\n";

gline(hlp)
char	*hlp;
{
	register int cc, ovflow;

	ovflow = 0;
	fflush(stdout);
	while(1) {
	    glbuf[0] = '\0';
	    if(fgets(&glbuf, LBSIZE, stdin) == NULL) {
		printf("%s", badline);
		return(-1);	/* reprint message */
	    }
	    for(cc=0; glbuf[cc]; cc++) ;
	    if((cc == 0) || (glbuf[0] == '\n'))
		return(0);	/* cause question to be reprinted */
	    if(glbuf[cc-1] != '\n') {	/* line too long */
		ovflow++;
		continue;
	    }
	    if(ovflow) {
		printf("\nLine too long, please try again!\n");
		return(-1);
	    }
	    cc--;
	    glbuf[cc] = '\0';
	    if((glbuf[0] == '?') || (strcmp("help", glbuf) == 0)) {
		if(hlp)
			phelp(hlp);
		else
			printf("\nSorry no additional help available!\n");
		return(-1);
	    }
	    return(cc);
	}
}

getline(buf)
char	*buf;
{
	register int i;

	for(i=0; i<LBSIZE; i++) {
		buf[i] = getchar();
		if((buf[i] >= 'A') && (buf[i] <= 'Z'))
			buf[i] |= 040;	/* force lower case */
		if(buf[i] == '\n')
			break;
	}
	if(i >= LBSIZE) {
		while((buf[i] = getchar()) != '\n') ;
		printf("\nLine length exceeded - truncating line!\n");
	}
	return(i+1);
}

getlist(com)
char	*com;
{
	register int i;
	char	*p;
	char	c;

	if(args[0])
		return;	/* items were specified with command */
	printf("\nPlease enter a list of items to ");
	switch(com) {
	case LOAD:
		printf("LOAD");
		break;
	case UNLOAD:
		printf("UNLOAD");
		break;
	}
	printf(" (? for help).\n");
	/* args[] already zeroed by command parser */
	while(1) {
	    argp = 0;
	    printf("\nList: ");
	    if(getline(line) == 1)
		continue;
	    if(line[0] == '?') {
		phelp("h_glist");
		continue;
	    }
	    i = 0;
	    while(line[i] == ' ')
		i++;
	    if(line[i] == '\n')
		continue;
	    p = &line[i];
	    for(; i<LBSIZE; i++) {
		if((line[i] != ' ') && (line[i] != '\n'))
		    continue;
		c = line[i];
		line[i] = 0;
		if(argp >= NARG) {
		    printf("\nItem buffer full, truncating line\n");
		    break;
		}
		args[argp++] = p;
		while(line[++i] == ' ') ;
		if((c == '\n') || (line[i] == '\n'))
		    break;
		p = &line[i];
	    }
	    break;
	}
}

/*
 * Check list of optional software items.
 *	Validates the name of each OS item.
 *	Sets the OS_SEL flag for each valid item.
 *	All means load/unload all items.
 */

char	cl_buf[100];

chklist(com)
{
	register struct os_info *osp;
	register int ap;
	char	*p;
	int	cnt;

	switch(com) {
	case LIST:
		p = "LIST";
		break;
	case LOAD:
		p = "LOAD";
		break;
	case UNLOAD:
		p = "UNLOAD";
		break;
	default:
		p = "????";
		break;
	}
	if(args[0] == 0) {
	    if(com == LIST) {
		for(osp=os_info; osp->os_name; osp++)
		    osp->os_flags |= OS_SEL;
		return(0);
	    }
	    printf("\n%s: item list empty!\n", p);
	    return(1);
	}
	ap = -1;
	while(1) {
	    if(args[++ap] == 0)
		return(0);
	    if(strcmp("all", args[ap]) == 0) {	/* list = all */
		cnt = 0;
		for(osp=os_info; osp->os_name; osp++) {
		    if((com == UNLOAD) || (com == LIST)) {
			osp->os_flags |= OS_SEL;
			cnt++;
			continue;
		    }
		    if((*osp->os_func)(LIST, osp) == NO) {
			osp->os_flags |= OS_SEL;
			cnt++;
		    } else {
			printf("\n(%s) already loaded: ", osp->os_name);
			printf("must unload first!\n");
		    }
		}
		if(cnt == 0)
		    return(1);	/* nothing to load */
		continue;
	    }
	    sprintf(&cl_buf, "%s", args[ap]);
	    while(1) {
		for(osp=os_info; osp->os_name; osp++)
		    if(strcmp(&cl_buf, osp->os_name) == 0)
			break;
		if(osp->os_name == 0) {
		    printf("\n\7\7\7%s: %s - not a valid item!\n", p, &cl_buf);
		    printf("\nPlease enter a valid item or press <RETURN> ");
		    printf("to skip this item.\n");
		    printf("\nItem: ");
		    if(gline(NOHELP) == 0) {
			break;
		    } else {
			sprintf(&cl_buf, "%s", &glbuf);
			continue;
		    }
		} else {
		    osp->os_flags |= OS_SEL;
		    break;
		}
	    }
	}
}

/*
 * Ask the user if any symbolic links are needed.
 * If so, get home directory name and save it in the
 * os_info.os_slink[] array.
 *
 * Default answers enclosed in [ ], user presses <RETURN> to take default.
 * Default base directory name is last used name (if there is one).
 */

sblink()
{
	register struct os_info *osp;
	register struct os_info *lastosp;
	register int i;
	char	*p;
	int	cnt, cc;
	int	linkit;

	/*
	 * Count number of items selected for loading.
	 * If none of them can be loaded via symbolic links, return.
	 */
	for(cnt=0, osp=os_info; osp->os_name; osp++)
	    if((osp->os_flags&OS_SEL) && (osp->os_filsys != ROOT))
		cnt++;
	if(cnt == 0)
	    return;
	while(1) {
	    if(cnt == 1)
		break;
	    printf("\nLoad any items with symbolic links (? for help)");
	    printf(" <y or n> ? ");
	    i = yes(YHELP);
	    if(i == HELP) {
		phelp("h_rsl");
		continue;
	    }
	    if(i == NO)
		return;
	    else
		break;
	}
	lastosp = 0;
	for(osp=os_info; osp->os_name; osp++) {
	    if((osp->os_flags&OS_SEL) == 0)
		continue;
	    if(osp->os_filsys == ROOT)
		continue;
	    while(1) {
		linkit = NO;
		do {
		    printf("\nLoad (%s) with symbolic links ", osp->os_name);
		    printf("(? for help) <y or n> ? ");
		} while((cc = gline("h_rsl")) <= 0);
		if((strcmp("n", &glbuf) == 0) || (strcmp("no", &glbuf) == 0))
		    break;
		if((strcmp("y", &glbuf) == 0) || (strcmp("yes", &glbuf) == 0)) {
		    linkit = YES;
		    break;
		}
		/* INVALID RESPONSE, continue (ask question again) */
	    }
	    if(linkit != YES)
		continue;
	    while(1) {
		do {
		    printf("\nSymbolic link base directory ");
		    if(lastosp)
			printf("(Press <RETURN> if %s): ",
			    &lastosp->os_slink);
		    else
			printf("(? for help): ");
		} while((cc = gline("h_rsld")) < 0);
		if(cc == 0) {	/* user typed <RETURN> for default directory */
		    if(lastosp)
			sprintf(&glbuf, "%s", &lastosp->os_slink);
		    else
			continue;
		}
		if(glbuf[0] == '/')
		    p = &glbuf[1];
		else
		    p = &glbuf[0];
		if(strlen(p) > DIRSIZ) {
		    printf("\nMaximum directory name length is %d characters!\n",
			DIRSIZ);
		    continue;
		}
		sprintf(&osp->os_slink, "/%s", p);
		p = &osp->os_slink;
		if(stat(p, &statb) < 0) {
		    printf("\nCan't stat %s - directory does not exist!\n", p);
		    continue;
		}
		if((statb.st_mode&S_IFMT) != S_IFDIR) {
		    printf("\n%s - is not a directory!\n", p);
		    continue;
		}
		osp->os_flags |= OS_SYM;
		lastosp = osp;	/* save last used base directory name */
		break;
	    }
	}
}

retry(str)
char	*str;
{
	printf("\n%s FAILED: ", str);
	printf("Try again <y or n> ? ");
	if(yes(NOHELP) == YES)
	    return(1);
	 else
	    return(0);
}

/*
 * Try to clean up the mess if the user
 * type <CTRL/C>.
 */

cleanup()
{
	signal(SIGINT, cleanup);
	chdir("/.setup");
	printf("\n");
	longjmp(savej, 1);
}

dosystem(cmd)
char	*cmd;
{
	register int s;

	s = system(cmd);
/*	if((s == SIGINT) || (s == 01400))	*/
	if((s & 0377) == SIGINT)
		cleanup();
	else
		return(s);
}


xit(s)
{
	if(cbsetup == NO) {
	    printf("\n\n\7\7\7OSLOAD: following file systems remain mounted!\n\n");
	    system("/etc/mount");
	    printf("\nIf the system is in single-user mode, you should");
	    printf("\nexecute \"/etc/umount -a\" before going multiuser.");
	}
	printf("\n");
	exit(s);
}

/*
 * Open the distribution device, the close it.
 * Print an error message and ask the user if we
 * should retry, if the open fails.
 * If the load device is magtape,
 * this has a side effect of rewinging the tape.
 * If the distribution device is magtape, use the dd
 * command to position the tape at the proper tar image.
 *
 * files - number of tape files to skip.
 * loadev - magtape file name (rmt0 for 800 BPI, rht0 for 1600 BPI).
 * ld_tape - load device is (is not) magtape.
 */

ddopen(osp, flop)
register struct os_info *osp;
char	*flop;
{
	register int i;

	sprintf(ddfile, "/dev/%s", loadev);
	while(1) {
	    if(ld_rx50 == YES)
		iflop(flop);
/* TODO: need to verify correct diskette inserted! */
	    if((i = open(ddfile, 0)) >= 0)	/* rewind the tape */
		close(i);
	    else {
		if(retry("Open of distribution device"))
		    continue;
		else
		    longjmp(savej, 1);	/* go back to command prompt */
	    }
	    break;
	}
	if(ld_rx50 == YES)
	    return;
	if(ld_tape == NO) {	/* must be loading from RL02/RC25 */
				/* mount rc04 or rl07/rl17 read only */
	    sprintf(ddfile, "/dev/%s", &loadev[1]);
	    /*
	     * The umount is in case this is an error retry,
	     * the disk may already be mounted!
	     * Don't care if the umount fails!
	     */
	    umount(ddfile);
	    while(1) {
		if(mount(ddfile, "/mnt", 1) != 0) {
		    if(retry("Mount of distribution disk on /mnt directory"))
			continue;
		    else
			longjmp(savej, 1);	/* go back to command prompt */
		}
		break;
	    }
	    return;
	}
	sprintf(mtscmd,
	    "dd if=/dev/n%s of=/dev/null bs=20b files=%d > /dev/null 2>&1",
	    loadev, osp->os_offset);
	system(mtscmd);
}

/*
 * Set up the tar command used to load optional software.
 *
 * The tar command is created in three steps:
 *
 * 1.	This routine writes the basic tar command string into syscmd[].
 *	The files are extracted from the raw device when loading from
 *	magtape or RX50 diskettes. If the load device is RC25/RL02, the
 *	files are extracted from a file system on the load media thru a pipe.
 *
 * 2.	The f_??() load function appends the file/directory names, to be
 *	extracted from the load media, to the tar command string in syscmd[].
 *
 * 3.	If the load media is RC25/RL02, this routine completes the tar command
 *	string in syscmd[], other wise it just returns.
 *
 * tarcs(op, osp)
 *
 *	op  - TCSTART = load the basic tar command string.
 *	op  - TCEND   = end the tar command string (if load dev is RL/RC).
 *
 *	osp - Optional software load info structure pointer.
 */

tarcs(op, osp)
int	op;
register struct os_info *osp;
{
	char	p[50];

	if(op == TCSTART) {
	    if((ld_tape == YES) || (ld_rx50 == YES))
		sprintf(syscmd, "tar xpbf 20 /dev/%s", loadev);
	    else
		sprintf(syscmd, "cd /mnt/%s; tar cf -", osp->os_tarfs);
	} else {
	    if((ld_tape == NO) && (ld_rx50 == NO)) {
		if(osp->os_filsys == ROOT) {
		    strcat(syscmd, " | (cd /; tar xpf -)");
		} else {
		    sprintf(&p, " | (cd %s; tar xpf -)",
			osp->os_flags&OS_SYM ? (char *)&osp->os_slink : "/usr");
		    strcat(syscmd, &p);
		}
	    }
/*	    printf("\nDEBUG: %s\n", syscmd);	*/
	}
}

/*
 * The following functions (f_?????()) do the
 * actual loading/unloading of optional software.
 * They are called from doload() via their address
 * being in the os_info structure.
 *
 * osp - pointer into os_info[] structure.
 * com - command being executed.
 *	 LOAD = load optional software item.
 *	 UNLOAD = unload item (just what we loaded).
 *	 LIST = list items (best guess if item loaded or not).
 */

char	*l_dict[] =
{
	"/usr/dict/words",
	"/usr/dict/american",
	"/usr/dict/british",
	"/usr/dict/stop",
	0
};

f_dict(com, osp)
register struct os_info *osp;
{
	register int i;

	if(com == LIST) {
	    for(i=0; l_dict[i]; i++)
		if(lstat(l_dict[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_dict[i]; i++)
		rmfile(l_dict[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "dict"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd,
" ./dict/words ./dict/american ./dict/british ./dict/stop ");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		/* NO SYMBOLIC LINK FOR local */
		dosystem("touch /usr/dict/local");
		chown("/usr/dict/local", 3, 3);
		chmod("/usr/dict/local", 0666);
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for DICTIONARY files.\n", sl_make);
		for(i=0; l_dict[i]; i++)
		    mslink(osp, l_dict[i]);
	    }
	}
}

char	*l_docprep[] =
{
	"/usr/bin/checkmm",
	"/usr/bin/mm",
	"/usr/bin/mmt",
	"/usr/bin/mvt",
	"/usr/bin/osdd",
	"/usr/bin/refer",
	"/usr/bin/tbl",
	"/usr/bin/eqn",
	"/usr/bin/neqn",
	"/usr/bin/checkeq",
	"/usr/bin/roff",
	"/usr/bin/troff",
	"/usr/bin/nroff",
	"/usr/lib/help/term",
	"/usr/lib/help/text",
	"/usr/lib/suftab",
	"/usr/lib/refer/inv",
	"/usr/lib/refer/mkey",
	"/usr/lib/refer/hunt",
	"/usr/dict/papers/Ind.ia",
	"/usr/dict/papers/Ind.ib",
	"/usr/dict/papers/Ind.ic",
	"/usr/dict/papers/Rv7man",
	"/usr/dict/papers/runinv",
	0
};

char	*d_docprep[] =
{
	"/usr/lib/tmac",
	"/usr/lib/macros",
	"/usr/lib/me",
	"/usr/lib/ms",
	"/usr/lib/font",
	"/usr/lib/term",
	0
};

f_docprep(com, osp)
register struct os_info *osp;
{
	register int fatal, i;

	if(com == LIST) {
	    for(i=0; l_docprep[i]; i++)
		if(lstat(l_docprep[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_docprep[i]; i++)
		rmfile(l_docprep[i]);
	    printf("\n\7\7\7");
	    printf("Following directories (and all files) will be removed:\n\n");
	    for(i=0; d_docprep[i]; i++)
		printf("\t%s\n", d_docprep[i]);
	    printf("\nFILES: user macro packages, local modifications or files.\n");
	    usfiles(MULTI);
	    for(i=0; d_docprep[i]; i++)
		rmdirf(d_docprep[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		if(msdir(osp, "lib/help"))
		    return;
		if(msdir(osp, "lib/refer"))
		    return;
		if(msdir(osp, "dict"))
		    return;
		if(msdir(osp, "dict/papers"))
		    return;
		sync();
		for(i=0; d_docprep[i]; i++) {
		    printf("\n%s: %s -> %s%s\n", sl_make, d_docprep[i],
			&osp->os_slink, &d_docprep[i][4]);
		    msdir1(osp, &d_docprep[i][5]);
		    sprintf(&syscmd, "chog bin %s%s",
			&osp->os_slink, &d_docprep[i][4]);
		    dosystem(syscmd);
		    sprintf(&syscmd, "chmod 755 %s%s",
			&osp->os_slink, &d_docprep[i][4]);
		    dosystem(syscmd);
		    if(mslink(osp, d_docprep[i]))
			return;
		}
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd,
" ./bin/eqn ./bin/neqn ./bin/checkeq ./bin/roff ./bin/nroff ./bin/troff");
	    strcat(syscmd,
" ./bin/checkmm ./bin/mm ./bin/mmt ./bin/mvt ./bin/osdd");
	    if(cputyp[tpi].p_sid == SID)
		strcat(syscmd, " ./bin/tbl70");
	    else
		strcat(syscmd, " ./bin/tbl40");
	    if(cputyp[tpi].p_sid == SID)
		strcat(syscmd, " ./bin/refer70");
	    else
		strcat(syscmd, " ./bin/refer40");
	    if(ld_rx50 == NO) {
		strcat(syscmd, " ./dict/papers");
		strcat(syscmd, " ./lib/help/term ./lib/help/text");
		strcat(syscmd, " ./lib/suftab");
		strcat(syscmd,
		    " ./lib/font ./lib/tmac ./lib/ms ./lib/me ./lib/term");
		strcat(syscmd, " ./lib/macros");
		strcat(syscmd, " ./lib/refer/inv ./lib/refer/mkey");
		if(cputyp[tpi].p_sid == SID)
		    strcat(syscmd, " ./lib/refer/hunt70");
		else
		    strcat(syscmd, " ./lib/refer/hunt40");
	    }
	    fatal = 0;
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else {
			fatal++;
			break;
		    }
		}
		break;
	    }
	    if(fatal)
		return;
	    if(ld_rx50 == YES) {
		rflop(osp->os_flop);
		tarcs(TCSTART, osp);
		if(cputyp[tpi].p_sid == SID)
		    strcat(syscmd, " ./lib/refer/hunt70");
		else
		    strcat(syscmd, " ./lib/refer/hunt40");
		strcat(syscmd, " ./dict/papers");
		strcat(syscmd, " ./lib/refer/inv ./lib/refer/mkey");
		strcat(syscmd, " ./lib/help/term ./lib/help/text");
		strcat(syscmd, " ./lib/suftab");
		strcat(syscmd,
		    " ./lib/font ./lib/tmac ./lib/ms ./lib/me ./lib/term");
		tarcs(TCEND, osp);
		fatal = 0;
		while(1) {
		    ddopen(osp, "DOCPREP #2");
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else {
			    fatal++;
			    break;
			}
		    }
		    break;
		}
		if(fatal)
		    return;
		rflop("DOCPREP #2");
		tarcs(TCSTART, osp);
		strcat(syscmd, " ./lib/macros");
		tarcs(TCEND, osp);
		fatal = 0;
		while(1) {
		    ddopen(osp, "DOCPREP #3");
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else {
			    fatal++;
			    break;
			}
		    }
		    break;
		}
		if(fatal)
		    return;
	    }
	    if(chngdir("./bin"))
		return;
	    if(cputyp[tpi].p_sid == SID) {
		 dosystem("mv tbl70 tbl");
		 dosystem("mv refer70 refer");
		 if(chngdir("../lib/refer"))
		    return;
		 dosystem("mv hunt70 hunt");
	    } else {
		dosystem("mv tbl40 tbl");
		dosystem("mv refer40 refer");
		if(chngdir("../lib/refer"))
		    return;
		dosystem("mv hunt40 hunt");
	    }
	    dosystem("chog bin hunt");
	    chmod("hunt", 0755);
	    if(chngdir("../../bin"))
		return;
	    dosystem("chog bin tbl refer");
	    chmod("tbl", 0755);
	    chmod("refer", 0755);
	    if(ld_rx50 == YES)
		rflop("DOCPREP #3");
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for DOCPREP files.\n", sl_make);
		for(i=0; l_docprep[i]; i++)
		    mslink(osp, l_docprep[i]);
	    }
	}
}

char	*l_f77[] =
{
	"/usr/bin/f77",
	"/usr/lib/f77_strings",
	"/usr/lib/f77pass1",
	"/usr/lib/libF77.a",
	"/usr/lib/libI77.a",
	"/usr/lib/libU77.a",
	"/usr/bin/ratfor",
	"/usr/bin/struct",
	"/usr/lib/struct/structure",
	"/usr/lib/struct/beautify",
	0
};

f_f77(com, osp)
register struct os_info *osp;
{
	register int fatal, i;

	if(com == LIST) {
	    for(i=0; l_f77[i]; i++)
		if(lstat(l_f77[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_f77[i]; i++)
		rmfile(l_f77[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		if(msdir(osp, "lib/struct"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd,
" ./bin/f77 ./bin/ratfor ./lib/f77_strings ./lib/libF77.a ./lib/libI77.a ");
	    strcat(syscmd, "./lib/libU77.a ");
	    if(ld_rx50 == NO)
		strcat(syscmd, "./bin/struct ./lib/struct/beautify ");
	    if(cputyp[tpi].p_sid == SID)
		strcat(syscmd, "./lib/f77pass1id");
	    else
		strcat(syscmd, "./lib/f77pass1ov");
	    if(ld_rx50 == NO) {
		if(cputyp[tpi].p_sid == SID)
		    strcat(syscmd, " ./lib/struct/structure70");
		else
		    strcat(syscmd, " ./lib/struct/structure40");
	    }
	    fatal = 0;
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else {
			fatal++;
			break;
		    }
		}
		break;
	    }
	    if(fatal)
		return;
	    if(ld_rx50 == YES) {
		rflop(osp->os_flop);
		printf("\nLoading remainder of F77 from USAT diskette.\n");
		tarcs(TCSTART, osp);
		strcat(syscmd, " ./bin/struct ./lib/struct/beautify");
		if(cputyp[tpi].p_sid == SID)
		    strcat(syscmd, " ./lib/struct/structure70");
		else
		    strcat(syscmd, " ./lib/struct/structure40");
		tarcs(TCEND, osp);
		fatal = 0;
		while(1) {
		    ddopen(osp, "USAT");
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else {
			    fatal++;
			    break;
			}
		    }
		    break;
		}
		if(fatal)
		    return;
	    }
	    if(cputyp[tpi].p_sid == SID) {
		dosystem("mv ./lib/f77pass1id ./lib/f77pass1");
		dosystem("mv ./lib/struct/structure70 ./lib/struct/structure");
	    } else {
		dosystem("mv ./lib/f77pass1ov ./lib/f77pass1");
		dosystem("mv ./lib/struct/structure40 ./lib/struct/structure");
	    }
	    chmod("./lib/f77pass1", 0775);
	    dosystem("chog bin ./lib/f77pass1");
	    chmod("./lib/struct/structure", 0775);
	    dosystem("chog bin ./lib/struct/structure");
	    if(ld_rx50 == YES)
		rflop("USAT");
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for F77 files.\n", sl_make);
		for(i=0; l_f77[i]; i++)
		    mslink(osp, l_f77[i]);
	    }
	}
}

f_games(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat("/usr/games", &lstatb) >= 0)
		return(YES);
/* TODO: remove after debug
	    if(chdir("/usr/games") < 0)
		return(NO);
	    if(lstat("fortune", &lstatb) >= 0)
		return(YES);
	    if(lstat("chess", &lstatb) >= 0)
		return(YES);
	    if(lstat("ttt", &lstatb) >= 0)
		return(YES);
	    if(lstat("wump", &lstatb) >= 0)
		return(YES);
	    if(lstat("quiz", &lstatb) >= 0)
		return(YES);
*/
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/games directory (and all files) will be removed!\n");
	    printf("\nFILES: any of your own games programs.\n");
	    usfiles(MULTI);
	    rmdirf("/usr/games");
	} else {
	    if(osp->os_flags&OS_SYM) {
		printf("\n%s: /usr/games -> %s/games\n",
		    sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		msdir1(osp, "games");
		dosystem("chmod 755 games");
		dosystem("chog bin games");
		if(mslink(osp, "/usr/games"))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./games");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	}
}

char	*l_userdev[] =
{
	"/usr/src/userdev",
	0
};

f_userdev(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat(l_userdev[0], &lstatb) >= 0)
		return(YES);
/* TODO: remove after debug
	    if(chdir(l_userdev[0]) < 0)
		return(NO);
	    if(lstat("u1.c", &lstatb) >= 0)
		return(YES);
	    if(lstat("if_n1.c", &lstatb) >= 0)
		return(YES);
	    if(lstat("userdev.doc", &lstatb) >= 0)
		return(YES);
	    if(lstat("rs04_driver.c", &lstatb) >= 0)
		return(YES);
*/
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The %s directory (and all files) ", l_userdev[0]);
	    printf("will be removed!\n");
	    printf("\nFILES: user device driver sources (*.c) and ");
	    printf("documentation (*.doc).\n");
	    usfiles();
	    rmdirf(l_userdev[0]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "src"))
		    return;
		printf("\n%s: %s -> %s/src/userdev\n",
		    sl_make, l_userdev[0], &osp->os_slink);
		msdir1(osp, "src/userdev");
		sprintf(&syscmd, "chmod 755 %s/src/userdev", &osp->os_slink);
		dosystem(syscmd);
		sprintf(&syscmd, "chog bin %s/src/userdev", &osp->os_slink);
		dosystem(syscmd);
		if(mslink(osp, l_userdev[0]))
		    return;
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./src/userdev");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		printf("\nUnpacking files in %s...\n", l_userdev[0]);
		if(chngdir("src/userdev"))
		    break;
		dosystem("unpack * >/dev/null 2>&1");
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	}
}

f_learn(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat("/usr/bin/learn", &lstatb) >= 0)
		return(YES);
	    if(lstat("/usr/lib/learn", &lstatb) >= 0)
		return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/lib/learn directory (and all files) ");
	    printf("will be removed!\n");
	    printf("\nFILES: log files and any local modifications or files.\n");
	    usfiles(MULTI);
	    rmfile("/usr/bin/learn");
	    rmdirf("/usr/lib/learn");
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		sync();
		printf("\n%s: /usr/bin/learn -> %s/bin/learn\n",
		    sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		if(chngdir("bin"))
		    return;
		dosystem("touch learn");
		dosystem("chog bin learn");
		dosystem("chmod 755 learn");
		if(mslink(osp, "/usr/bin/learn"))
		    return;
		printf("\n%s: /usr/lib/learn -> %s/lib/learn\n",
		    sl_make, &osp->os_slink);
		if(chngdir("../lib"))
		    return;
		msdir1(osp, "lib/learn");
		dosystem("chmod 777 learn");
		dosystem("chog bin learn");
		if(mslink(osp, "/usr/lib/learn"))
		    return;
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    if(ld_rx50 == YES) {
		r_learn(osp);
		return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd," ./bin/learn ./lib/learn");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		break;
	    }
	}
}

r_learn(osp)
register struct os_info *osp;
{
	register int fatal;

	fatal = 0;
	ddopen(osp, osp->os_flop);
	sprintf(syscmd, "/dev/rx%d", rxunit);
	while(1) {
	    if(mount(syscmd, "/mnt", 1) != 0) {
		if(retry("Mount of LEARN #1 diskette on /mnt directory"))
		    continue;
		else {
		    fatal++;
		    break;
		}
	    }
	    break;
	}
	while(1) {
	    if(fatal)
		break;
	    else
		fatal = 1;
	    if(chngdir("/usr/bin"))
		break;
	    dosystem("cp /mnt/learn learn");
	    dosystem("chog bin learn");
	    chmod("learn", 0755);
	    if((osp->os_flags&OS_SYM) == 0) {
		if(chngdir("/usr/lib"))
		    break;
		makedir("learn");
		dosystem("chog bin learn");
		chmod("learn", 0777);
	    }
	    if(chngdir("/usr/lib/learn"))
		break;
	    dosystem("cp /mnt/Linfo /mnt/Xinfo .");
	    dosystem("chog bin Linfo Xinfo");
	    chmod("Linfo", 0644);
	    chmod("Xinfo", 0644);
	    makedir("log");
	    makedir("play");
	    dosystem("chog bin log play");
	    dosystem("chmod 777 log play");
	    makedir("C");
	    dosystem("chog bin C");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("C", 0755);
	    if(chngdir("C"))
		break;
	    dosystem("ar x /mnt/C.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    makedir("editor");
	    dosystem("chog bin editor");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("editor", 0755);
	    if(chngdir("editor"))
		break;
	    dosystem("ar x /mnt/editor.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    fatal = 0;
	    break;
	}
	umount(syscmd);
	rflop(osp->os_flop);
	if(fatal)
	    return;
	ddopen(osp, "LEARN #2");
	while(1) {
	    if(mount(syscmd, "/mnt", 1) != 0) {
		if(retry("Mount of LEARN #2 diskette on /mnt directory"))
		    continue;
		else {
		    fatal++;
		    break;
		}
	    }
	    break;
	}
	while(1) {
	    if(fatal)
		break;
	    else
		fatal = 1;
	    if(chngdir("/usr/lib/learn"))
		break;
	    dosystem("cp /mnt/lcount /mnt/tee .");
	    dosystem("chog bin lcount tee");
	    chmod("lcount", 0755);
	    chmod("tee", 0755);
	    makedir("eqn");
	    dosystem("chog bin eqn");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("eqn", 0755);
	    if(chngdir("eqn"))
		break;
	    dosystem("ar x /mnt/eqn.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    makedir("vi");
	    dosystem("chog bin vi");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("vi", 0755);
	    if(chngdir("vi"))
		break;
	    dosystem("ar x /mnt/vi.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    makedir("files");
	    dosystem("chog bin files");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("files", 0755);
	    if(chngdir("files"))
		break;
	    dosystem("ar x /mnt/files.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    makedir("macros");
	    dosystem("chog bin macros");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("macros", 0755);
	    if(chngdir("macros"))
		break;
	    dosystem("ar x /mnt/macros.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    makedir("morefiles");
	    dosystem("chog bin morefiles");
/* TODO: tape mode may be wrong (775 s/b 755) */
	    chmod("morefiles", 0755);
	    if(chngdir("morefiles"))
		break;
	    dosystem("ar x /mnt/morefiles.a");
	    dosystem("chog bin *");
	    dosystem("chmod 644 *");
	    if(chngdir(".."))
		break;
	    fatal = 0;
	    break;
	}
	umount(syscmd);
	rflop("LEARN #2");
}

char	*l_libsa[] =
{
	"/usr/lib/libsa.a",
	0
};

f_libsa(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat(l_libsa[0], &lstatb) >= 0)
		return(YES);
	    else
		return(NO);
	} else if(com == UNLOAD) {
	    rmfile(l_libsa[0]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "lib"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./lib/libsa.a");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%s: %s -> %s/lib/libsa.a\n",
		    sl_make, l_libsa[0], &osp->os_slink);
		mslink(osp, l_libsa[0]);
	    }
	}
}

char	*l_plot[] =
{
	"/usr/bin/plot",
	"/usr/bin/tk",
	"/usr/bin/tek",
	"/usr/bin/tla50",
	"/usr/bin/tla100",
	"/usr/bin/tregis",
	"/usr/bin/t300",
	"/usr/bin/t300s",
	"/usr/bin/t450",
	"/usr/bin/vplot",
	"/usr/lib/libtla50.a",
	"/usr/lib/libtla100.a",
	"/usr/lib/libtregis.a",
	"/usr/lib/libtgigi.a",
	"/usr/lib/libt300.a",
	"/usr/lib/libt300s.a",
	"/usr/lib/libt4014.a",
	"/usr/lib/libt450.a",
	"/usr/lib/libplot.a",
	0
};

f_plot(com, osp)
register struct os_info *osp;
{
	register int i;

	if(com == LIST) {
	    for(i=0; l_plot[i]; i++)
		if(lstat(l_plot[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_plot[i]; i++)
		rmfile(l_plot[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd,
" ./bin/plot \
./bin/tk \
./bin/tek \
./bin/tla50 \
./bin/tla100 \
./bin/tregis \
./bin/t300 \
./bin/t300s \
./bin/t450 \
./bin/vplot ");
	    strcat(syscmd,
"./lib/libtla50.a \
./lib/libtla100.a \
./lib/libtgigi.a \
./lib/libtregis.a \
./lib/libt300.a \
./lib/libt300s.a \
./lib/libt4014.a \
./lib/libt450.a \
./lib/libplot.a");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for PLOT files.\n", sl_make);
		for(i=0; l_plot[i]; i++)
		    mslink(osp, l_plot[i]);
	    }
	}
}

f_saprog(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat("/sas/syscall", &lstatb) >= 0)
		return(YES);
	    else
		return(NO);
	} else if(com == UNLOAD) {
	    unlink("/sas/bads");
	    unlink("/sas/rabads");
	    unlink("/sas/copy");
	    unlink("/sas/dskinit");
	    unlink("/sas/icheck");
	    unlink("/sas/mkfs");
	    unlink("/sas/restor");
	    unlink("/sas/scat");
	    unlink("/sas/syscall");
	} else {
	    if(ld_rx50 == YES) {
		r_saprog(osp);
		return;
	    }
	    if(chngdir("/"))
		return;
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd,
" ./sas/bads \
./sas/rabads \
./sas/copy \
./sas/dskinit \
./sas/icheck \
./sas/mkfs \
./sas/restor \
./sas/scat \
./sas/syscall");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		break;
	    }
	}
}

r_saprog(osp)
register struct os_info *osp;
{
	register int fatal;

	fatal = 0;
	ddopen(osp, osp->os_flop);
	sprintf(syscmd, "/dev/rx%d", rxunit);
	while(1) {
	    if(mount(syscmd, "/mnt", 1) != 0) {
		if(retry("Mount of BOOT diskette on /mnt directory"))
		    continue;
		else {
		    fatal++;
		    break;
		}
	    }
	    break;
	}
	while(1) {
	    if(fatal)
		break;
	    if(chngdir("/mnt"))
		break;
	    dosystem("cp bads rabads copy dskinit icheck mkfs /sas");
	    dosystem("cp restor scat syscall /sas");
	    dosystem("chmod 644 /sas/*");
	    chngdir("/");
	    break;
	}
	umount(syscmd);
	rflop(osp->os_flop);
}

char	*l_sccs[] =
{
	"/usr/bin/admin",
	"/usr/bin/bdiff",
	"/usr/bin/cdc",
	"/usr/bin/comb",
	"/usr/bin/delta",
	"/usr/bin/get",
	"/usr/bin/sccshelp",
	"/usr/bin/prs",
	"/usr/bin/prt",
	"/usr/bin/rmchg",
	"/usr/bin/rmdel",
	"/usr/bin/unget",
	"/usr/bin/val",
	"/usr/bin/vc",
/*	"/usr/bin/what",	(what is part of the base system)	*/
	"/usr/bin/sact",
	"/usr/bin/sccs",
	"/usr/bin/sccsdiff",
	"/usr/lib/help/ad",
	"/usr/lib/help/bd",
	"/usr/lib/help/cb",
	"/usr/lib/help/cm",
	"/usr/lib/help/cmds",
	"/usr/lib/help/co",
	"/usr/lib/help/de",
	"/usr/lib/help/default",
	"/usr/lib/help/ge",
	"/usr/lib/help/he",
	"/usr/lib/help/prs",
	"/usr/lib/help/rc",
	"/usr/lib/help/un",
	"/usr/lib/help/ut",
	"/usr/lib/help/vc",
	0
};

f_sccs(com, osp)
register struct os_info *osp;
{
	register int i;

	if(com == LIST) {
	    for(i=0; l_sccs[i]; i++)
		if(lstat(l_sccs[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_sccs[i]; i++)
		rmfile(l_sccs[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		if(msdir(osp, "lib/help"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd,
" ./bin/admin \
./bin/bdiff \
./bin/cdc \
./bin/comb \
./bin/delta \
./bin/get \
./bin/sccshelp \
./bin/prs \
./bin/prt \
./bin/rmchg \
./bin/rmdel \
./bin/unget \
./bin/val \
./bin/vc \
./bin/sact \
./bin/sccs \
./bin/sccsdiff ");
/* NOTE: /usr/bin/what is now part of the base system! */
	    strcat(syscmd,
" ./lib/help/ad \
./lib/help/bd \
./lib/help/cb \
./lib/help/cm \
./lib/help/cmds \
./lib/help/co \
./lib/help/de \
./lib/help/default \
./lib/help/ge \
./lib/help/he \
./lib/help/prs \
./lib/help/rc \
./lib/help/un \
./lib/help/ut \
./lib/help/vc");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for SCCS files.\n", sl_make);
		for(i=0; l_sccs[i]; i++)
		    mslink(osp, l_sccs[i]);
	    }
	}
}

char	*l_spell[] =
{
	"/usr/bin/spell",
	"/usr/lib/spell",
	"/usr/lib/spellin",
	"/usr/lib/spellout",
	"/usr/dict/hlista",
	"/usr/dict/hlistb",
	"/usr/dict/hstop",
	0
};

f_spell(com, osp)
register struct os_info *osp;
{
	register int i;

	if(com == LIST) {
	    for(i=0; l_spell[i]; i++)
		if(lstat(l_spell[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_spell[i]; i++)
		rmfile(l_spell[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		if(msdir(osp, "dict"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./bin/spell");
	    if(cputyp[tpi].p_sid == SID) {
		strcat(syscmd,
" ./lib/spell70 \
./lib/spellin70 \
./lib/spellout70 \
./dict/hlista70 \
./dict/hlistb70 \
./dict/hstop70");
	    } else {
		strcat(syscmd,
" ./lib/spell40 \
./lib/spellin40 \
./lib/spellout40 \
./dict/hlista40 \
./dict/hlistb40 \
./dict/hstop40");
	    }
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(chngdir("lib"))
		    return;
		if(cputyp[tpi].p_sid == SID) {
		    dosystem("mv spell70 spell");
		    dosystem("mv spellin70 spellin");
		    dosystem("mv spellout70 spellout");
		    if(chngdir("../dict"))
			return;
		    dosystem("mv hlista70 hlista");
		    dosystem("mv hlistb70 hlistb");
		    dosystem("mv hstop70 hstop");
		} else {
		    dosystem("mv spell40 spell");
		    dosystem("mv spellin40 spellin");
		    dosystem("mv spellout40 spellout");
		    if(chngdir("../dict"))
			return;
		    dosystem("mv hlista40 hlista");
		    dosystem("mv hlistb40 hlistb");
		    dosystem("mv hstop40 hstop");
		}
		dosystem("chog bin hlista hlistb hstop");
		dosystem("chmod 0644 hlista hlistb hstop");
		/* NO SYMBOLIC LINK FOR spellhist */
		dosystem("touch /usr/dict/spellhist");
		dosystem("chog bin /usr/dict/spellhist");
		dosystem("chmod 0666 /usr/dict/spellhist");
		if(chngdir("../lib"))
		    return;
		dosystem("chog bin spell spellin spellout");
		dosystem("chmod 0755 spell spellin spellout");
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for SPELL files.\n", sl_make);
		for(i=0; l_spell[i]; i++)
		    mslink(osp, l_spell[i]);
	    }
	}
}

char	*l_pascal[] =
{
	"/usr/bin/pi",
	"/usr/bin/pix",
	"/usr/bin/px",
	"/usr/bin/pxp",
	"/usr/lib/how_pi",
	"/usr/lib/how_pix",
	"/usr/lib/how_pxp",
	"/usr/lib/npx_header",
	"/usr/lib/pi1.2strings",
	0
};

f_pascal(com, osp)
register struct os_info *osp;
{
	register int i, err;

	if(com == LIST) {
	    for(i=0; l_pascal[i]; i++)
		if(lstat(l_pascal[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_pascal[i]; i++)
		rmfile(l_pascal[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./bin/pix ./bin/pxp");
	    if(cputyp[tpi].p_sid == SID) {
		strcat(syscmd, " ./bin/pi70 ./bin/px70");
	    } else {
		strcat(syscmd, " ./bin/pi40 ./bin/px40");
	    }
	    strcat(syscmd,
" ./lib/how_pi ./lib/how_pix ./lib/how_pxp ./lib/npx_header ./lib/pi1.2strings");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(chngdir("bin"))
		    return;
		if(cputyp[tpi].p_sid == SID) {
		    dosystem("mv pi70 pi");
		    dosystem("mv px70 px");
		} else {
		    dosystem("mv pi40 pi");
		    dosystem("mv px40 px");
		}
		dosystem("chog bin pi px");
		dosystem("chmod 755 pi px");
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for PASCAL files.\n", sl_make);
		for(i=0; l_pascal[i]; i++)
		    mslink(osp, l_pascal[i]);
	    }
	}
}

f_sysgen(com, osp)
register struct os_info *osp;
{
	register char *p;
	int	fatal;

	if(com == LIST) {
	    if(lstat("/usr/sys", &lstatb) >= 0)
		return(YES);
/* TODO: remove after debug
	    if(lstat("/usr/sys/conf/sysgen", &lstatb) >= 0)
		return(YES);
	    if(lstat("/usr/sys/conf/mkconf", &lstatb) >= 0)
		return(YES);
*/
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/sys directory (all subdirectories and files");
	    printf(" will be removed!\n");
	    printf("\nFILES: configuration files (conf/*.cf) and ");
	    printf("user device drivers.\n");
	    usfiles(MULTI);
	    rmdirf("/usr/sys");
	} else {
	    if(osp->os_flags&OS_SYM) {
		printf("\n%s: /usr/sys -> %s/sys\n",
		    sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		msdir1(osp, "sys");
		dosystem("chmod 755 sys");
		dosystem("chog sys sys");
		if(mslink(osp, "/usr/sys"))
		    return;
		sync();
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./sys/conf");
/*
 * TODO: remove after debug
	    strcat(syscmd, " ./sys/crt.profile ./sys/prt.profile ./sys/conf");
*/
	    if(ld_rx50 == NO) {
		if(cputyp[tpi].p_sid == SID)
		    strcat(syscmd, " ./sys/sys ./sys/dev/LIB2_id ./sys/net");
		else
		    strcat(syscmd, " ./sys/ovsys ./sys/ovdev ./sys/ovnet");
	    } else {
		if(cputyp[tpi].p_sid == SID)
		    strcat(syscmd, " ./sys/sys");
	    }
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		/* .profile saved in /usr/skel by setup */
		dosystem("cp /usr/skel/sys_profile /usr/sys/.profile");
		if(cputyp[tpi].p_sid == SID)
		    unlink("./sys/conf/mch_ov.o");
		else
		    unlink("./sys/conf/mch_id.o");
		break;
	    }
	    if(ld_rx50 == NO)
		return;
	    rflop("SYSGEN #1");
	    if(cputyp[tpi].p_sid == SID)
		printf("\nSYSGEN #2 not used with split I/D processors!\n");
	    if(cputyp[tpi].p_sid == NSID) {
		if(fmnt("SYSGEN #2"))
		    return;
		mkdir("/usr/sys/ovsys", 0755);
		mkdir("/usr/sys/ovnet", 0755);
		dosystem("chog sys /usr/sys/ovsys /usr/sys/ovnet");
		dosystem("chmod 755 /usr/sys/ovsys /usr/sys/ovnet");
		if(chngdir("/usr/sys/ovsys") == 0) {
		    system("ar x /mnt/LIB1_ov");
		    system("chog sys *");
		    system("chmod 444 *");
		    if(chngdir("../ovnet") == 0) {
			system("ar x /mnt/LIB3_ov");
			system("chog sys *");
			system("chmod 444 *");
		    }
		}
		fmnt(0);
		sync();
	    	rflop("SYSGEN #2");
		printf("\nSYSGEN #3 not used with non split I/D processors!\n");
	    }
	    if(cputyp[tpi].p_sid == SID) {
		if(osp->os_flags&OS_SYM) {
		    if(chngdir(&osp->os_slink))
			return;
		} else {
		    if(chngdir(gs_usr))
			return;
		}
		tarcs(TCSTART, osp);
		p = "SYSGEN #3";
		strcat(syscmd, " ./sys/sys ./sys/dev");
		tarcs(TCEND, osp);
		while(1) {
		    ddopen(osp, p);
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else
			    break;
		    }
		    rflop(p);
		    break;
		}
		sync();
	    }
	    if(fmnt("SYSGEN #4"))
		return;
	    fatal = 0;
	    if(cputyp[tpi].p_sid == NSID) {
		mkdir("/usr/sys/ovdev", 0755);
		dosystem("chog sys /usr/sys/ovdev");
		dosystem("chmod 755 /usr/sys/ovdev");
		if(chngdir("/usr/sys/ovdev") == 0) {
		    system("cp /mnt/asmfix? .");
		    system("ar x /mnt/LIB2_ov");
		} else
		    fatal++;
	    } else {
		mkdir("/usr/sys/net", 0755);
		dosystem("chog sys /usr/sys/net");
		dosystem("chmod 0755 /usr/sys/net");
		if(chngdir("/usr/sys/net") == 0)
		    system("ar x /mnt/LIB3_id");
		else
		    fatal++;
	    }
	    if(fatal == 0) {
		system("chog sys *");
		system("chmod 444 *");
	    }
	    fmnt(0);
	    sync();
	    rflop("SYSGEN #4");
	}
}

char	*l_usat[] =
{
	"/usr/bin/usat",
	0
};

f_usat(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat(l_usat[0], &lstatb) >= 0)
		return(YES);
	    if(lstat("/usr/lib/usat", &lstatb) >= 0)
		return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/lib/usat directory (and all files) ");
	    printf("will be removed!\n");
	    printf("\nFILES: log files and any local modifications or files.\n");
	    usfiles(MULTI);
	    rmfile(l_usat[0]);
	    rmdirf("/usr/lib/usat");
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		sync();
		printf("\n%s: /usr/lib/usat -> %s/lib/usat\n",
		    sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		if(chngdir("lib"))
		    return;
		msdir1(osp, "lib/usat");
		dosystem("chmod 755 usat");
		dosystem("chog bin usat");
		if(mslink(osp, "/usr/lib/usat"))
		    return;
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./bin/usat ./lib/usat");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%s: %s -> %s/bin/usat\n",
		    sl_make, l_usat[0], &osp->os_slink);
		mslink(osp, l_usat[0]);
	    }
	}
}

f_usep(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat("/usr/usep", &lstatb) >= 0)
		return(YES);
/* TODO: remove after debug
	    if(lstat("/usr/usep/sysx", &lstatb) >= 0)
		return(YES);
*/
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/usep directory (and all files) will be removed!\n");
	    printf("\nFILES: log files (*.log) and exerciser scripts (*.xs).\n");
	    usfiles(MULTI);
	    rmdirf("/usr/usep");
	} else {
	    if(osp->os_flags&OS_SYM) {
		printf("\n%s: /usr/usep -> %s/usep\n", sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		msdir1(osp, "usep");
		dosystem("chog bin usep");
		dosystem("chmod 755 usep");
		if(mslink(osp, "/usr/usep"))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./usep");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		/*
		 * The idea here is to get the correct .profile
		 * from the root (CRT or PRT). It will be in /profile
		 * if we are in setup phase 1 or 2, in /.profile otherwise.
		 */
		if(access("/profile", 0) == 0)
		    dosystem("cp /profile usep/.profile");
		else
		    dosystem("cp /.profile usep/.profile");
		printf("\n\7\7\7");
		printf("You can recover some disk space by removing exercisers");
		printf("\nfor devices not configured on your system.\n");
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	}
}

char	*l_uucp[] =
{
	"/usr/bin/uucp",
	"/usr/bin/uulog",
	"/usr/bin/uuname",
	"/usr/bin/uupoll",
	"/usr/bin/uustat",
	"/usr/bin/uux",
	0
};

f_uucp(com, osp)
register struct os_info *osp;
{
	register int i, fatal;

	if(com == LIST) {
	    for(i=0; l_uucp[i]; i++)
		if(lstat(l_uucp[i], &lstatb) >= 0)
		    return(YES);
	    if(lstat("/usr/lib/uucp", &lstatb) >= 0)
		return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/lib/uucp directory (and all files) will be removed!\n");
	    printf("\nFILES: L.sys, L-devices, log files, local modifications.\n");
	    usfiles(MULTI);
	    for(i=0; l_uucp[i]; i++)
		rmfile(l_uucp[i]);
	    rmdirf("/usr/lib/uucp");
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "lib"))
		    return;
		sync();
		printf("\n%s: /usr/lib/uucp -> %s/lib/uucp\n",
		    sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		if(chngdir("lib"))
		    return;
		msdir1(osp, "lib/uucp");
		dosystem("chmod 755 uucp");
		dosystem("chown uucp uucp");
		dosystem("chgrp daemon uucp");
		if(mslink(osp, "/usr/lib/uucp"))
		    return;
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    if(ld_rx50 == NO)
		strcat(syscmd,
" ./bin/uucp ./bin/uulog ./bin/uuname ./bin/uupoll ./bin/uustat ./bin/uux");
	    strcat(syscmd, " ./lib/uucp");
	    fatal = 0;
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else {
			fatal++;
			break;
		    }
		}
		break;
	    }
	    if(fatal)
		return;
	    if(ld_rx50 == YES) {
		rflop(osp->os_flop);
		printf("\nLoading remainder of UUCP from PLOT diskette.\n");
		tarcs(TCSTART, osp);
		strcat(syscmd,
" ./bin/uucp ./bin/uulog ./bin/uuname ./bin/uupoll ./bin/uustat ./bin/uux");
		tarcs(TCEND, osp);
		fatal = 0;
		while(1) {
		    ddopen(osp, "PLOT");
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else {
			    fatal++;
			    break;
			}
		    }
		    break;
		}
		if(fatal)
		    return;
	    }
	    if(chngdir("./lib/uucp"))
		return;
	    if(cputyp[tpi].p_sid == SID) {
		unlink("uucico40");
		dosystem("mv uucico70 uucico");
	    } else {
		unlink("uucico70");
		dosystem("mv uucico40 uucico");
	    }
	    if(ld_rx50 == YES)
		rflop("PLOT");
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for UUCP files.\n", sl_make);
		for(i=0; l_uucp[i]; i++)
		    mslink(osp, l_uucp[i]);
	    }
	}
}

char	*l_tcpip[] =
{
	"/usr/bin/dls",
	"/usr/bin/dcat",
	"/usr/bin/dcp",
	"/usr/bin/dlogin",
	"/usr/bin/drm",
	"/usr/ucb/rlogin",
	"/usr/ucb/rcp",
	"/usr/ucb/rwho",
	"/usr/ucb/ruptime",
	"/usr/ucb/talk",
	"/usr/ucb/telnet",
	"/usr/ucb/rsh",
	"/usr/ucb/netstat",
	"/usr/ucb/ftp",
	"/usr/ucb/tftp",
	"/usr/etc/ftpd",
	"/usr/etc/inetd",
	"/usr/etc/miscd",
	"/usr/etc/rexecd",
	"/usr/etc/rlogind",
	"/usr/etc/routed",
	"/usr/etc/rshd",
	"/usr/etc/syslog",
	"/usr/etc/talkd",
	"/usr/etc/tftpd",
	"/usr/etc/telnetd",
	"/usr/etc/rwhod",
	"/usr/etc/dgated",
	0
};

f_tcpip(com, osp)
register struct os_info *osp;
{
	register int i, fatal;

	if(com == LIST) {
	    for(i=0; l_tcpip[i]; i++)
		if(lstat(l_tcpip[i], &lstatb) >= 0)
		    return(YES);
	    return(NO);
	} else if(com == UNLOAD) {
	    for(i=0; l_tcpip[i]; i++)
		rmfile(l_tcpip[i]);
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "bin"))
		    return;
		if(msdir(osp, "ucb"))
		    return;
		if(msdir(osp, "etc"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    if(ld_rx50 == NO)
		strcat(syscmd,
" ./bin/dls ./bin/dcat ./bin/dcp ./bin/dlogin ./bin/drm");
	    strcat(syscmd,
" ./ucb/rlogin \
./ucb/rcp \
./ucb/rwho \
./ucb/ruptime \
./ucb/talk \
./ucb/telnet \
./ucb/netstat \
./ucb/ftp \
./ucb/tftp \
./ucb/rsh");
	    strcat(syscmd,
" ./etc/ftpd \
./etc/inetd \
./etc/miscd \
./etc/rexecd \
./etc/rlogind \
./etc/routed \
./etc/talkd \
./etc/rshd \
./etc/syslog \
./etc/tftpd");
	    if(ld_rx50 == NO)
		strcat(syscmd,
" ./etc/telnetd \
./etc/rwhod \
./etc/dgated");
	    fatal = 0;
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else {
			fatal++;
			break;
		    }
		}
		break;
	    }
	    if(fatal)
		return;
	    if(ld_rx50 == YES) {
		rflop(osp->os_flop);
		printf("\nLoading remainder of TCP/IP from SCCS diskette.\n");
		tarcs(TCSTART, osp);
		strcat(syscmd,
" ./bin/dls ./bin/dcat ./bin/dcp ./bin/dlogin ./bin/drm");
		strcat(syscmd,
" ./etc/telnetd ./etc/rwhod ./etc/dgated");
		tarcs(TCEND, osp);
		fatal = 0;
		while(1) {
		    ddopen(osp, "SCCS");
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else {
			    fatal++;
			    break;
			}
		    }
		    break;
		}
		if(fatal)
		    return;
	    }
	    if(osp->os_flags&OS_SYM) {
		printf("\n%ss for TCP/IP files.\n", sl_make);
		for(i=0; l_tcpip[i]; i++)
		    mslink(osp, l_tcpip[i]);
	    }
	    if(ld_rx50 == YES)
		rflop("SCCS");
	}
}

f_orphan(com, osp)
register struct os_info *osp;
{
	if(com == LIST) {
	    if(lstat("/usr/orphan/usr", &lstatb) >= 0)
		return(YES);
	    else
		return(NO);
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("All files (except README) will be removed from ");
	    printf("/usr/orphan directory!\n");
	    printf("\nFILES: local modifications.\n");
	    usfiles(MULTI);
	    rmdirf("/usr/orphan/bin");
	    rmdirf("/usr/orphan/lib");
	    rmdirf("/usr/orphan/usr");
	} else {
	    if(osp->os_flags&OS_SYM) {
		if(msdir(osp, "orphan"))
		    return;
		if(msdir1(osp, "orphan/bin"))
		    return;
		sprintf(&syscmd, "chog bin %s/orphan/bin", &osp->os_slink);
		dosystem(syscmd);
		sprintf(&syscmd, "chmod 755 %s/orphan/bin", &osp->os_slink);
		dosystem(syscmd);
		if(msdir1(osp, "orphan/lib"))
		    return;
		sprintf(&syscmd, "chog bin %s/orphan/lib", &osp->os_slink);
		dosystem(syscmd);
		sprintf(&syscmd, "chmod 755 %s/orphan/lib", &osp->os_slink);
		dosystem(syscmd);
		if(msdir1(osp, "orphan/usr"))
		    return;
		sprintf(&syscmd, "chog bin %s/orphan/usr", &osp->os_slink);
		dosystem(syscmd);
		sprintf(&syscmd, "chmod 755 %s/orphan/usr", &osp->os_slink);
		dosystem(syscmd);
		sync();
		printf("\n%s: /usr/orphan/bin -> %s/orphan/bin\n",
		    sl_make, &osp->os_slink);
		if(mslink(osp, "/usr/orphan/bin"))
		    return;
		printf("\n%s: /usr/orphan/lib -> %s/orphan/lib\n",
		    sl_make, &osp->os_slink);
		if(mslink(osp, "/usr/orphan/lib"))
		    return;
		printf("\n%s: /usr/orphan/usr -> %s/orphan/usr\n",
		    sl_make, &osp->os_slink);
		if(mslink(osp, "/usr/orphan/usr"))
		    return;
		sync();
		if(chngdir(&osp->os_slink))
		    return;
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    strcat(syscmd, " ./orphan");
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else
			break;
		}
		if(ld_rx50 == YES)
		    rflop(osp->os_flop);
		break;
	    }
	}
}

f_manuals(com, osp)
register struct os_info *osp;
{
	register int fatal, i;
	char	fn[20];

	if(com == LIST) {
	    if(lstat("/usr/man", &lstatb) >= 0)
		return(YES);
	    else
		return(NO);
/* TODO: remove after debug
	    for(i=1; i<9; i++) {
		sprintf(&fn, "/usr/man/man%d", i);
		if(lstat(&fn, &lstatb) >= 0)
		    return(YES);
	    }
	    return(NO);
*/
	} else if(com == UNLOAD) {
	    printf("\n\7\7\7");
	    printf("The /usr/man directory (and all files) will be removed!\n");
	    printf("\nFILES: manual page directories [man1-man8, cat1-cat8].\n");
	    usfiles(MULTI);
	    rmdirf("/usr/man");
	} else {
	    if(osp->os_flags&OS_SYM) {
		printf("\n%s: /usr/man -> %s/man\n",
		    sl_make, &osp->os_slink);
		if(chngdir(&osp->os_slink))
		    return;
		msdir1(osp, "man");
		dosystem("chmod 755 man");
		dosystem("chog bin man");
		if(mslink(osp, "/usr/man"))
		    return;
		sync();
	    } else {
		if(chngdir(gs_usr))
		    return;
	    }
	    tarcs(TCSTART, osp);	/* Create base tar command string */
	    if(ld_rx50 == NO)
		strcat(syscmd, " ./man");
	    fatal = 0;
	    tarcs(TCEND, osp);		/* End tar command string */
	    while(1) {
		ddopen(osp, osp->os_flop);
		if(dosystem(syscmd) != 0) {
		    if(retry(gs_txerr))
			continue;
		    else {
			fatal++;
			break;
		    }
		}
		break;
	    }
	    if((fatal) || (ld_rx50 == NO)) {
		if((ld_rl02 == YES) && (fatal == 0))
		    upman();
		return;
	    }
	    rflop(osp->os_flop);
	    for(i=2; i<6; i++) {
		sprintf(fn, "MANUALS #%d", i);
		fatal = 0;
		while(1) {
		    ddopen(osp, &fn);
		    if(dosystem(syscmd) != 0) {
			if(retry(gs_txerr))
			    continue;
			else {
			    fatal++;
			    break;
			}
		    }
		    break;
		}
		if(fatal)
		    break;
		rflop(&fn);
	    }
	    upman();
	}
}

/*
 * Unpack the man page files.
 * For RL02 and RX50 kits only.
 */

upman()
{
	register int i;
	char	fn[20];

	printf("\nUnpacking files for on-line manuals....\n");
	/* assumes we are in /usr (or a symbolic link to it) */
	if(chngdir("./man/man2") == 0) {
	    for(i=1; i<9; i++) {	/* unpack man files */
		sprintf(&fn, "../man%d", i);
		if(chngdir(&fn))
		    break;
		dosystem("unpack * >/dev/null 2>&1");
	    }
	}
}

/*
 * If the load device is TM02/3 (ht) magtape, ask for the
 * tape density, unless it has already been set.
 * Set loadev to rmt0 for 800 or rht0 for 1600.
 * If load device is not magtape, just return.
 */

getden()
{
	register int j;

	if(ld_tape == NO)
	    return;
	if(loadev)
	    return;
	while(1) {
	    do {
		printf("\nDistribution tape density (? for help) ");
		printf("< 800 1600 > ? ");
	    } while(gline("h_dtden") <= 0);
	    j = atoi(glbuf);
	    if(j == 800)
		loadev = "rmt0";
	    else if(j == 1600)
		loadev = "rht0";
	    else {
		printf("\n%s - bad density!\n", glbuf);
		continue;
	    }
	    break;
	}
}

/*
 * Ask the user to make sure the distribution media
 * is mounted, on-line, and ready. This may be RL02,
 * RC25, or magtape. Only ask once!
 */

int	ddmount = 0;

ddmnt()
{
	if(ld_rx50 == YES)
	    return;
	if(ddmount)
	    return;
	ddmount++;
	if(ld_tape == YES) {
	    printf("\nMake sure the distribution tape (or TK50 cartridge) is");
	    printf("\nmounted in unit zero and the unit is on-line and ready.\n");
	} else if(strncmp(loadev, "rrl", 3) == 0) {
	    printf("\nMake sure the OPTIONAL SOFTWARE disk is loaded and the");
	    printf("\ndisk drive is on-line and ready. Enter the unit number");
	    printf("\nof the RL02 where the OPTIONAL SOFTWARE disk is mounted.\n");
	    while(1) {
		do
		    printf("\nOPTIONAL SOFTWARE disk unit number < 0 1 2 3 > ? ");
		while(gline(NOHELP) <= 0);
		if((strlen(glbuf) != 1) ||
		   (glbuf[0] < '0') ||
		   (glbuf[0] > '3'))
			continue;
		loadev[3] = glbuf[0];
		break;
	    }
	} else if(strncmp(loadev, "rrc", 3) == 0) {
	    printf("\nMake sure the distribution disk is loaded in RC25 unit");
	    printf("\nzero and the disk is ready.\n");
	} else
	    printf("\nUnknown distribution media!\n");
	prtc();
}

iflop(fn)
char	*fn;
{
	printf("\n\7\7\7Insert (%s) diskette into RX%d unit %d",
		fn, (rxtype==RX33) ? RX33 : RX50, rxunit);
	if(rxtype != RX33)
		printf(" %s", rxpos(rxunit));
	printf("\n");
	prtc();
}

rflop(fn)
char	*fn;
{
	printf("\n\7\7\7Remove (%s) diskette from RX%d unit %d",
		fn, (rxtype==RX33) ? RX33 : RX50, rxunit);
	if(rxtype != RX33)
		printf(" %s", rxpos(rxunit));
	printf("\n");
	prtc();
}

char	*rxp_tl = "(top/left)";
char	*rxp_lr = "(lower/right)";

rxpos(unit)
{
	switch(unit) {
	case 1:
		return(rxp_tl);
	case 2:
		return((rd2) ? rxp_tl : rxp_lr);
	case 3:
		return(rxp_lr);
	default:
		return("(?)");
	}
}

prtc()
{
	printf("%s", gs_prtc);
	fflush(stdout);
	while(getchar() != '\n') ;
}

/*
 * Make a directory, only if it
 * does not already exist.
 */

makedir(dir)
char *dir;
{
	char	syscmd[30];

	if(access(dir, 0) != 0) {
	    sprintf(syscmd, "mkdir %s", dir);
	    dosystem(syscmd);
	}
}

fmnt(flop)
char	*flop;

{
	char	p[100];
	char	sysmnt[100];

	sprintf(sysmnt, "/dev/rx%d", rxunit);
	if(flop == 0) {
	    umount(sysmnt);
	    return(0);
	}
	iflop(flop);
	sprintf(p, "Mount of %s diskette on /mnt", flop);
	while(1) {
	    if(mount(sysmnt, "/mnt", 1) != 0) {
		if(retry(&p))
		    continue;
		else
		    return(1);
	    }
	    break;
	}
	return(0);
}

chngdir(dir)
char *dir;
{
	if(chdir(dir) < 0) {
	    printf("\nCannot change directory to %s!\n", dir);
	    return(1);
	} else
	    return(0);
}

/*
 * Remove a file.
 * If file is a symbolic link, remove it and the real file.
 *
 *   file	full pathname including file name
 */

rmfile(file)
char	*file;
{
	register int cc;
	struct	stat	statb;
	char	buf[BUFSIZ];

	if(lstat(file, &statb) < 0)
	    return;			/* file does not exist */
	if((statb.st_mode&S_IFMT) == S_IFLNK) {	/* file is a symbolic link */
	    cc = readlink(file, &buf, BUFSIZ);	/* get pathname of real file */
	    if(cc > 0) {
		buf[cc] = 0;
		unlink(&buf);
	    }
/* TODO: may want to warn symlink could not be removed??? */
	}
	unlink(file);
}

/*
 * Remove a directory and its files.
 *
 * If the directory is a symbolic link, remove the link
 * and the real directory and its files.
 *
 *   dir	full pathname of directory
 */

rmdirf(dir)
char	*dir;
{
	register int cc;
	struct	stat	statb;
	char	scmd[100];
	char	buf[BUFSIZ];

	if(lstat(dir, &statb) < 0)
	    return;			/* directory does not exist */
	if((statb.st_mode&S_IFMT) == S_IFLNK) {	/* dir is a symbolic link */
	    cc = readlink(dir, &buf, BUFSIZ);	/* get pathname of real file */
	    if(cc > 0) {
		buf[cc] = 0;
		sprintf(&scmd, "rm -rf %s", &buf);
		dosystem(&scmd);
	    }
	}
	sprintf(&scmd, "rm -rf %s", dir);
	dosystem(&scmd);
}

/*
 * Make subdirectories needed for symbolic links to
 * individual files only (not directories).
 * Makes entries in both /usr and the mounted file system
 * where the real file(s) will exist.
 * Also, "chog bin" and "chmod 755".
 * No error if directory already exists, all others are fatal.
 *
 *   osp	optional software info table pointer
 *   dir	subdirectory name (no / in front of name)
 */

msdir(osp, dir)
register struct os_info *osp;
char	*dir;
{
	char	*p, *q, *v;
	char	pn[50];		/* parent directory name (eg, /user1/.) */
	char	dn[50];		/* directory name (eg, /user1/bin) */
	char	dnp[50];	/* dn + /. (eg, /user1/bin/.) */
	char	dnpp[50];	/* dn + /.. (eg, /user1/bin/..) */
	char	scmd[100];

	/*
	 * Create path name string for parent directory.
	 * Will be the symbolic link base directory (eg, /user1)
	 * if the directory being created (*dir) has no slashes
	 * in its path name. Otherwise, will be base + *dir (eg, /user1/bin/.).
	 */
	sprintf(&pn, "%s/.", &osp->os_slink);
	for(p = &pn; (*p != '.'); p++);
	for(v=0, q=dir; *q; q++)
	    if(*q == '/')
		v = q;
	if(v) {
	    for(q=dir; ((int)q < (int)v); q++)
		*p++ = *q;
	    *p++ = '/';
	    *p++ = '.';
	    *p++ = '\0';
	}
/*	printf("\nDEBUG: %s\n", &pn);	*/
	/*
	 * Make subdirectory in mounted file system (real files).
	 */
	sprintf(&dn, "%s/%s", &osp->os_slink, dir);
	if(mknod(&dn, 040755, 0) < 0) {
	    if(errno != EEXIST) {
		printf("\nCan't make %s directory!\n", &dn);
		return(1);
	    }
	} else {
	    sprintf(&scmd, "chog bin %s/%s", &osp->os_slink, dir);
	    dosystem(scmd);
	    /* We do chmod so se don't have to mess with the users' umask */
	    sprintf(&scmd, "chmod 755 %s/%s", &osp->os_slink, dir);
	    /* Link . and .. */
	    sprintf(&dnp, "%s/.", &dn);
	    if(link(&dn, &dnp) < 0) {
		linkerr(dn, dnp);
		unlink(dn);
		return(1);
	    }
	    sprintf(&dnpp, "%s/..", &dn);
	    if(link(&pn, &dnpp) < 0) {
		linkerr(dn, dnpp);
		unlink(dnp);
		unlink(dn);
		return(1);
	    }
	}
	/*
	 * Make subdirectory in /usr (for symbolic links).
	 */
	sprintf(&pn, "/usr/.");
	sprintf(&dn, "/usr/%s", dir);
	if(mknod(&dn, 040755, 0) < 0) {
	    if(errno != EEXIST) {
		printf("\nCan't make %s directory!\n", &dn);
		return(1);
	    }
	} else {
	    sprintf(&scmd, "chog bin /usr/%s", dir);
	    dosystem(scmd);
	    /* We do chmod so se don't have to mess with the users' umask */
	    sprintf(&scmd, "chmod 755 /usr/%s", dir);
	    /* Link . and .. */
	    sprintf(&dnp, "%s/.", &dn);
	    if(link(&dn, &dnp) < 0) {
		linkerr(dn, dnp);
		unlink(dn);
		return(1);
	    }
	    sprintf(&dnpp, "%s/..", &dn);
	    if(link(&pn, &dnpp) < 0) {
		linkerr(pn, dnpp);
		unlink(dnp);
		unlink(dn);
		return(1);
	    }
	}
	return(0);
}

linkerr(to, from)
char	*to;
char	*from;
{
	printf("\nCannot link %s -> %s\n", from, to);
}

/*
 * Make directory needed for symbolic links.
 * This is the directory in the mounted file system
 * where the files will be actually loaded.
 *
 * If the file exists and is a directory, just return.
 * If the file does not exist, make the directory.
 * If the file exists and is not directory, give the
 * user a chance to preserve the file, then blow it away and
 * make the directory.
 * Return an error if can't make the directory.
 *
 *   osp	optional software info table pointer
 *   dir	directory name, relative to base directory
 *		eg, "lib/uucp", no beginning slash.
 *
 */

msdir1(osp, dir)
register struct os_info *osp;
char	*dir;
{
	struct stat statb;
	char	dn[100];
	sprintf(&dn, "%s/%s", &osp->os_slink, dir);
	if(lstat(&dn, &statb) >= 0) {
	    if((statb.st_mode&S_IFMT) == S_IFDIR)
		return(0);
	    printf("\nCONFLICT: a file named %s exists!\n", &dn);
	    usfiles(SINGLE);
	    unlink(&dn);
	}
	if(mkdir(&dn, 0777) < 0) {
	    printf("\nCannot make %s directory!\n", &dn);
	    return(1);
	}
	return(0);
}

/*
 * Make symbolic link for a single file.
 *
 *   osp	optional software info table pointer
 *   path	full pathname of symbolic link (not real file name)
 *		ASSUMPTION: pathname begins with /usr!
 */

mslink(osp, path)
register struct os_info *osp;
char	*path;
{
	char	rfname[100];

	sprintf(&rfname, "%s%s", &osp->os_slink, &path[4]);
	if(symlink(rfname, path) < 0) {
	    printf("\nCannot create symbolic link: %s -> %s", path, rfname);
	    printf("\n\7\7\7Try unloading (%s), then retry loading (%s).\n",
		osp->os_name, osp->os_name);
	    return(1);
	} else
	    return(0);
}

/*
 * Escape to the shell,
 * to give the user a chance to preserve critical files
 * and/or local modifications when unloading optional software.
 *
 * Assumes caller printed appropriate warning messages.
 *
 *   nf		single file or many files
 */

usfiles(nf)
{
	printf("\nDo you want to preserve %s <y or n> ? ",
	    (nf==SINGLE) ? "this file" : "any of these files");
	if(yes(NOHELP) == NO)
	    return;
	phelp("h_suf");
	fflush(stdout);
	system("sh");
	if(nf==MULTI)
	    printf("\nRemoving files...\n");
	else
	    printf("\nContinuing...\n");
}