Ultrix-3.1/src/cmd/msf.c

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


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

static	char	Sccsid[] = "@(#)msf.c	3.1	3/26/87";
/*
 *
 *  File name:
 *
 *	msf.c
 *
 *  Source file description:
 *
 *	ULTRIX-11 Make Special Files program (msf).
 *
 *	This program makes, or optionally removes, the special files for a
 *	device. Everything is keyed off the device's generic name, i.e.,
 *	rp06, dh11, lp11, etc. This makes it easy for the user to make the
 *	special files needed to access a device.
 *
 *	The special files are created in the /dev directory. There is no way
 *	to specify an alternate directory.
 *
 *	The msf command can be used interactively, which is recommended for
 *	users. It also accepts device names and other information on the
 *	command line, so it can be called by other programs or shell scripts.
 *
 *	CAUTION!, this program depends on /usr/include/sys/devmaj.h. If the
 *	order of major device numbers changes, msf must be recompiled.
 *
 *  Functions:
 *
 *	main()		The planes in spain fall MAINLY in the rain!
 *
 *	OTHERS?
 *
 *  Usage:
 *
 *	Interactive usage:
 *
 *		/etc/msf	(program prompts for device name, etc.)
 *
 *	Non-interactive usage:
 *
 *		/etc/msf [-t] [-r] [-f #] device [-c #] unit [tty##]
 *
 *		-t	print the device name/information table
 *		-r	remove instead of create special files
 *		-f #	remove/create only disk partition #
 *			(# = all for all partitions)
 *		device	device's generic name (rp06, dh11, lp11, etc.)
 *		-c #	# = MSCP/MASSBUS controller number (default = 0)
 *		unit	for maus, ptty, kl, & dl, unit = number of lines
 *			for all others, unit = unit number or all for all units
 *			(no default)
 *		tty##	first /dev/tty## assigned to a communications device
 *			or pseudo TTY (default = 0)
 *
 *  Compile:
 *
 *	cd /usr/src/cmd; make msf
 *
 *  Modification History:
 *
 *	18 July 1985
 *		File created -- Fred Canter
 *
 */

#include <stdio.h>
#include <pwd.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/devmaj.h>

/*
 * Help messages
 */

char	*help[] =
{
	"The /etc/msf (Make Special Files) command creates or removes a",
	"device's special files. Refer to chapter 1 of the ULTRIX-11",
	"System Management Guide for a description of device special files.",
	"",
	"To execute a command, type the first letter of the command then",
	"press <RETURN>. The command will execute, then return to the command",
	"prompt. The create and remove commands prompt you for the device",
	"name and other information. Each of the create or remove command",
	"prompts include on-line help, activated by typing a ?.",
	"",
	"The msf commands are:",
	"",
	"CTRL/C	Abort current command and return to the command prompt.",
	"help	Print this help message (? also prints help message).",
	"exit	Exit from the make special files program.",
	"table	Prints the device name/information table.",
	"create	Create some or all of a device's special files.",
	"remove	Remove some or all of a device's special files.",
	"",
	0
};

char	*h_devnam[] =
{
	"Enter the device's generic name, using only lowercase characters.",
	"The generic name is the real name for the device as opposed to its",
	"ULTRIX-11 mnemonic, for example, rp06 vs hp. Use the table command",
	"to list the names of all supported devices.",
	"",
	0
};

char	*h_cn[] =
{
	"The MASSBUS disk driver supports up to three RH11/RH70 MASSBUS",
	"disk controllers. The MSCP disk driver supports up to four MSCP",
	"(UDA50 KDA50 KLESI RQDX RUX1) disk controllers. The controller",
	"number is encoded in the special files for MASSBUS/MSCP disks.",
	"",
	"The MASSBUS disks are:",
	"	RH11/RH70 - RP04/5/6, RM02/3/5, and ML11",
	"",
	"The MSCP disks are:",
	"	RX50 RX33 RD31 RD32 RD51 RD52 RD53 RD54 RC25 RA60 RA80 RA81",
	"",
	"The controller number is determined by the order in which the",
	"controllers were specified during the system generation, that is,",
	"controller zero was entered first, controller one second and",
	"controller two third, etc.",
	"",
	0
};

char	*h_units[] =
{
	"For SLUs (Single Line Units), such as the DL11, enter the number",
	"of single line units. This determines how may /dev/tty## files are",
	"to be created/removed.",
	"",
	"For pseudo TTYs, enter the number of /dev/pty?? /dev/tty?? pairs",
	"to be created/removed.",
	"",
	"For maus (multiple access user space), enter the number of maus",
	"special files needed. The maus files are /dev/maus# (# is 0 - 7).",
	"A /dev/maus# file is needed for each maus map entry in the kernel.",
	"The number of maus map entries is specified during system generation.",
	"",
	"The word all may be used to specify that all possible /dev/tty files",
	"are to be created. This is not recommend for /dev/tty files, because",
	"a large number of unnecessary files could be created, or more files",
	"than desired could be removed.",
	"",
	0
};

char	*h_unit[] =
{
	"Enter the unit number of the device for which the special files are",
	"to be created or removed. The word all may be used to specify that",
	"the special files for all possible units are to be created/removed.",
	"The \"all\" feature should be used with caution, because large numbers",
	"of files can be created (tm03, 64 units times 6 files/unit). Also,",
	"more than the desired number of files could be removed.",
	"",
	0
};

char	*h_ttyn[] =
{
	"For communications devices and pseudo TTYs, the starting TTY number",
	"specifies the first /dev/tty## or /dev/pty?? /dev/tty?? pair to be",
	"created/removed. The starting TTY number must be specified because",
	"there may be existing /dev/tty## files.",
	"",
	"For example, a DH11 with a starting tty number of 0 would create the",
	"files /dev/tty00 -> /dev/tty15 (DH11 has 16 lines). If the starting",
	"TTY number was 16, the /dev/tty16 -> /dev/tty31 files get created.",
	"",
	0
};

char	*h_stdpar[] =
{
	"Some disks do not use all eight possible disk partitions. The msf",
	"program's device information table specifies which partitions are",
	"used for each type of disk. If a non standard disk partition layout",
	"is being used, you may need to override the partition usage data",
	"in the device information table.",
	"",
	"Answer yes if you are using the standard disk partition layout.",
	"This will be the case for most systems. Msf will only create or",
	"remove special files for partitions actually used by the disk.",
	"",
	"Answer no if you are using a nonstandard disk partition layout and",
	"you need special files for additional disk partitions. If you",
	"answer no, the program will prompt for which partitions to use.",
	"",
	0
};

char	*h_usepar[] =
{
	"Enter the partition number for which special files are to be created",
	"or removed. If you enter a number from 0 -> 7, only the special",
	"files for that partition will be created/removed. You can enter the",
	"word all to create/remove the special files for all 8 partitions.",
	"",
	"To use a variation of the standard partitions, first create the",
	"special files for the standard partitions, then create/remove other",
	"special files one at a time.",
	"",
	0
};

char	*usage[] =
{
	"",
	"Usage:\t/etc/msf [-t] [-r] [-f #] device [-c #] unit [tty##]",
	"",
	"	-t	print the device name/information table",
	"	-r	remove special files instead of create them",
	"	-f #	remove/create only disk partition # (# can = all)",
	"	device	generic device name (rp06, dh11, lp11, etc.)",
	"	-c #	# = MSCP/MASSBUS disk controller number (default = 0)",
	"	unit	for maus, ptty & kl/dl, unit = number of lines",
	"		for all others, unit = unit number (unit can = all)",
	"	tty##	start assigning comm. device lines or pseudo ttys",
	"		at /dev/tty## (default = 0)",
	"",
	0
};

char	*bcnerr = "Invalid MSCP/MASSBUS cnltr number with -c option!\n";
char	*bfserr = "Invalid disk partition with -f option!\n";
char	*btnerr = "Invalid starting TTY number with tty## option!\n";
char	*bunerr = "Invalid unit number or number of units!\n";

/*
 * Device type info table.
 * Describes each possible device and provides
 * all info necessary to make/remove its special files.
 */

#define	NODEV	-1	/* No block major device nuber */
#define	MSCP	01	/* MSCP disk (cntlr # in minor device bits 6 & 7) */
#define	RX	02	/* RX50/RX33 (DISK_P with DISK_NP naming) */
			/* 04 was HS (rs03/4) */
#define	LPU4	010	/* MUX - # lines per unit, 4, 8, 16 */
#define	LPU8	020
#define	LPU16	040
#define	D800	0100	/* MAGTAPE - density, 800, 1600, 6250, tk50 */
#define	D1600	0200
#define	D6250	0400
#define	DTK50	01000	/* TK50 is black sheep! */
#define	CN	02000	/* MSCP/MASSBUS, multiple cntlr deivces (ask for cn) */
#define	NOSUP	04000	/* Device not supported (historical dreg) */
#define	ML11	010000	/* ML11 - special case of DISK_P */
#define	MASSBUS	020000	/* MASSBUS cpontrollers (HP HM HJ) */
#define	DISK_NP	0	/* Non partitioned disk */
#define	DISK_P	1	/* Partitioned disk */
#define	DISK_RX	2	/* RX02, requires special handling */
#define	MAGTAPE	3	/* Magnetic tape device */
#define	MUX	4	/* Communications multiplexer */
#define	SLU	5	/* Single line communications interface */
#define	LP	6	/* Line printer */
#define	CT	7	/* C/A/T (V7 phototypesetter interface) */
#define	DN	8	/* DN11 */
#define	DUDP	9	/* DU11 */
#define	PTY	10	/* Pseudo TTYs */
#define	MAUS	11	/* Multiple Access User Space files */

struct	dt_info {
	char	*dt_gname;	/* Generic device name */
	char	*dt_uname;	/* ULTRIX-11 device mnemonic */
	int	dt_units;	/* Max # of units (for SLU, max # ttys+1) */
	int	dt_type;	/* Device type (disk, tape, MUX, SLU, etc.) */
	int	dt_bmaj;	/* Block mode major device number or NODEV */
	int	dt_rmaj;	/* Raw/Character mode major device number */
	int	dt_pmask;	/* Disk partition mask (bit=0, unused partition */
	int	dt_flags;	/* Special case flags (ain't it awful!) */
} dt_info[] = {
	"rx02", "hx",  2, DISK_RX, HX_BMAJ, HX_RMAJ,    0, 0,
	"rk03", "rk",  8, DISK_NP, RK_BMAJ, RK_RMAJ,    0, 0,
	"rk05", "rk",  8, DISK_NP, RK_BMAJ, RK_RMAJ,    0, 0,
	"rl01", "rl",  4,  DISK_P, RL_BMAJ, RL_RMAJ, 0201, 0,
	"rl02", "rl",  4,  DISK_P, RL_BMAJ, RL_RMAJ, 0203, 0,
	"rk06", "hk",  8,  DISK_P, HK_BMAJ, HK_RMAJ, 0107, 0,
	"rk07", "hk",  8,  DISK_P, HK_BMAJ, HK_RMAJ, 0213, 0,
	"rp02", "rp",  8,  DISK_P, RP_BMAJ, RP_RMAJ, 0107, 0,
	"rp03", "rp",  8,  DISK_P, RP_BMAJ, RP_RMAJ, 0213, 0,
	"rp04", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0117, MASSBUS|CN,
	"rp04", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0117, MASSBUS|CN,
	"rp04", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0117, MASSBUS|CN,
	"rp05", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0117, MASSBUS|CN,
	"rp05", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0117, MASSBUS|CN,
	"rp05", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0117, MASSBUS|CN,
	"rp06", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0377, MASSBUS|CN,
	"rp06", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0377, MASSBUS|CN,
	"rp06", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0377, MASSBUS|CN,
	"rm02", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0217, MASSBUS|CN,
	"rm02", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0217, MASSBUS|CN,
	"rm02", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0217, MASSBUS|CN,
	"rm03", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0217, MASSBUS|CN,
	"rm03", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0217, MASSBUS|CN,
	"rm03", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0217, MASSBUS|CN,
	"rm05", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0377, MASSBUS|CN,
	"rm05", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0377, MASSBUS|CN,
	"rm05", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0377, MASSBUS|CN,
	"ml11", "hp",  8,  DISK_P, HP_BMAJ, HP_RMAJ, 0001, MASSBUS|CN|ML11,
	"ml11", "hm",  8,  DISK_P, HM_BMAJ, HM_RMAJ, 0001, MASSBUS|CN|ML11,
	"ml11", "hj",  8,  DISK_P, HJ_BMAJ, HJ_RMAJ, 0001, MASSBUS|CN|ML11,
	"ra60", "ra",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0277, MSCP|CN,
	"ra80", "ra",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0217, MSCP|CN,
	"ra81", "ra",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0377, MSCP|CN,
	"rc25", "rc",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0237, MSCP|CN,
	"rx33", "rx",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0200, MSCP|CN|RX,
	"rx50", "rx",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0200, MSCP|CN|RX,
	"rd31", "rd",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0341, MSCP|CN,
	"rd32", "rd",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0217, MSCP|CN,
	"rd51", "rd",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0221, MSCP|CN,
	"rd52", "rd",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0217, MSCP|CN,
	"rd53", "rd",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0217, MSCP|CN,
	"rd54", "rd",  8,  DISK_P, RA_BMAJ, RA_RMAJ, 0217, MSCP|CN,
	"tm11", "tm",  8, MAGTAPE, TM_BMAJ, TM_RMAJ,    0, D800,
	"tu10", "tm",  8, MAGTAPE, TM_BMAJ, TM_RMAJ,    0, D800,
	"te10", "tm",  8, MAGTAPE, TM_BMAJ, TM_RMAJ,    0, D800,
	"tk50", "tk",  4, MAGTAPE, TK_BMAJ, TK_RMAJ,    0, DTK50,
	"tu81", "tk",  4, MAGTAPE, TK_BMAJ, TK_RMAJ,    0, D1600|D6250,
	"ts11", "ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"ts04", "ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"ts05", "ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"tu80", "ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"tsv05","ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"tsu05","ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"tk25", "ts",  4, MAGTAPE, TS_BMAJ, TS_RMAJ,    0, D1600,
	"tm02", "ht", 64, MAGTAPE, HT_BMAJ, HT_RMAJ,    0, D800|D1600,
	"tm03", "ht", 64, MAGTAPE, HT_BMAJ, HT_RMAJ,    0, D800|D1600,
	"te16", "ht", 64, MAGTAPE, HT_BMAJ, HT_RMAJ,    0, D800|D1600,
	"tu16", "ht", 64, MAGTAPE, HT_BMAJ, HT_RMAJ,    0, D800|D1600,
	"tu77", "ht", 64, MAGTAPE, HT_BMAJ, HT_RMAJ,    0, D800|D1600,
	"kl11", "kl", 17,     SLU,   NODEV, CO_RMAJ,    0, 0, /* XXX */
	"dl11", "dl", 32,     SLU,   NODEV, CO_RMAJ,    0, 0, /* XXX */
	"klv11","kl", 17,     SLU,   NODEV, CO_RMAJ,    0, 0, /* XXX */
	"dlv11","dl", 32,     SLU,   NODEV, CO_RMAJ,    0, 0, /* XXX */
	"cat",  "ct",  1,      CT,   NODEV, CT_RMAJ,    0, 0,
	"ct",   "ct",  1,      CT,   NODEV, CT_RMAJ,    0, 0,
	"lp11", "lp",  1,      LP,   NODEV, LP_RMAJ,    0, 0,
	"dh11", "dh",  8,     MUX,   NODEV, DH_RMAJ,    0, LPU16,
	"dp11", "dp",  1,    DUDP,   NODEV, DU_RMAJ,    0, 0, /* yes, DU_RMAJ */
	"dhu11","uh",  8,     MUX,   NODEV, UH_RMAJ,    0, LPU16,
	"dhv11","uh",  8,     MUX,   NODEV, UH_RMAJ,    0, LPU8,
	"dn11", "dn",  4,      DN,   NODEV, DN_RMAJ,    0, 0,
	"dz11", "dz", 16,     MUX,   NODEV, DZ_RMAJ,    0, LPU8,
	"dzv11","dz", 16,     MUX,   NODEV, DZ_RMAJ,    0, LPU4,
	"dzq11","dz", 16,     MUX,   NODEV, DZ_RMAJ,    0, LPU4,
	"du11", "du",  4,    DUDP,   NODEV, DU_RMAJ,    0, NOSUP,
	"ptty", "pt",176,     PTY,   NODEV, PTC_RMAJ,   0, 0,
	"maus", "none",8,    MAUS,   NODEV, ME_RMAJ,    0,  0,
	0,
};

#define	HELP	2
#define	NOHELP	0
#define	YES	1
#define	NO	0
#define	LBSIZE	50
char	lbuf[LBSIZE];

char	dn[6];
char	devn[12];
char	ml_devn[12];
char	*daemon = "daemon";

int	imode;		/* Interactive mode */
int	rflag;		/* Remove special files instead of create them */
int	cntlr;		/* MSCP/MASSBUS controller number */
int	unit;		/* Unit number (-1 for all) or number of units */
int	ttyn;		/* Starting TTY number (tty##) */
int	fflag;		/* Use non standard partitions */
int	fpart;		/* Partitions to use (-1 for all, # >= 0 for just one) */

jmp_buf	savej;

int	sumask;

main(argc, argv)
int	argc;
char	*argv[];
{
	int	intr();
	register struct	dt_info	*dip;	/* Pointer into the dt_info table */
	register int i;
	int	cc;
	char	*p;

	sumask = umask(0);
	imode = 0;
	if(argc == 1) {		/* Interactive mode */
	    imode++;
	    printf("\nULTRIX-11 Make Special Files Program\n");
	    printf("\nFor help, type ? or help, then press <RETURN>.");
	    setjmp(savej);
	    signal(SIGINT, intr);
	    printf("\n");
	    while(1) {
		fflag = NO;
		printf("\nCommand < create exit help remove table >: ");
		if((cc = getline(NOHELP)) <= 0)
		    continue;	/* user typed help, <RETURN> or <CTRL/D> */
		switch(lbuf[0]) {
		case 'h':
		case '?':		/* print help message */
		    pmsg(help);
		    continue;
		case 'e':		/* exit from program */
		    umask(sumask);
		    exit(0);
		case 't':		/* print device table */
		    dotable();
		    continue;
		case 'c':		/* create special files */
		    if(sucheck("create"))
			continue;
		    rflag = NO;
		    dip = getinfo();
		    if(unit >= 0)
			domsf(dip);
		    else
			for(unit=0; unit<dip->dt_units; unit++)
			    domsf(dip);
		    continue;
		case 'r':		/* remove special files */
		    if(sucheck("remove"))
			continue;
		    rflag = YES;
		    dip = getinfo();
		    if(unit >= 0)
			domsf(dip);
		    else
			for(unit=0; unit<dip->dt_units; unit++)
			    domsf(dip);
		    continue;
		default:
		    printf("\n%s - not a valid command!\n", lbuf);
		    continue;
		}
	    }
	}
/*
 * Non interactive mode.
 */
	signal(SIGINT, intr);
	rflag = NO;
	fflag = NO;
	unit = 0;
	cntlr = 0;
	ttyn = 0;
	for(i=1; argv[i]; i++) {
	    if(equal("-h", argv[i])) {
		pmsg(usage);
		if(argc == 2)
		    xit();
		else {
		    argc--;
		    continue;
		}
	    }
	    if(equal("-t", argv[i])) {
		dotable();
		if(argc == 2)
		    xit();
		else {
		    argc--;
		    continue;
		}
	    }
	    if(equal("-r", argv[i])) {
		rflag = YES;
		continue;
	    }
	    if(equal("-f", argv[i])) {
		fflag = YES;
		i++;
		if(equal("all", argv[i])) {
		    fpart = -1;	/* all partitions */
		    continue;
		}
		if((strlen(argv[i]) != 1) ||
		   (argv[i][0] < '0') || (argv[i][0] > '7')) {
			printf("\nmsf: %s", bfserr);
			pmsg(usage);
			errxit();
		}
		fpart = atoi(argv[i]);
		continue;
	    }
	    if(equal("-c", argv[i])) {
		/*
		 * For now, cntlr limit is 3.
		 * Check again later, when we know device type.
		 */
		i++;
		if((strlen(argv[i]) != 1) ||
		   (argv[i][0] < '0') || (argv[i][0] > '3')) {
			printf("\nmsf: %s", bcnerr);
			pmsg(usage);
			errxit();
		}
		cntlr = atoi(argv[i]);
		continue;
	    }
	    if(strncmp("tty", argv[i], 3) == 0) {
		if((strlen(argv[i]) < 4) ||
		   (strlen(argv[i]) > 6) ||
		   (argv[i][3] < '0') ||
		   (argv[i][3] > '9')) {
			printf("\nmsf: %s", btnerr);
			pmsg(usage);
			errxit();
		}
		ttyn = atoi(&argv[i][3]);
		continue;
	    }
	    if(equal("all", argv[i])) {		/* unit # = all */
		unit = -1;
		continue;
	    }
	    if((argv[i][0] >= '0') && (argv[i][0] <= '9')) {	/* unit # */
		unit = atoi(argv[i]);
		/*
		 * Max unit # is 176 (# of pttys).
		 */
		if((unit < 0) || (unit > 176)) {
		    printf("\nmsf: %s", bunerr);
		    pmsg(usage);
		    errxit();
		}
		continue;
	    } else {		/* assume device name */
		for(dip=dt_info; dip->dt_gname; dip++)
		    if(equal(argv[i], dip->dt_gname))
			break;
		if(dip->dt_gname == 0) {
		    printf("\nmsf: %s - invalid device name!\n", argv[i]);
		    pmsg(usage);
		    errxit();
		}
		continue;
	    }
	}
	if((dip->dt_type==SLU) || (dip->dt_type==PTY) || (dip->dt_type==MAUS)) {
	    if(unit == 0) {
		printf("\nmsf: SLU/PTTY/MAUS number of units missing!\n");
		pmsg(usage);
		errxit();
	    }
	}
	if(dip->dt_flags&CN) {
	    if(dip->dt_flags&MSCP)
		i = 3;
	    else
		i = 2;
	    if(cntlr > i) {
		printf("\nmsf: %d - invalid %s controller number!\n",
		    i, (dip->dt_flags&MSCP) ? "MSCP" : "MASSBUS");
		pmsg(usage);
		errxit();
	    }
	}
	if(dip->dt_flags&MASSBUS)
	    dip += cntlr;	/* point to wright cntlr (hp hm hj) */
	if(argc == 1)	/* only args were -h and/or -t */
	    xit();
	if(rflag)
	    p = "remove";
	else
	    p = "create";
	if(sucheck(p))
	    errxit();
	if(unit >= 0)
	    domsf(dip);
	else
	    for(unit=0; unit<dip->dt_units; unit++)
		domsf(dip);
	xit();
}

/*
 * Ask user for device name,
 * [cn], unit number, [tty##].
 */

getinfo()
{
	register struct dt_info *dp;
	register int j, cc;

	while(1) {
	    do
		printf("\nDevice name (? for help) < rp06, dz11, lp11, etc. >: ");
	    while((cc = getline(h_devnam)) < 0);
	    if(cc == 0)
		continue;	/* user typed <RETURN> */
	    for(dp=dt_info; dp->dt_gname; dp++)
		if(strcmp(lbuf, dp->dt_gname) == 0)
		    break;
	    if(dp->dt_gname == 0) {
		printf("\n%s - bad device name!\n", lbuf);
		continue;
	    }
	    break;
	}
	while(1) {
	    cntlr = 0;
	    if((dp->dt_flags&CN) == 0)
		break;
	    do {
		if(dp->dt_flags&MSCP)
		    printf("\nMSCP ");
		else
		    printf("\nMASSBUS ");
		printf("controller number < 0 1 2 ");
		if(dp->dt_flags&MSCP)
		    printf("3 ");
		printf("> : ");
	    } while((cc = getline(h_cn)) < 0);
	    if(cc == 0)
		continue;	/* <RETURN> */
	    if(dp->dt_flags&MSCP)
		j = '3';
	    else
		j = '2';
	    if((cc != 1) || (lbuf[0] < '0') || (lbuf[0] > j)) {
		printf("\n%s - bad controller number!\n", lbuf);
		continue;
	    }
	    cntlr = lbuf[0] - '0';
	    if(dp->dt_flags&MASSBUS)
		dp += cntlr;	/* TRICK PLAY, dt_info has entry for each cntlr */
	    break;
	}
	while(1) {
	    unit = 0;
	    if((dp->dt_type==SLU) || (dp->dt_type==PTY) || (dp->dt_type==MAUS)) {
		j = dp->dt_units;
		if(dp->dt_type == SLU)
		    j--;
		do
		    printf("\nNumber of units < %d maximum >: ", j);
		while((cc = getline(h_units)) < 0);
		if(cc == 0)
			continue;
		unit = atoi(lbuf);
		if((unit <= 0) || (unit > j)) {
		    printf("\n%s - bad number of units!\n", lbuf);
		    continue;
		}
		break;
	    } else {
		do {
		    printf("\nUnit number ");
		    if(dp->dt_units == 1) {
			printf("= 0, only one %s allowed!\n", dp->dt_gname);
			break;
		    }
		    printf("< 0 -> %d or all >: ", dp->dt_units - 1);
		} while((cc = getline(h_unit)) < 0);
		if(cc == 0)
		    continue;
		if(equal("all", lbuf)) {
		    unit = -1;
		    break;
		}
		unit = atoi(lbuf);
		if((unit < 0) || (unit > (dp->dt_units - 1))) {
		    printf("\n%s - bad unit number!\n", lbuf);
		    continue;
		}
		break;
	    }
	}
	while(1) {
	    if(dp->dt_type != DISK_P)
		break;
	    if(dp->dt_flags&RX)
		break;	/* RX50/RX33 always use only partition 7 */
	    if(dp->dt_flags&ML11)
		break;	/* No paritions on ML11 */
	    while(1) {
		printf("\nAssume standard disk partitions ");
		printf("(? for help) <y or n> ? ");
		j = yes(HELP);
		if(j == HELP) {
		    pmsg(h_stdpar);
		    continue;
		}
		if(j == YES)
		    fflag = NO;
		else
		    fflag = YES;
		break;
	    }
	    if(fflag != YES)
		break;
	    while(1) {
		do
		    printf("\n%s partitions < 0 -> 7 or all > ? ",
			rflag ? "Remove" : "Create");
		while((getline(h_usepar)) < 0);
		if(equal("all", lbuf)) {
		    fpart = -1;
		    break;
		}
		if((strlen(lbuf) != 1) || (lbuf[0] < '0') || (lbuf[0] > '7')) {
		    printf("\n%s - invalid response!\n", lbuf);
		    continue;
		}
		fpart = lbuf[0] - '0';
		break;
	    }
	    break;
	}
	while(1) {
	    ttyn = 0;
	    if((dp->dt_type != MUX) && (dp->dt_type != SLU))
		break;
	    do
		printf("\nStarting TTY number < ? for help >: ");
	    while((cc = getline(h_ttyn)) < 0);
	    if(cc == 0)
		continue;
	    ttyn = atoi(lbuf);
	    if((ttyn < 0) || (ttyn >= 100)) {
		printf("\n%s - bad TTY number!\n", lbuf);
		continue;
	    }
	    break;
	}
	return(dp);
}

/*
 * Print the device type/name table.
 */

dotable()
{
	register struct dt_info *dp;
	register int i;

	printf("\n\nNon partitioned disks:\n");
	printf("\nGeneric  ULTRIX-11  Units/  Block  Raw");
	printf("\nName     Mnemonic   Cntlr   Major  Major");
	printf("\n-------  ---------  ------  -----  -----");
	for(dp=dt_info; dp->dt_gname; dp++) {
		if((dp->dt_type != DISK_NP) && (dp->dt_type != DISK_RX))
			continue;
		printf("\n%-7s  %-9s  %-6d  %-5d  %-5d", dp->dt_gname,
			dp->dt_uname, dp->dt_units, dp->dt_bmaj, dp->dt_rmaj);
	}
	printf("\n\nPartitioned disks:\n");
	printf("\nGeneric  ULTRIX-11  Units/  Block  Raw    Partitions");
	printf("\nName     Mnemonic   Cntlr   Major  Major  Used");
	printf("\n-------  ---------  ------  -----  -----  ---------------");
	for(dp=dt_info; dp->dt_gname; dp++) {
		if(dp->dt_type != DISK_P)
			continue;
		printf("\n%-7s  %-9s  %-6d  %-5d  %-5d  ", dp->dt_gname,
			dp->dt_uname, dp->dt_units, dp->dt_bmaj, dp->dt_rmaj);
		for(i=0; i<8; i++)
			if(dp->dt_pmask&(1 << i))
				printf("%d ", i);
			else
				printf("x ");
	}
	printf("\n\nMagnetic tapes:\n");
	printf("\nGeneric  ULTRIX-11  Units/  Block  Raw    Density(s)");
	printf("\nName     Mnemonic   Cntlr   Major  Major  Supported");
	printf("\n-------  ---------  ------  -----  -----  ----------");
	for(dp=dt_info; dp->dt_gname; dp++) {
		if(dp->dt_type != MAGTAPE)
			continue;
		printf("\n%-7s  %-9s  %-6d  %-5d  %-5d  ", dp->dt_gname,
			dp->dt_uname, dp->dt_units, dp->dt_bmaj, dp->dt_rmaj);
		i = 0;
		if(dp->dt_flags&DTK50) {
			printf("N/A");
			continue;
		}
		if(dp->dt_flags&D800) {
			printf("800");
			i++;
		}
		if(dp->dt_flags&D1600) {
			if(i)
				printf("/");
			printf("1600");
			i++;
		}
		if(dp->dt_flags&D6250) {
			if(i)
				printf("/");
			printf("6250");
			i++;
		}
	}
	printf("\n\nCommunications single line units:\n");
	printf("\nGeneric  ULTRIX-11  # units  Raw");
	printf("\nName     Mnemonic   Allowed  Major");
	printf("\n-------  ---------  -------  -----");
	for(dp=dt_info; dp->dt_gname; dp++) {
		if(dp->dt_type != SLU)
			continue;
		printf("\n%-7s  %-9s  %-7d  %-5d", dp->dt_gname,
			dp->dt_uname, dp->dt_units, dp->dt_rmaj);
	}
	printf("\n\nCommunications multiplexers:\n");
	printf("\nGeneric  ULTRIX-11  # units  Raw    # lines");
	printf("\nName     Mnemonic   Allowed  Major  / unit");
	printf("\n-------  ---------  -------  -----  -------");
	for(dp=dt_info; dp->dt_gname; dp++) {
		if(dp->dt_type != MUX)
			continue;
		printf("\n%-7s  %-9s  %-7d  %-5d  ", dp->dt_gname,
			dp->dt_uname, dp->dt_units, dp->dt_rmaj);
		if(dp->dt_flags&LPU4)
			printf("4");
		if(dp->dt_flags&LPU8)
			printf("8");
		if(dp->dt_flags&LPU16)
			printf("16");
	}
	printf("\n\nMiscellaneous devices:\n");
	printf("\nGeneric  ULTRIX-11  # units  Raw    Device");
	printf("\nName     Mnemonic   Allowed  Major  Type");
	printf("\n-------  ---------  -------  -----  ------");
	for(dp=dt_info; dp->dt_gname; dp++) {
		if((dp->dt_type != LP) &&
		   (dp->dt_type != CT) &&
		   (dp->dt_type != DUDP) &&
		   (dp->dt_type != DN) &&
		   (dp->dt_type != MAUS) &&
		   (dp->dt_type != PTY))
			continue;
		printf("\n%-7s  %-9s  %-7d  %-5d  ", dp->dt_gname,
			dp->dt_uname, dp->dt_units, dp->dt_rmaj);
		if(dp->dt_type == LP)
		    printf("Line printer");
		if(dp->dt_type == PTY)
		    printf("Pseudo TTY for TCP/IP networking");
		if(dp->dt_type == CT)
		    printf("CAT phototypesetter interface");
		if(dp->dt_type == DN)
		    printf("Obsolete auto-call unit");
		if(dp->dt_type == DUDP)
		    printf("Obsolete synchronous communications");
		if(dp->dt_type == MAUS)
		    printf("Multiple Access User Space (MAUS)");
	}
	printf("\n");
}

/*
 * need funct header
 */

domsf(dp)
register struct dt_info *dp;
{
	register int i;
	struct passwd *np;
	int	err;
	int	j, k, cn, md, fsmask, mode;
	int	tline, nline;
	char	p, n;
	/* not sure of these yet */
	int	dlflag, klflag, numkl, dcflag;

	err = 0;
	switch(dp->dt_type) { /* device type tells what to do */
	case DISK_NP:
		k = unit;		/* k is minor device number */
		sprintf(&devn, "/dev/%s%d", dp->dt_uname, unit);
		unlink(devn);
		if(!rflag)
		    if(mknod(devn, 060600, ((dp->dt_bmaj << 8) | k)) < 0) {
			err++; break;
		    }
		sprintf(&devn, "/dev/r%s%d", dp->dt_uname, unit);
		unlink(devn);
		if(!rflag)
		    if(mknod(devn, 020600, ((dp->dt_rmaj << 8) | k)) < 0) {
			err++; break;
		    }
		break;
	case DISK_P:
		if(dp->dt_flags&MSCP)
		    cn = cntlr;	/* cntlr # in bits 6 & 7 of minor dev */
		else
		    cn = 0;
		if(fflag == YES) {
		    if(fpart == -1)
			fsmask = 0377;	/* make/remove all partitions */
		    else
			fsmask = (1<<fpart);	/* make/remove just one partition */
		} else
		    fsmask = dp->dt_pmask;
		for(k=0; k<8; k++) {
		    md = (unit << 3) | k;	/* minor dev */
		    md |= (cn << 6);	/* MSCP cont # */
		    if(dp->dt_flags&RX) {
			mode = 060666;
			sprintf(&devn, "/dev/%s%d", dp->dt_uname, unit);
		    } else {
			mode = 060600;
			sprintf(&devn, "/dev/%s%d%d", dp->dt_uname, unit, k);
		    }
		    if(fflag == NO)
			unlink(devn);
		    else if(fsmask & (1 << k))
			unlink(devn);
		    if(!rflag  && (fsmask & (1 << k)))
			if(mknod(devn, mode, ((dp->dt_bmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    if(dp->dt_flags&RX) {
			mode = 020666;
			sprintf(&devn, "/dev/r%s%d", dp->dt_uname, unit);
		    } else {
			mode = 020600;
			sprintf(&devn, "/dev/r%s%d%d", dp->dt_uname, unit, k);
		    }
		    if(fflag == NO)
			unlink(devn);
		    else if(fsmask & (1 << k))
			unlink(devn);
		    if(!rflag && (fsmask & (1 << k)))
			if(mknod(devn, mode, ((dp->dt_rmaj << 8) | md)) <0) {
			    err++; break;
			}
		}
		/* For ML11, link /dev/ml0, and /dev/rml0 */
		if(dp->dt_flags&ML11) {
		    /* restore old name (/dev/hp00) */
		    sprintf(&devn, "/dev/%s%d%d", dp->dt_uname, unit, 0);
		    /* set up /dev/ml0 */
		    sprintf(&ml_devn, "/dev/%s%d", "ml", unit);
		    unlink(ml_devn);
		    if (!rflag) {
		        if (link(devn, ml_devn) < 0)
			    printf("Cannot link %s to %s!\n",devn, ml_devn);
		    }

		    /* restore old name (/dev/rhp00) */
		    sprintf(&devn, "/dev/r%s%d%d", dp->dt_uname, unit, 0);
		    /* set up /dev/rml0 */
		    sprintf(&ml_devn, "/dev/r%s%d", "ml", unit);
		    unlink(ml_devn);
		    if (!rflag) {
		        if (link(devn, ml_devn) < 0)
			    printf("Cannot link %s to %s!\n",devn, ml_devn);
		    }
		}
		break;
	case MAGTAPE:
		if(dp->dt_flags&D800) {
		    sprintf(&devn, "/dev/mt%d", unit);
		    unlink(devn);
		    if(dp->dt_bmaj == TM_BMAJ)	/* minor device number */
		    	md = unit;		/* tm */
		    else
		    	md = unit | 0100;	/* ht (bit 6 = 800 BPI) */
		    if(!rflag)
			if(mknod(devn, 060666, ((dp->dt_bmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/rmt%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/nrmt%d", unit);
		    unlink(devn);		/* no rewind on close */
		    md |= 0200;			/* bit 7 is no rewind on close */
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		}
		if(dp->dt_flags&D1600) {
		    md = unit;
		    sprintf(&devn, "/dev/ht%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 060666, ((dp->dt_bmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/rht%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/nrht%d", unit);
		    unlink(devn);		/* no rewind on close */
		    md |= 0200;			/* bit7 says no rewind */
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		}
		if(dp->dt_flags&D6250) {
		    md = unit | 0100;
		    sprintf(&devn, "/dev/gt%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 060666, ((dp->dt_bmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/rgt%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/nrgt%d", unit);
		    unlink(devn);		/* no rewind on close */
		    md |= 0200;			/* bit7 says no rewind */
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		}
		if(dp->dt_flags&DTK50) {
		    md = unit;
		    sprintf(&devn, "/dev/tk%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 060666, ((dp->dt_bmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/rtk%d", unit);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/nrtk%d", unit);
		    unlink(devn);		/* no rewind on close */
		    md |= 0200;			/* bit7 says no rewind */
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
			}
		}
		break;
	case MUX:
		tline = ttyn;
		if(dp->dt_flags&LPU4)
		    nline = 4;
		if(dp->dt_flags&LPU8)
		    nline = 8;
		if(dp->dt_flags&LPU16)
		    nline = 16;
		for(j=0; j<nline; j++) {
		    sprintf(&devn, "/dev/tty%02d", tline+j);
		    unlink(devn);
		    if(!rflag) {
			md = (unit*nline) + j;
			if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | md)) < 0) {
			    err++; break;
		 	}
		    }
		}
		break;
/* NOTE: needs modification to support multiple LP units */
	case LP:
		sprintf(&devn, "/dev/lp");
		unlink(devn);
		unlink("/dev/rlp");
		if(!rflag) {
		    if(mknod(devn, 020200, (dp->dt_rmaj << 8)) < 0) {
			err++; break;
		    }
		    if(mknod("/dev/rlp", 020200, ((dp->dt_rmaj << 8) | 04)) < 0) {
			err++; break;
		    }
		}
		if((np = getpwnam(daemon)) == NULL) {
		    printf("\nmsf: Can't find daemon password entry!\n");
		    exit(1);
		}
		endpwent();
		chown(devn, np->pw_uid, np->pw_gid);
		chown("/dev/rlp", np->pw_uid, np->pw_gid);
		break;
/* NOTE: not tested yet! */
	case DN:
		sprintf(&devn, "/dev/dn%d", unit);
		unlink(devn);
		if(!rflag)
		    if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | j)) < 0) {
			err++; break;
		    }
		break;
	case CT:
		sprintf(&devn, "/dev/cat");
		unlink(devn);
		if(!rflag)
		    if(mknod(devn, 020222, (dp->dt_rmaj << 8)) < 0) {
			err++; break;
		    }
		break;
	case DISK_RX:
/*
 * This code assumes there are only two RX02 units.
 */
		for(j=0; j<10; j++) {
		    if((j&1) != unit)
			continue;
		    sprintf(&devn, "/dev/hx%d", j);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 060600, ((dp->dt_bmaj << 8) | j)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/rhx%d", j);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020600, ((dp->dt_rmaj << 8) | j)) < 0) {
			    err++; break;
			}
		}
		break;
/* NOTE: not tested yet! */
	case DUDP:
		sprintf(&devn, "/dev/%s%d", dp->dt_uname, unit);
		unlink(devn);
		if(!rflag)
		    if(mknod(devn, 020666, ((dp->dt_rmaj << 8) | unit)) < 0) {
			err++; break;
		    }
		break;
	case SLU:
		tline = ttyn;
		if(equal("kl", dp->dt_uname)) {
		    klflag++;
		    numkl = unit;
		    md = 1;
		} else if(equal("dl", dp->dt_uname)) {
		    dlflag++;
		    md = numkl + 1;	/* set when kl nodes made */
		} else {
		    dcflag++;
		    md = 0;
		}
		for(j=0; j<unit; j++) {
		    sprintf(&devn, "/dev/tty%02d", tline+j);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj<<8)|(md+j))) < 0) {
			    err++; break;
			}
		}
		break;
	case PTY:
		for(j=0; j<unit; j++) {
		    p = 'p' + (j / 16);
		    if((j % 16) < 10)
			n = '0' + (j % 16);
		    else
			n = 'a' + ((j % 16) - 10);
		    sprintf(&devn, "/dev/pty%c%c", p, n);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj<<8) | j)) < 0) {
			    err++; break;
			}
		    sprintf(&devn, "/dev/tty%c%c", p, n);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, (((dp->dt_rmaj+1)<<8) | j)) < 0) {
			    err++; break;
			}
		}
		break;
	case MAUS:
		for(j=0; j<unit; j++) {
		    sprintf(&devn, "/dev/maus%d", j);
		    unlink(devn);
		    if(!rflag)
			if(mknod(devn, 020666, ((dp->dt_rmaj<<8) | j+8)) < 0) {
			    err++; break;
			}
		}
		break;
	default:
		printf("\nmsf: device information table format error!\n");
		break;
	}
	if(err) {
		printf("\nmsf: can't create %s special file!\n", devn);
		perror("errno");
		return(-1);
	} else
		return(0);
}

/*
 * Get a line of text from the terminal,
 * replace the newline with a NULL.
 * Return the string length (not counting the NULL).
 * Use lbuf[] as the buffer and LBSIZE 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";

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

	ovflow = 0;
	fflush(stdout);
	while(1) {
	    lbuf[0] = '\0';
	    if(fgets(&lbuf, LBSIZE, stdin) == NULL) {
		printf("%s", badline);
		return(-1);	/* reprint message */
	    }
	    for(cc=0; lbuf[cc]; cc++) ;
	    if((cc == 0) || (lbuf[0] == '\n'))
		return(0);	/* (cc==0) says user typed just a <RETURN> */
	    if(lbuf[cc-1] != '\n') {	/* line too long */
		ovflow++;
		continue;
	    }
	    if(ovflow) {
		printf("\nLine too long, please try again!\n");
		return(-1);
	    }
	    cc--;
	    lbuf[cc] = '\0';
	    if((lbuf[0] == '?') || equal("help", lbuf) || equal("h", lbuf)) {
		if(hlp) {
		    pmsg(hlp);
		    return(-1);
		}
	    }
	    return(cc);
	}
}

equal(a, b)
char	*a, *b;
{
	return(!strcmp(a, b));
}

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

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

sucheck(str)
char	*str;
{
	if(getuid() == 0)
		return(0);
	else {
		printf("\nOnly super-user can %s special files!\n", str);
		return(1);
	}
}

char	line[10];

yes(hlp)
{
	register int i;

yorn:
	fflush(stdout);
	for(i=0; i<10; i++) {
		line[i] = getchar();
		if(line[i] == '\n') {
			line[i] = '\0';
			break;
		}
	}
	if(i > 4) {
ynerr:
		printf("\nPlease answer yes or no ? ");
		goto yorn;
	}
	if((strcmp(line, "yes") == 0) || (strcmp(line, "y") == 0))
		return(YES);
	else if((strcmp(line, "no") == 0) || (strcmp(line, "n") == 0))
		return(NO);
	else if((hlp==HELP) && ((line[0]=='?') || (strcmp(line, "help")==0)))
		return(HELP);
	else
		goto  ynerr;
}

intr()
{
	if(imode == 0) {	/* non interactive mode */
	    umask(sumask);
	    exit(0);
	}
	longjmp(savej, 1);
}

errxit()
{
	umask(sumask);
	exit(1);
}

xit()
{
	umask(sumask);
	exit(0);
}