static char Sccsid[] = "@(#)setup.c 3.3 10/14/87"; /********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* * TODO: * * [n] Need lp, mem, null, kmem, console, du & other oddballs! * * [n] Convert all error messages to use perror()!!!!!! * * [n] When to remove the BOOT floppy? * * [n] Look at all fatal error exits (see if they could be warnings). * * [NO] Chmod 400 /dev/??07 and /dev/r??07 (except RA) -- DOES NO GOOD! * * [n] Test RP02/3 by configuring driver and faking drives present! * * [n] Test interruptablity of each setup phase. * * [y] Mount /usr/once, dismount on exit (need usr mnt flag for error). * * [y] Write setup info back to setup.info if user enters it. * * [NO] Print warning: do not remove setup.info, setup, etc. files. * Handle in installation guide. * * [n] Test hz, timezone, dstflag loading in /dev/mem and /unix. * tested ok on 0431 kernel, not 0430. * * [n] Must be in single-user mode! * * [y] Need to replace ??unixes with a generic kernel. * * [y] Need new disk partitions and standard root/swap/elog layouts. * * [y] Handle case where target cpu not current cpu, split I/D space * or not is the big issue. * * [y] Save sid/* and nsid/* if target cpu not current cpu. -- TESTED * * [n] Need TK50 supported as load device. * * [n] Convert rxunit to rxflag (like setup53). * * [y] Blast fstab. * * [n] Make setup restartable to do phase 2 (setup.info). */ /* * * File name: * * setup.c * * Source file description: * * ULTRIX-11 initial setup program. * * TBS, when I figger it out! * need comment format of setup.info file * * multiple versions, RX, MT, others???? * do more work for users * even more on Micro/PDP-11s * * Functions: * * main() The main is the main! * * pmsg() Prints a message from an array of character pointers. * * yes() 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. * * iflop() Instruct the user to insert the named floppy into * one of the floppy disk drives. * * rflop() Instruct the user to remove the named floppy from * one of the floppy disk drives. * * prtc() Handles "Press <RETURN> to continue: " * * OTHERS? * * Usage: * * cd /.setup; setup * * The setup and setup.ifno files must not be removed. * The above commands are executed by the root .profile when the * system is first booted, after loading by sdload. The root .profile * is replaced after setup has completed its work, and the setup * program is removed. This is so that all subsequent boots be normal. * * Compile: * * cd /usr/sys/distr; make setup * * Modification History: * * 18 January 1984 * File created -- Fred Canter * * ?? ??????? 198? * Time passes -- Fred Canter * Many changes, see sccs prt setup.c setup53.c * * 13 March 1985 * Version 2.1 -- Fred Canter * Combined setup.c and setup53.c to form the new setup.c. * Many changes for new kit layout and installation flow. * Added setup_osl to handle loading optional software. * * 12 May 1985 * Version 2.2 -- Fred Canter * Clean up setup and finalize installation flow. * Take advantage of magtape in generic kernel. * Handle install on other than target processor. * Added #ifdef DEBUG. * TODO: more? * */ #include <stdio.h> #include <a.out.h> #include <signal.h> #include <setjmp.h> #include <fstab.h> #include <sys/param.h> #include <sys/dir.h> #include <sys/stat.h> #include <sys/filsys.h> #include <sys/devmaj.h> #include <sys/conf.h> #include <sys/ra_info.h> #include <sys/hp_info.h> #include <sys/tk_info.h> #include <sys/time.h> /* #define DEBUG 1 /* debug flag: turn on debug code */ jmp_buf savej; struct nlist nl[] = { { "_cputype" }, #define X_CPUTYPE 0 { "_hz" }, #define X_HZ 1 { "_timezon" }, #define X_TIMEZONE 2 { "_dstflag" }, #define X_DSTFLAG 3 { "_nrk" }, #define X_NRK 4 { "_rk_dt" }, #define X_RK_DT 5 { "_nrp" }, #define X_NRP 6 { "_rp_dt" }, #define X_RP_DT 7 { "_nuda" }, #define X_NUDA 8 { "_nra" }, #define X_NRA 9 { "_ra_inde" }, #define X_RA_INDEX 10 { "_ra_ctid" }, #define X_RA_CTID 11 { "_ra_drv" }, #define X_RA_DRV 12 { "_nrl" }, #define X_NRL 13 { "_rl_dt" }, #define X_RL_DT 14 { "_nhp" }, #define X_NHP 15 { "_hp_inde" }, #define X_HP_INDEX 16 { "_hp_dt" }, #define X_HP_DT 17 { "_nhs" }, #define X_NHS 18 { "_hs_dt" }, #define X_HS_DT 19 { "_nhk" }, #define X_NHK 20 { "_hk_dt" }, #define X_HK_DT 21 { "_nkl11" }, #define X_NKL11 22 { "_ndl11" }, #define X_NDL11 23 { "_ndh11" }, #define X_NDH11 24 { "_nuh11" }, #define X_NUH11 25 { "_dz_cnt" }, #define X_DZ_CNT 26 { "_ntty" }, #define X_NTTY 27 { "_ra_mas" }, #define X_RA_MAS 28 { "_ud_size" }, #define X_UD_SIZES 29 { "_rq_size" }, #define X_RQ_SIZES 30 { "_rc_size" }, #define X_RC_SIZES 31 { "_hp_size" }, #define X_HP_SIZES 32 { "_hk_size" }, #define X_HK_SIZES 33 { "_rp_size" }, #define X_RP_SIZES 34 { "_bdevsw" }, #define X_BDEVSW 35 { "_nht" }, #define X_NHT 36 { "_nts" }, #define X_NTS 37 { "_ntm" }, #define X_NTM 38 { "_ntk", }, #define X_NTK 39 { "_tk_ctid" }, #define X_TK_CTID 40 { "_npty" }, #define X_NPTY 41 { "_nmausen" }, #define X_NMAUSENT 42 { "" }, }; /* Structure for Daylight Savings Time information */ struct dst_table { char *dst_area; /* Geographical area */ int dst_id; /* Numeric id */ } dst_table[] = { "USA",DST_USA, "Australia",DST_AUST, "Western Europe",DST_WET, "Central Europe",DST_MET, "Eastern Europe",DST_EET, 0 }; #define YES 1 #define NO 0 #define ERR 1 #define NOERR 0 #define HELP 2 #define NOHELP 0 #define MOUNT 1 #define UMOUNT 0 #define FATAL 1 #define ABORT 2 #define MSF 0 #define MKFS 1 #define BLOCK 0 #define RAW 1 #define FST_SCH 0 #define FST_ENT 1 #define FST_RMV 2 #define CONSOLE 1 #define OTHER 0 #define LBSIZE 50 char lbuf[LBSIZE]; #define SCSIZE 512 /* CAUTION: 512 min size (doubles as disk read buf) */ char syscmd[SCSIZE]; char sphase[15]; char sdname[15]; char tproc[15]; char loadev[20]; char ldunit[10]; char *info = "/.setup/setup.info"; char *osload = "/bin/osload"; char *rclock = "/.setup/rootcmd.lock"; char *uclock = "/.setup/usrcmd.lock"; char *homedir = "/.setup"; char *lpfdir = "lost+found"; char *confirm = "\nPLEASE CONFIRM: "; char *dsk_sfn = "/dev/setup.dsf"; char *debug = "\nDEBUG: "; int firstfs = YES; /* making very first file system flag */ int sdtype; /* Index into sd_info[] entry for system disk */ int sdcntlr = 0; /* System disk on controller number */ /* TODO: 0 for now, how or if to set this? */ int sdunit; /* System disk unit number */ /* TODO: RUX50 - unit could be 0 ---| */ int rxflag; /* Unit # if load device is floppy, 0 if not */ int rxunit; int rd2 = NO; /* YES if second RD disk present (changes RX unit #s) */ int mtflag; /* Load device is magtape (unit number) */ int tkflag; /* set if magtape is really a TK50 */ int rlflag; /* load device is RL02 */ int rcflag; /* load device is RC25 */ /* * System's disk info structure. * * Disk drive type ID definitions (must be unique): */ /* ra_info: RX33 RX50 RD31 RD32 RD51 RD52 RD53 RD54 RC25 RA60 RA80 RA81 */ /* hp_info: RP04 RP05 RP06 RM02 RM03 RM05 ML11 */ #define RK05 5 #define RX02 1 #define RS03 8 #define RS04 9 #define RL01 10240 #define RL02 20480 #define RK06 0 #define RK07 02000 #define RP02 2 #define RP03 3 #define SD_SYSDSK 1 /* This is the system disk */ #define SD_WINIE 2 /* Disk is a winchester (can be system disk) */ #define SD_USRDSK 4 /* Disk has non-system partition(s) [/user] */ #define SD_FLOPPY 010 /* Floppy disk (rx33 or rx50) */ #define SD_SMALL 020 /* SMALL ROOT (rm -rf /sas to make room) */ #define SD_ML11 040 /* ML11 (no setup user file systems) */ struct sd_info { char *sd_lname; /* disk type name in lowercase */ char *sd_uname; /* disk type name in uppercase */ char *sd_swap; /* /dev/swap link (0 if can't be system disk) */ int sd_type; /* numeric disk type */ char sd_pmask; /* BIT WISE -- disk partition usage mask */ char sd_smask; /* BIT WISE -- partitions taken by system */ char sd_flags; /* flags is flags */ } sd_info[] = { /* DUMMY ENTRY: must be here, see di_info.di_dt[] */ "", "", 0, -1, 0, 0, 0, "rx02", "RX02", 0, RX02, 0, 0, SD_FLOPPY, "rk05", "RK05", 0, RK05, 0, 0, 0, "ml11", "ML11", 0, ML11, 0, 0, SD_ML11, "rx33", "RX33", 0, RX33, 0200, 0, SD_FLOPPY, "rx50", "RX50", 0, RX50, 0200, 0, SD_FLOPPY, "rd31", "RD31", "rd05", RD31, 0341, 0141, SD_WINIE, "rd32", "RD32", "rd02", RD32, 0217, 0007, (SD_WINIE|SD_USRDSK), "rd51", "RD51", "rd00", RD51, 0221, 0021, (SD_WINIE|SD_SMALL), "rd52", "RD52", "rd02", RD52, 0217, 0007, (SD_WINIE|SD_USRDSK), "rd53", "RD53", "rd02", RD53, 0217, 0007, (SD_WINIE|SD_USRDSK), "rd54", "RD54", "rd02", RD54, 0217, 0007, (SD_WINIE|SD_USRDSK), "rl01", "RL01", "rl00", RL01, 0201, 0001, SD_SMALL, "rl02", "RL02", "rl00", RL02, 0203, 0003, SD_SMALL, "rk06", "RK06", "hk01", RK06, 0107, 0007, SD_SMALL, "rk07", "RK07", "hk01", RK07, 0213, 0013, (SD_USRDSK|SD_SMALL), "rp02", "RP02", "rp01", RP02, 0107, 0007, SD_USRDSK, "rp03", "RP03", "rp01", RP03, 0213, 0013, SD_USRDSK, "rp04", "RP04", "hp02", RP04, 0117, 0007, SD_USRDSK, "rp05", "RP05", "hp02", RP05, 0117, 0007, SD_USRDSK, "rp06", "RP06", "hp02", RP06, 0377, 0007, SD_USRDSK, "rm02", "RM02", "hp02", RM02, 0217, 0007, SD_USRDSK, "rm03", "RM03", "hp02", RM03, 0217, 0007, SD_USRDSK, "rm05", "RM05", "hp02", RM05, 0377, 0007, SD_USRDSK, "ra60", "RA60", "ra02", RA60, 0277, 0007, SD_USRDSK, "ra80", "RA80", "ra02", RA80, 0217, 0007, SD_USRDSK, "ra81", "RA81", "ra02", RA81, 0377, 0007, SD_USRDSK, "rc25", "RC25", "rc11", RC25, 0237, 0007, SD_USRDSK, 0 }; /* * File system table (/etc/fstab) information. * Used to blast the initial fstab. */ struct fs_info { char *fs_lname; /* lowercase disk name (same as sd_info) */ char *fs_root; /* disk to mount on root (/) */ char *fs_usr; /* disk to mount on /usr */ } fs_info[] = { "rd31", "rd00", "rd06", "rd32", "rd00", "rd01", "rd51", "rd00", "rd04", "rd52", "rd00", "rd01", "rd53", "rd00", "rd01", "rd54", "rd00", "rd01", "rl01", "rl00", "rl10", "rl02", "rl00", "rl01", "rk06", "hk00", "hk02", "rk07", "hk00", "hk03", "rp02", "rp00", "rp02", "rp03", "rp00", "rp03", "rp04", "hp00", "hp01", "rp05", "hp00", "hp01", "rp06", "hp00", "hp01", "rm02", "hp00", "hp01", "rm03", "hp00", "hp01", "rm05", "hp00", "hp01", "ra60", "ra00", "ra01", "ra80", "ra00", "ra01", "ra81", "ra00", "ra01", "rc25", "rc10", "rc12", 0 }; /* * Disk controller and drive info table. * Loaded with controller type and type of each * configured disk. Used for making the fstab, * special files, and file systems. */ #define DI_MSCP 01 /* MSCP controller flag */ #define DI_MASS 02 /* MASSBUS controller flag */ #define DI_NPD 04 /* Non-partitioned disk flag */ #define DI_HX 010 /* RX02 special case flag */ #define DI_RS 020 /* RS03/4 specical case flag */ int rk_gdti(), rp_gdti(), ra_gdti(), rl_gdti(); int hx_gdti(), hp_gdti(), hs_gdti(), hk_gdti(); struct di_info { char *di_typ; /* Controller type (name string) */ char *di_name; /* Two char ULTRIX-11 mnemonic */ /* ("ra" changed on the fly to ra|rc|rd|rx) */ char di_cn; /* Controller number (if massbus or mscp) */ char di_nunit; /* Number units (0 if cntlr not configured) */ char di_bmaj; /* Block major device number */ char di_rmaj; /* Raw major device number */ int (*di_func)(); /* Call this function to get drive type info */ int di_flags; /* Flags (massbus, mscp, NP disk, etc.) */ int di_dt[8]; /* Each unit's type (index into sd_info[]) */ /* Zero indicates non existent drive */ } di_info[] = { { "RK11", "rk", 0, 0, RK_BMAJ, RK_RMAJ, rk_gdti, DI_NPD }, { "RP11", "rp", 0, 0, RP_BMAJ, RP_RMAJ, rp_gdti, 0 }, { "MSCP", "ra", 0, 0, RA_BMAJ, RA_RMAJ, ra_gdti, DI_MSCP }, { "MSCP", "ra", 1, 0, RA_BMAJ, RA_RMAJ, ra_gdti, DI_MSCP }, { "MSCP", "ra", 2, 0, RA_BMAJ, RA_RMAJ, ra_gdti, DI_MSCP }, { "MSCP", "ra", 3, 0, RA_BMAJ, RA_RMAJ, ra_gdti, DI_MSCP }, { "RL11", "rl", 0, 0, RL_BMAJ, RL_RMAJ, rl_gdti, 0 }, { "RX11", "hx", 0, 0, HX_BMAJ, HX_RMAJ, hx_gdti, DI_HX }, { "MASSBUS", "hp", 0, 0, HP_BMAJ, HP_RMAJ, hp_gdti, DI_MASS }, { "MASSBUS", "hm", 1, 0, HM_BMAJ, HM_RMAJ, hp_gdti, DI_MASS }, { "MASSBUS", "hj", 2, 0, HJ_BMAJ, HJ_RMAJ, hp_gdti, DI_MASS }, { "RK611", "hk", 0, 0, HK_BMAJ, HK_RMAJ, hk_gdti, 0 }, { 0 }, }; /* * Number of 512 byte blocks per cylinder * for each type of disk. * Not affected by 1K block file system. */ #define RP23_BPC 200 /* RP02/3 */ #define RP456_BPC 418 /* RP04/5/6 */ #define RM23_BPC 160 /* RM02/3 */ #define RM5_BPC 608 /* RM05 */ #define RK67_BPC 66 /* RK06/7 */ /* * Disk partition info table. * Used to guide user thru disk partition selection. */ #define PT_USER 1 /* partition has file system on it already */ #define PT_SYS 2 /* partition used by the system */ #define PT_NUP 4 /* non usable (disk doesn't use this partition) */ #define PT_OP 010 /* not usable (overlapped by a used partition) */ struct pt_info { daddr_t pt_sb; /* starting block number (1KB logical block) */ daddr_t pt_nb; /* length in 1KB logical blocks */ char pt_op; /* BIT WISE -- overlapping partitions */ int pt_flags; /* special info flags */ } pt_info[8]; /* * Misc. stuff for setup of user file systems. */ int ufsnum; /* running count of # user file systems */ char fsname[20]; /* superblock fsname (also mounted on directory name) */ char volname[20]; /* superblock volname */ char mntdir[20]; /* mounted on directory (/user#) */ char fmntdir[20]; /* possible alternate mounted on directory */ char bdisk[20]; /* block special file name (/dev/??##) */ char rdisk[20]; /* raw special file name (/dev/r??##) */ /* * Kernel data structures needed to determine * disk controller and drive configuration. */ struct dksize { daddr_t nblocks; /* partition length - 512 byte blocks (sectors) */ int cyloff; /* partition starting cylinder number */ }; struct bdevsw bdevswb; /* * RK05 * NED = -1 * RK05 = 1 */ int nrk; char rk_dt[8]; int rk_size = 4872; /* * RP02/3 * NED = -1 * RP02 = 0 * RP03 = 1 * Note: must read each configured RP02/3 unit to * force update of rp_dt[]. */ int nrp; char rp_dt[8]; struct dksize rp_sizes[8]; /* * MSCP (UDA50 RC25 RQDX RUX50) * NED = 0 * See /usr/include/sys/ra_info.h for drive types. * * Note: MSCP drive type info arrays are non-semetrical * ra_index must be used to access drive type info. */ int nuda; /* Number of configured MSCP controllers */ char nra[MAXUDA]; /* Number of units configured on each controller */ char ra_ctid[MAXUDA];/* Controller type ID and micro-code rev level */ char ra_index[MAXUDA];/* Index into drive type info ra_drv[] */ struct ra_drv ra_drv[MAXUDA*8]; /* RA drive info (see ra_info.h) */ char rq_dt[8]; /* RD/RX disk drive types for iflop() & rflop() */ /* Set up by ra_gdti() */ daddr_t ra_mas[MAXUDA]; /* Size of maintenance area */ struct rasize ud_sizes[8]; /* UDA50 partition sizes */ struct rasize rc_sizes[8]; /* RC25 partition sizes */ struct rasize rq_sizes[8]; /* RQDX partition sizes */ /* * RL01/2 * NED = -1 * RL01 = 10240 * RL02 = 20480 */ int nrl; int rl_dt[4]; /* SIZE: drive type = size (RL01=10240, RL02=20480) */ /* * MASSBUS (HP HM HJ) * NED = 0 * See /usr/include/sys/hp_info.h for drive types. * * Note: MASSBUS drive type info arrays are non-semetrical * hp_index must be used to access drive type info. */ char hp_index[MAXRH]; /* Index into drive type info arrays */ char nhp[MAXRH]; /* Number units per cntlr (0 = not config) */ char hp_dt[MAXRH*8]; /* Drive type of each drive */ struct dksize hp_sizes[32]; /* disk partition sizes */ /* * RK06/7 * NED = -1 * RK06 = 0 * RK07 = 02000 */ int nhk; int hk_dt[8]; struct dksize hk_sizes[8]; /* * Kernel data symbols used to determine number * and type of magtape controllers configured. */ int nht; /* HT - TM02/3 */ int nts; /* TS - TS11/TU80/TSV05/TK25 (TK25 no longer supported) */ int ntm; /* TM - TM11 */ int ntk; /* TK - TK50/TU81 */ char tk_ctid[MAXTK]; /* TK - TU81/TK50 */ /* * Kernel data symbols used to find comm. devices. */ int ntty; /* Total number of TTY structures */ int nttys; /* Number of TTY structures used so far */ int nkl11; /* Number of KL lines (including console) */ int ndl11; /* Number of DL lines */ int ndh11; /* Number of DH lines */ int nuh11; /* Number of DHU/DHV lines */ int dz_cnt; /* Number of DZ/DZV/DZQ lines */ char *dl_name; /* Set to DL11 or DLV11 */ char *uh_name; /* Set to DHU11 or DHV11 */ char *dz_name; /* Set to DZ11 or DZV11 (DZQ11 is out of luck) */ int dz_lpu; /* DZ/DZV lines per unit */ int uh_lpu; /* DHU/DHV lines per unit */ int dh_lpu = 16; /* DH lines per unit */ /* * Number of pseudo ttys and * maus segments. */ int npty; int nmausent; /* * Supported processor table. */ #define NSID 0 #define SID 1 #define QBUS 0 #define UBUS 1 int cpi; /* current processor index into cputyp[] */ int tpi; /* target processor index into cputyp[] */ int ontarget; /* on the target processor ? */ struct cputyp { int p_type; /* processor type */ int p_sid; /* separate I & D space ? */ int p_bus; /* Qbus or Unibus */ } cputyp[] = { 23, NSID, QBUS, 24, NSID, UBUS, 34, NSID, UBUS, 40, NSID, UBUS, 44, SID, UBUS, 45, SID, UBUS, 53, SID, QBUS, 55, SID, UBUS, 60, NSID, UBUS, 70, SID, UBUS, 73, SID, QBUS, 83, SID, QBUS, 84, SID, UBUS, 0 }; int cputype; /* current processor type */ int hz; /* line frequency */ int tzone; /* timezone (minutes behind GMT) */ int dstflag; /* daylight savings time flag */ /* * Variables used to overlay the new values of * hz, timezone, and dstflag onto the kernel. * Both memory (/dev/mem) and a.out (/??unix) * values are replaced. */ int magic; /* kernel magic number (430, 431, 450, 451) */ int novseg; /* number of overlay segments (8 or 32) */ unsigned int txtsiz; /* size of root text segment */ unsigned int ovsz[16]; /* size of each overlay */ long ovsize; /* total size of all overlays */ long tsoff; /* offset to text (32 or 48) */ long dsoff; /* offset to data space in a.out file */ long hzoff; /* offset to hz */ long tzoff; /* offset to timezone */ long dstoff; /* offset to dstflag */ int ab_flag; /* abort flag, set by intr() */ /* * Some stuff for symbolic link of /usr/spool. * Remainder local vairables in main(). */ #define SL_MAXPL 50 /* MAX pathname length */ char *sl_usd = "/usr/spool"; /* * Setup phase definitions: * * Phase 0 - cold start, first time setup runs after sdload. * Phase 1 - doing initial setup, read of setup.info successful. * Phase 2 - initial setup complete, setup restarted after sysgen. * Phase 3 - setup completed, customer wants to change one or more items. * * The setup phase is stored in the first byte of the setup.info * file. The sdload program initializes the phase to zero. */ #define SUP0 0 #define SUP1 1 #define SUP2 2 #define SUP3 3 int phase; main() { int intr(); char *asktt(); register struct sd_info *sdp; struct di_info *dip; register int i, j; int k; int mem, fd; FILE *fi, *fo; int fsp; daddr_t fsz; int crt; int skipit; int sifdirty; long soff; int *bip; int nunits; /* /usr/spool symbolic link stuff */ int sl_islink; char sl_src[SL_MAXPL+1]; char sl_dst[SL_MAXPL+1]; char sl_bdn[SL_MAXPL+1]; char sl_sbdn[DIRSIZ+1]; char sl_rlb[BUFSIZ]; char *p; struct stat statb; mem = -1; /* supdone() needs to if mem open */ crt = -1; /* say we don't know console terminal type */ ab_flag = 0; setjmp(savej); if(ab_flag) { printf("\n\nSETUP PROGRAM interrupted via <CTRL/C>!\n"); printf("\nEXIT SETUP (y to exit, n to restart setup) <y or n> ? "); if(yes(NOHELP) == YES) su_err(0); ab_flag = 0; } signal(SIGINT, intr); /* * The /.profile (calls setup) does stty prterase, so * the terminal will behave like a printing terminal until * we ask the user if it is a CRT. * * Sneek a peek at the setup.info file, just to get the * phase number. If we can't get the phase number, set it * to zero (real read of setup.info will fail later). * Knowing the phase number in advance helps taylor setup's * operation and makes phase 3 less of a pain for the user, * and after all the user is paying the bills! */ phase = SUP0; if((fi = fopen(info, "r")) != NULL) { if(fgets(sphase, 10, fi) != NULL) { if(sphase[1] == '\n') phase = sphase[0] - '0'; } fclose(fi); } if((phase < 0) || (phase > 3)) phase = SUP0; if(phase < SUP3) { phelp("sum1"); phelp("sum2"); prtc(); } else { phelp("sum1"); if(access("/usr/bin", 0) == 0) { phelp("mu_warn"); printf("\n\nIs the system in multiuser mode <y or n> ? "); if(yes(NOHELP) == YES) exit(1); } printf("\n\n\nPrint instructions <y or n> ? "); if(yes(NOHELP) == YES) { phelp("sum2"); prtc(); } } /* * Unless in phase 3, * ask if the console is a CRT and do * stty accordingly. */ if(phase < SUP3) crt = gcrt(); /* * Get the setup phase, system disk, target CPU type, * and load device type * from /.setup/setup.info and validate info. * If they are not valid, ask the user for them. */ printf("\n****** READING SETUP DATA FROM setup.info FILE ******\n"); sifdirty = NO; while(1) { if((fi = fopen(info, "r")) == NULL) { printf("\nCan't open %s file!\n", info); sifdirty = YES; break; } if(fgets(sphase, 10, fi) == NULL) { printf("\nCan't get setup phase from %s!\n", info); sifdirty = YES; break; } zapnl(&sphase); /* change newline to null */ if(fgets(sdname, 10, fi) == NULL) { printf("\nCan't get system disk type from %s!\n", info); sifdirty = YES; break; } zapnl(&sdname); /* change newline to null */ if(fgets(tproc, 10, fi) == NULL) { printf("\nCan't get target CPU type from %s!\n", info); sifdirty = YES; break; } zapnl(&tproc); /* change newline to null */ if(fgets(loadev, 15, fi) == NULL) { printf("\nCan't get load device name from %s!\n", info); sifdirty = YES; break; } zapnl(&loadev); /* change newline to null */ rcflag = -1; rlflag = -1; mtflag = -1; tkflag = 0; rxflag = 0; if((strncmp(loadev, "rx", 2) == 0) && (loadev[3] > '0') && (loadev[3] <= '3')) { rxflag = 1; rxunit = loadev[3] - '0'; } else if((strncmp(loadev, "ht", 2) == 0) || (strncmp(loadev, "ts", 2) == 0) || (strncmp(loadev, "tm", 2) == 0)) mtflag = (loadev[3] - '0') & 3; else if(strncmp(loadev, "tk", 2) == 0) { mtflag = (loadev[3] - '0') & 3; tkflag = 1; } else if(strncmp(loadev, "rl", 2) == 0) rlflag = loadev[3] - '0'; else if(strncmp(loadev, "rc", 2) == 0) rcflag = loadev[3] - '0'; else { printf("\n(%s) - bad load device!\n", loadev); sifdirty = YES; break; } fclose(fi); for(i=0; sd_info[i].sd_lname; i++) if(strcmp(sdname, sd_info[i].sd_lname) == 0) break; if(sd_info[i].sd_lname == 0) { printf("\n(%s) - bad system disk type!\n", sdname); sifdirty = YES; break; } sd_info[i].sd_flags |= SD_SYSDSK; sdunit = sd_info[i].sd_swap[2] - '0'; sdtype = i; phase = sphase[0] - '0'; if((phase < 0) || (phase > 3)) { phase = 0; printf("\n(%s) - bad setup phase number!\n", sphase); sifdirty = YES; break; } if(rlflag >= 0) break; if(rcflag >= 0) break; for(i=0, j=atoi(tproc); cputyp[i].p_type; i++) if(cputyp[i].p_type == j) break; if(cputyp[i].p_type == 0) { printf("\n(%s) - bad target CPU type!\n", tproc); sifdirty = YES; break; } tpi = i; /* save index to target processor type */ break; } usr_info: if(sifdirty == YES) { if(fi != NULL) fclose(fi); phelp("usrinfo"); u_info: printf("\nContinue the installation <y or n> ? "); if(yes(NOHELP) != YES) su_err(ABORT); sprintf(&loadev, "rx(0,0)boot"); /* for write to setup.info */ /* * Ask the user what phase to enter. * This is risky, but it should not be a * problem unless setup.info gets blown away! */ while(1) { phase = 0; do printf("\nSetup phase number (? for help) < 1 2 3 > ? "); while(getline("h_pn") <= 0); phase = atoi(lbuf); if((phase <= 0) || (phase > 3)) { printf("\n(%s) - bad setup phase number!\n", lbuf); continue; } break; } while(1) { rxflag = 0; mtflag = -1; tkflag = 0; rlflag = -1; rcflag = -1; printf("\nWas system loaded from RX50 diskettes <y or n> ? "); if(yes(NOHELP) == YES) { while(1) { do printf("\nFloppy disk unit number < 1 2 3 > ? "); while(getline("h_rxldun") <= 0); if((strlen(lbuf) != 1) || (lbuf[0] < '1') || (lbuf[0] > '3')) { printf("\n(%s) - Bad unit number!\n", lbuf); continue; } rxflag = 1; rxunit = lbuf[0] - '0'; loadev[3] = lbuf[0]; break; } break; } printf("\nWas system loaded from TK50 <y or n> ? "); if(yes(NOHELP) == YES) { mtflag = 0; /* assume unit zero */ tkflag = 1; loadev[0] = 't'; loadev[1] = 'k'; break; } printf("\nWas system loaded from MAGTAPE <y or n> ? "); if(yes(NOHELP) == YES) { mtflag = 0; while(1) { do printf("\nMagtape controller type < tm ht ts > ? "); while(getline("h_mtldct") <= 0); if((strlen(lbuf) != 2) || ((strcmp("ht", lbuf) != 0) && (strcmp("ts", lbuf) != 0) && (strcmp("tm", lbuf) != 0))) { printf("\n(%s) - Invalid cntlr type!\n", lbuf); continue; } loadev[0] = lbuf[0]; loadev[1] = lbuf[1]; break; } break; } printf("\nWas system loaded from RL02 disk pack <y or n> ? "); if(yes(NOHELP) == YES) { rlflag = 0; loadev[1] = 'l'; break; } printf("\nWas system loaded from RC25 disk pack <y or n> ? "); if(yes(NOHELP) == YES) { rcflag = 0; loadev[1] = 'c'; break; } } usr_sdt: while(1) { printf("\nPlease enter the generic system disk name.\n"); printf("\nThese disks are supported:\n"); for(j=0, i=0; sd_info[i].sd_lname; i++) { if(sd_info[i].sd_swap == 0) continue; /* can't be system disk */ if((j & 7) == 0) printf("\n "); printf("%s ", sd_info[i].sd_lname); j++; } printf("\n\nSystem Disk Type: "); for(i=0; i<10; i++) { sdname[i] = getchar(); if(sdname[i] == '\n') { sdname[i] = '\0'; break; } } for(i=0; sd_info[i].sd_lname; i++) if(strcmp(sdname, sd_info[i].sd_lname) == 0) break; if(sd_info[i].sd_lname == 0) { printf("\n(%s) - bad system disk!\n", sdname); continue; } sd_info[i].sd_flags |= SD_SYSDSK; sdunit = sd_info[i].sd_swap[2] - '0'; sdtype = i; break; } usr_cpt: if((rlflag < 0) && (rcflag < 0)) { while(1) { phelp("tcpu"); printf("\n\nTarget Processor Type: "); for(i=0; i<10; i++) { tproc[i] = getchar(); if(tproc[i] == '\n') { tproc[i] = '\0'; break; } } for(i=0, j=atoi(tproc); cputyp[i].p_type; i++) if(cputyp[i].p_type == j) break; if(cputyp[i].p_type == 0) { printf("\n(%s) - bad target CPU type!\n", tproc); continue; } tpi = i; break; } } } info_ok: /* * Get current CPU type and lots of other * needed info from the kernel. */ if(nlist("/unix", nl) < 0) { printf("\nCan't access namelist in /unix!\n"); su_err(FATAL); } if((nl[X_CPUTYPE].n_value == 0) || (nl[X_HZ].n_value == 0) || (nl[X_TIMEZONE].n_value == 0) || (nl[X_DSTFLAG].n_value == 0)) { printf("\nCan't get needed symbol values from "); printf("/unix namelist!\n"); su_err(FATAL); } if((mem = open("/dev/mem", 2)) < 0) { printf("\nCan't open memory (/dev/mem)!\n"); su_err(FATAL); } lseek(mem, (long)nl[X_CPUTYPE].n_value, 0); read(mem, (char *)&cputype, sizeof(cputype)); for(cpi=0; cputyp[cpi].p_type; cpi++) if(cputyp[cpi].p_type == cputype) break; if(rxflag || (rlflag >= 0) || (rcflag >= 0)) { sprintf(tproc, "%d", cputype); tpi = cpi; } /* * Phase 0 is not visable to the user, it is * only internal to setup. */ printf("\nSETUP PHASE = %d", (phase == 0) ? 1 : phase); switch(phase) { case SUP0: case SUP1: printf(" (Initial Setup)"); break; case SUP2: printf(" (Final Setup)"); break; case SUP3: printf(" (Change Setup)"); break; /* NO DEFAULT: phase checked before we get here */ } printf("\nLOAD DEVICE TYPE = "); if(rxflag) printf("FLOPPY DISK UNIT %d", rxunit); else if(rlflag >= 0) printf("RL02 UNIT %d", rlflag); else if(rcflag >= 0) printf("RC25 UNIT %d", rcflag); else if(tkflag) printf("TK50 UNIT %d", mtflag); else printf("MAGTAPE UNIT %d", mtflag); printf("\nSYSTEM DISK TYPE = %s", sd_info[sdtype].sd_uname); printf("\nCURRENT CPU TYPE = 11/%d", cputype); printf("\nTARGET CPU TYPE = 11/%s", tproc); printf("\n\nIs the above information correct <y or n> ? "); if(yes(NOHELP) != YES) { phelp("info_err"); goto u_info; } /* * If we had to ask the user for the info that should * have come from setup.info, write the user entered * info back to the setup.info file. So, it will be * correct next time (most likely in setup phase 3). */ if(sifdirty == YES) { while(1) { if((fo = fopen(info, "w")) == NULL) { printf("\nWARNING: can't create %s file!\n", info); break; } fprintf(fo, "%d\n%s\n%d\n%s\n", phase, sd_info[sdtype].sd_lname, cputyp[tpi].p_type, loadev); fclose(fo); break; } } /* * Finally know what phase we are really in! * Modify setup.info to current phase. */ if((phase == SUP0) || ((phase == SUP1) && sifdirty)) { /* * Arrange for a copy of the generic kernel to be * preserved in case of disaster. * Do this on first call of setup only! */ if(access("/gunix", 0) != 0) link("/unix", "/gunix"); sync(); phase = SUP1; wrtpn(phase); } printf("\n****** ENTERING SETUP PHASE %d ******\n", phase); /* * If the system disk has a small root (SD_SMALL), * RD51, RL01, RL02, RK06, RK07, * remove the /sas directory (unload saprog). * The /sas files are always loaded from magtape or TK50, * this frees up some space in a tight root. User can re-load * saprog with osload if he/she really wants it. */ if((phase == SUP1) && (sd_info[sdtype].sd_flags&SD_SMALL)) system("rm -rf /sas"); /* * If target CPU type equals the current CPU type, * ask the user if this is the target CPU. * If they are not equal, we know it is not the target CPU. * Hate to ask the user, but it is a critical peice of info * and there is no other way to get it! * NOTE: If not loading from a magtape kit, must be on target CPU! */ if(phase == SUP1) { if(tpi != cpi) { if(mtflag < 0) { printf("\nNOT LOADING FROM MAGTAPE (or TK50): "); printf("must install on target processor!\n"); su_err(FATAL); } else ontarget = NO; } else { while(1) { if(mtflag < 0) { ontarget = YES; break; } printf("\nIs this the target processor "); printf("(? for help) <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_otp"); continue; } ontarget = j; printf("%s%sthe target processor <y or n> ? ", confirm, (j == YES) ? "on " : "not on "); if(yes(NOHELP) != YES) continue; break; } } } else ontarget = YES; /* all other phase must be done on target CPU */ /* * Blast temporary /etc/ttys and /etc/ttytype files * containing entries for the console terminal only. * The real files will be blasted after the new kernel * is installed and we know what devices are configured. */ if(phase < SUP2) if(bttys(crt, 0, 0) < 0) su_err(FATAL); /* * If phase 3, ask user if console terminal type * needs to be changed (CRT/PRT). */ if(phase == SUP3) { printf("\nChange console terminal type (CRT vs HARDCOPY) <y or n> ? "); if(yes(NOHELP) == YES) crt = gcrt(); } /* * Ask for info on hz, timezone, & dstflag. */ switch(phase) { case SUP0: case SUP1: skipit = NO; break; case SUP2: skipit = YES; break; case SUP3: printf("\nChange line frequency, timezone, or daylight "); printf("savings time <y or n> ? "); if(yes(NOHELP) == YES) skipit = NO; else skipit = YES; break; } g_hz: while(1) { if(skipit == YES) break; do { printf("\nWhat is your AC power line frequency in hertz"); printf(" < 50 or 60 > ? "); } while(getline("h_hz") <= 0); hz = atoi(lbuf); if((hz != 50) && (hz != 60)) printf("\nLine frequency should be 50 or 60 hertz!\n"); printf("%sAC line frequency is %d hertz <y or n> ? ", confirm, hz); if(yes(NOHELP) != YES) continue; break; } g_tz: while(1) { if(skipit == YES) break; do { printf("\nWhat is your local time zone "); printf("< hours west/behind GMT > ? "); } while(getline("h_tz") <= 0); tzone = atoi(lbuf); if((tzone < 0) || (tzone > 23)) { printf("\n%d - invalid time zone!\n", tzone); continue; } printf("%stime zone is %d hours west/behind GMT <y or n> ? ", confirm, tzone); if(yes(NOHELP) != YES) continue; tzone *= 60; break; } g_dst: while(1) { if(skipit == YES) break; printf("\nDoes your local area use daylight savings time <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_dst"); continue; } if(j == YES) { dstflag = 1; } else dstflag = 0; printf("%sdaylight savings time%sin use <y or n> ? ", confirm, dstflag ? " " : " not "); if(yes(NOHELP) != YES) continue; break; } if(dstflag) while(1) { dstflag = get_dst(); /* Get geographic area */ printf("%s Geographic area is %d <y or n> ?",confirm,dstflag); if(yes(NOHELP) != YES) continue; break; } /* * Overlay new HZ, TIMEZONE, and DSTFLAG * onto kernel a.out file (/unix). */ if(skipit == NO) { if((fd = open("/unix", 2)) < 0) { printf("\nCan't open /unix for read/write!\n"); su_err(FATAL); } read(fd, (char *)&magic, sizeof(magic)); switch(magic) { case 0430: case 0431: novseg = 8; tsoff = 32L; break; case 0450: case 0451: novseg = 16; tsoff = 48L; break; default: printf("\nType %o kernels not supported!\n", magic); su_err(FATAL); } read(fd, (char *)&txtsiz, sizeof(txtsiz)); lseek(fd, 16L, 0); read(fd, (char *)&ovsz, sizeof(ovsz)); ovsize = 0; for(i=1; i<novseg; i++) ovsize += ovsz[i]; dsoff = (long)tsoff + (long)txtsiz + (long)ovsize; /* data space offset */ hzoff = dsoff + (long)nl[X_HZ].n_value; tzoff = dsoff + (long)nl[X_TIMEZONE].n_value; dstoff = dsoff + (long)nl[X_DSTFLAG].n_value; if((magic == 0430) || (magic == 0450)) { hzoff -= 060000L; tzoff -= 060000L; dstoff -= 060000L; } #ifdef DEBUG printf("%shzoff=%O tzoff=%O dstoff=%O\n", debug, hzoff, tzoff, dstoff); #endif DEBUG lseek(fd, (long)hzoff, 0); write(fd, (char *)&hz, sizeof(hz)); lseek(fd, (long)tzoff, 0); write(fd, (char *)&tzone, sizeof(tzone)); lseek(fd, (long)dstoff, 0); write(fd, (char *)&dstflag, sizeof(dstflag)); close(fd); sync(); /* * Overlay new HZ, TIMEZONE, and DSTFLAG * onto the running kernel (/dev/mem). */ lseek(mem, (long)nl[X_HZ].n_value, 0); write(mem, (char *)&hz, sizeof(hz)); lseek(mem, (long)nl[X_TIMEZONE].n_value, 0); write(mem, (char *)&tzone, sizeof(tzone)); lseek(mem, (long)nl[X_DSTFLAG].n_value, 0); write(mem, (char *)&dstflag, sizeof(dstflag)); } /* * Set the date and time. */ g_date: while(1) { if((phase != SUP3) || ((phase == SUP3) && (skipit == NO))) { do { printf("\nPlease enter the current date/time "); printf("< yymmddhhmm.ss > ? "); } while(getline("h_date") <= 0); printf("\n"); sprintf(syscmd, "date %s", lbuf); if(system(syscmd) != 0) { printf("\nAttempt to set date/time failed!\n"); continue; } } else { printf("\n"); system("date"); } printf("%sdate/time correct <y or n> ? ", confirm); if(yes(NOHELP) != YES) { skipit = NO; continue; } sync(); break; } /* * Select split or non-split I/D space commands in /bin. * The selection will be made twice if the current CPU has * split I/D space and the target CPU does not, or visa versa. */ sel_bin: while(1) { if(phase != SUP1) break; if(access(rclock, 0) == 0) break; /* /bin commands already selected */ printf("\n****** SELECTING%sSPLIT I/D COMMANDS (/bin) ******\n", (cputyp[cpi].p_sid == SID) ? " " : " NON-"); if(chngdir("/bin")) su_err(FATAL); #ifdef DEBUG printf("%s", debug); fflush(stdout); system("ls sid"); /* sid/nsid contain same files */ #endif DEBUG if(cputyp[cpi].p_sid == SID) sprintf(syscmd, "cp sid/* ."); else sprintf(syscmd, "cp nsid/* ."); if(system(syscmd) != 0) { printf("\nCan't `%s' in /bin!\n", syscmd); su_err(FATAL); } sync(); #ifdef DEBUG printf("%s/lib/c2\n", debug); #endif DEBUG system("rm -f /lib/c2"); if(cputyp[cpi].p_sid == SID) sprintf(syscmd, "ln /lib/c2_id /lib/c2"); else sprintf(syscmd, "ln /lib/c2_ov /lib/c2"); if(system(syscmd) != 0) { printf("\nCan't `%s'!\n", syscmd); su_err(FATAL); } sync(); if(chngdir(homedir)) su_err(FATAL); if(cputyp[cpi].p_sid == cputyp[tpi].p_sid) { /* selection final */ creat(rclock, 0444); /* create lock file */ sync(); } break; } /* * Remove the alternate commands directories (/bin/sid & /bin/nsid). * ONLY if the lock file exists (final selection made). */ while(1) { if(phase != SUP1) break; if(access(rclock, 0) != 0) break; /* final selection not made yet */ if((access("/bin/sid", 0) != 0) && (access("/bin/nsid", 0) != 0)) break; /* /bin commands already removed */ #ifdef DEBUG printf("%sremove /bin/sid and /bin/nsid <y or n> ? ", debug); if(yes(NOHELP) != YES) break; #endif DEBUG system("rm -r /bin/sid /bin/nsid"); sync(); break; } /* * Zero the error log file. */ if(phase == SUP1) { printf("\n****** ZEROING THE ERROR LOG FILE ******\n"); if(system("/etc/eli -f > /dev/null 2>&1") != 0) { printf("\nCan't zero the error log file\n"); su_err(FATAL); } } /* * Make device special files. * If in phase 1, only make special files * for drives on the system disk controller and * magtapes (if any). * Also, take care of the work that used to be * done by /dev/makefile, i.e., system disk special files, * chmod 400 partition 7 (sometimes 6), /dev/swap file, * basic /etc/fstab, and boot block (redundant). * * If phase 2, make all special files. * If phase 3, ask user if we need to make special files. * NOTE: Even if the users says no, we go thru the motions of * making the special files, because the system config info * gathered is needed by some of the following steps. */ switch(phase) { case SUP0: case SUP1: case SUP2: skipit = NO; break; case SUP3: while(1) { printf("\nChange device special files <y or n> ? "); j = yes(HELP); if(j == YES) skipit = NO; else if(j == NO) skipit = YES; else if(j == HELP) { phelp("h_csf"); continue; } break; } break; /* DEFAULT CASE NOT NEEDED */ } if(chngdir("/dev")) su_err(FATAL); /* * Find out what disk controllers/drives are present * and save the necessary info in the di_info[] table. * * 1. Read bdevsw[] entry for disk controller. * 2. If d_tab entry is 0, controller not configured. * 3. Make a special file to access cntlr unit 0. * 4. Open unit 0 to force driver to load ??_dt[] with drive types. * Note: RP require reading each unit. * 5. Call appropriate routine to get drive type info and * load it into di_info[]. * */ while(1) { if((phase > SUP1) && (skipit == NO)) { if(phase == SUP2) { phelp("msf_rec"); prtc(); } printf("\n****** DETERMINING SYSTEM'S DISK CONFIGURATION ******\n"); } for(dip=di_info; dip->di_typ; dip++) { /* 1 */ soff = (long)nl[X_BDEVSW].n_value + (long)(sizeof(struct bdevsw) * dip->di_bmaj); lseek(mem, (long)soff, 0); read(mem, (char *)&bdevswb, sizeof(struct bdevsw)); /* 2 */ dip->di_nunit = 0; if(bdevswb.d_tab == 0) continue; /* 3 */ unlink(dsk_sfn); k = (dip->di_rmaj << 8); if(dip->di_flags&DI_MSCP) k |= (dip->di_cn << 6); if(mknod(dsk_sfn, 020400, k) < 0) { printf("\nmknod for %s controller %d failed!\n", dip->di_typ, dip->di_cn); su_err(FATAL); } /* 4 */ if((i = open(dsk_sfn, 0)) >= 0) close(i); unlink(dsk_sfn); /* 5 */ for(i=0; i<8; i++) /* set all drive types to NED */ dip->di_dt[i] = 0; (*dip->di_func)(MSF, dip, mem); /* get drive type info */ } break; } /* * If phase 1, don't print disk configuration and only * make special files for drives on the system disk controller. * * If phase 2, print the system's disk configuration * and make the disk special files. * * If phase 3, print the disk configuration then ask * if the user wants to remake the special files. * * DEPENDENCY: TODO: fixed by sdunit -- check it! * * This code assumes that the system disk is always unit 0. * This is true execpt for the RC25 which is unit 1, but the * code still works because, even though the system disk is * unit 1, unit 0 will also be an RC25. */ while(1) { if(skipit == YES) break; if(phase > SUP1) pdconf(MSF); if(phase == SUP2) { prtc(); } if(phase == SUP3) { phelp("cmp_info"); while(1) { printf("\nHas the disk configuration changed "); printf("(? for help) <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_rmsf"); continue; } else break; } if(j == NO) break; } printf("\n****** MAKING "); if(phase == SUP1) printf("SYSTEM DISK(s) "); else printf("DISK "); printf("SPECIAL FILES ******\n"); for(dip=di_info; dip->di_typ; dip++) { if(dip->di_nunit == 0) continue; /* * Following due to HACK in KLESI bus adaptor design! * Get unit status returns valid unit type (rc25) even if * the drive is not present. We only need first two units * during phase one. Things work ok in phase two, assuming * user only configures units that really exist. */ if((phase == SUP1) && (strcmp("KLESI", dip->di_typ) == 0)) nunits = 2; else nunits = dip->di_nunit; for(i=0; i<nunits; i++) { if(dip->di_dt[i] == 0) continue; if(dip->di_flags&(DI_MSCP|DI_MASS)) sprintf(syscmd, "/etc/msf %s -c %d %d", sd_info[dip->di_dt[i]].sd_lname, dip->di_cn, i); else sprintf(syscmd, "/etc/msf %s %d", sd_info[dip->di_dt[i]].sd_lname, i); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } /* TODO: following done in P1 & P2, I think that's ok! */ if(((sd_info[dip->di_dt[i]].sd_flags&SD_SYSDSK) == 0) || (i != sdunit) || (dip->di_cn != sdcntlr)) continue; /* following only done for system disk */ /* * Create /dev/swap so PS and other programs * can access the swap area. */ unlink("/dev/swap"); if(link(sd_info[sdtype].sd_swap, "/dev/swap") < 0) { printf("\nCan't link %s to /dev/swap!\n", sd_info[sdtype].sd_swap); su_err(FATAL); } sync(); /* * Blast the initial /etc/fstab (root & /usr entries only). */ for(j=0; fs_info[j].fs_lname; j++) if(strcmp(sd_info[sdtype].sd_lname, fs_info[j].fs_lname) == 0) break; /* THIS CAN'T HAPPEN! */ if(fs_info[j].fs_lname == 0) { printf("\nPANIC: sd_info & fs_info names don't match!\n"); su_err(FATAL); } unlink("/etc/fstab"); if((fo = fopen("/etc/fstab", "w")) == NULL) { printf("\nCreate of /etc/fstab file failed!\n"); su_err(FATAL); } fprintf(fo, "/dev/%s:/:rw:0:1\n", fs_info[j].fs_root); fprintf(fo, "/dev/%s:/usr:rw:0:1\n", fs_info[j].fs_usr); fclose(fo); sync(); /* * DD the boot block from /mdec to block zero of the * system disk, sdload does this, but we do it to be sure! */ sprintf(syscmd, "dd if=/mdec/%suboot of=%s count=1 > /dev/null 2>&1", (dip->di_flags&DI_MSCP) ? "ra" : dip->di_name, dsfn(RAW, sdunit, 0, dip)); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG system(syscmd); sync(); } } break; } /* * Find out what magtape controllers are present * and how many drives are configured. * * If phase 2, print magtape config and make special files. * * If phase 3, print magtape config, ask user if special files need remaking. * * TODO: what about multiple tape cntlr type clashes? * what about crash dump device? */ while(1) { if(phase < SUP1) break; if((skipit == NO) && (phase > SUP1)) printf("\n****** DETERMINING SYSTEM'S TAPE CONFIGURATION ******\n"); nht = nts = ntm = ntk = 0; for(i=0; i<MAXTK; i++) tk_ctid[i] = 0; if(nl[X_NHT].n_value) { lseek(mem, (long)nl[X_NHT].n_value, 0); read(mem, (char *)&nht, sizeof(nht)); } if(nl[X_NTS].n_value) { lseek(mem, (long)nl[X_NTS].n_value, 0); read(mem, (char *)&nts, sizeof(nts)); } if(nl[X_NTM].n_value) { lseek(mem, (long)nl[X_NTM].n_value, 0); read(mem, (char *)&ntm, sizeof(ntm)); } if(nl[X_NTK].n_value) { lseek(mem, (long)nl[X_NTK].n_value, 0); read(mem, (char *)&ntk, sizeof(ntk)); } if(nl[X_TK_CTID].n_value) { lseek(mem, (long)nl[X_TK_CTID].n_value, 0); read(mem, (char *)&tk_ctid, sizeof(tk_ctid)); for(i=0; i<MAXTK; i++) tk_ctid[i] = (tk_ctid[i] >> 4) & 017; } if(skipit == YES) break; if(phase > SUP1) { printf("\nMagtape Controller # Units"); printf("\n------------------ -------"); } j = 0; if(nht) { if(phase > SUP1) printf("\nTM02/3 - TU16/TE16/TU77 %d", nht); j++; } if(nts) { if(phase > SUP1) /* TK25 no longer supported */ printf("\nTS11/TU80/TS05 %d", nts); j++; } if(ntm) { if(phase > SUP1) printf("\nTM11 - TU10/TE10/TS03 %d", ntm); j++; } if(ntk) { if(phase > SUP1) printf("\nTK50/TU81 %d", ntk); j++; } /* * TODO: remove after debug if(tk_ctid) { i = 0; switch(tk_ctid) { case TK50: if(phase > SUP1) printf("\nTK50"); break; case TU81: if(phase > SUP1) printf("\nTU81"); break; default: if(phase > SUP1) printf("\nTK50/TU81 configured, but not present!\n"); i++; break; } if(i == 0) { j++; if(phase > SUP1) printf(" 1"); } } */ if(j == 0) { if(phase > SUP1) printf("\nNO MAGTAPES FOUND!\n"); break; } else if(phase > SUP1) printf("\n"); if(phase == SUP2) { prtc(); } if(phase == SUP3) { phelp("cmp_info"); while(1) { printf("\nHas the magtape configuration changed "); printf("(? for help) <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_rmsf"); continue; } else break; } if(j == NO) break; } printf("\n****** MAKING MAGTAPE SPECIAL FILES ******\n"); if(nht) { for(i=0; i<nht; i++) { sprintf(syscmd, "/etc/msf tm03 %d", i); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } } if(nts) { for(i=0; i<nts; i++) { sprintf(syscmd, "/etc/msf ts11 %d", i); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } } if(ntm) { for(i=0; i<ntm; i++) { sprintf(syscmd, "/etc/msf tm11 %d", i); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } } if(ntk) { for(i=0; i<ntk; i++) { if(tk_ctid[i] == TK50) sprintf(syscmd, "/etc/msf tk50 %d", i); else if(tk_ctid[i] == TU81) sprintf(syscmd, "/etc/msf tu81 %d", i); else { printf("\n\7\7\7TK50/TU81 unit %d: can't get ", i); printf("drive type (no special files created)!"); printf("\nRerun setup or use msf(8) to create "); printf("TK50 or TU81 special files.\n"); } #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } } sync(); break; } /* * Find out what comm. devices area configured and * how many units/lines of each type are configured. * * If phase 2, print comm. config and make special files. * * If phase 3, print comm. config, ask user if special files need remaking. * * TODO: what about misc. devices (du ?) and console, mem, lp? */ while(1) { if(phase < SUP2) break; if(skipit == NO) { printf("\n****** DETERMINING SYSTEM'S COMMUNICATIONS DEVICE "); printf("CONFIGURATION ******\n"); } if(cputyp[cpi].p_bus == QBUS) { dz_lpu = 4; uh_lpu = 8; dl_name = "DLV11"; dz_name = "DZV11"; uh_name = "DHV11"; } else { dz_lpu = 8; uh_lpu = 16; dl_name = "DL11"; dz_name = "DZ11"; uh_name = "DHU11"; } lseek(mem, (long)nl[X_NTTY].n_value, 0); read(mem, (char *)&ntty, sizeof(ntty)); ntty--; /* don't count console */ if(nl[X_NKL11].n_value) { lseek(mem, (long)nl[X_NKL11].n_value, 0); read(mem, (char *)&nkl11, sizeof(nkl11)); nkl11--; /* don't count console */ } if(nl[X_NDL11].n_value) { lseek(mem, (long)nl[X_NDL11].n_value, 0); read(mem, (char *)&ndl11, sizeof(ndl11)); } if(nl[X_NDH11].n_value) { lseek(mem, (long)nl[X_NDH11].n_value, 0); read(mem, (char *)&ndh11, sizeof(ndh11)); } if(nl[X_NUH11].n_value) { lseek(mem, (long)nl[X_NUH11].n_value, 0); read(mem, (char *)&nuh11, sizeof(nuh11)); } if(nl[X_DZ_CNT].n_value) { lseek(mem, (long)nl[X_DZ_CNT].n_value, 0); read(mem, (char *)&dz_cnt, sizeof(dz_cnt)); } if(skipit == YES) break; printf("\nDevice # Units Lines/Unit"); printf("\n------ ------- ----------"); if((i = nkl11 + ndl11) > 0) printf("\n%-6s %-7d 1", dl_name, i); if(ndh11) printf("\n%-6s %-7d %d", "DH11", (ndh11/dh_lpu), dh_lpu); if(nuh11) printf("\n%-6s %-7d %d", uh_name, (nuh11/uh_lpu), uh_lpu); if(dz_cnt) printf("\n%-6s %-7d %d", dz_name, (dz_cnt/dz_lpu), dz_lpu); if((nkl11 + ndl11 + ndh11 + nuh11 + dz_cnt) == 0) { printf("\nNO COMMUNICATIONS DEVICES FOUND!\n"); break; } else printf("\n"); if(phase == SUP2) { prtc(); } if(phase == SUP3) { phelp("cmp_info"); while(1) { printf("\nHas the communications configuration "); printf("changed (? for help) <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_rmsf"); continue; } else break; } if(j == NO) break; } printf("\n****** MAKING COMMUNICATIONS DEVICE SPECIAL FILES ******\n"); printf("\nCommunications port assignments:\n"); k = 0; nttys = 0; if((i = nkl11 + ndl11) > 0) { sprintf(syscmd, "/etc/msf dlv11 %d tty%02d", i, nttys); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } sync(); for(j=0; j<i; j++) { k = 1; printf("\n%s\tUNIT %d\t\t/dev/tty%02d", dl_name, j, j); if((++nttys % 16) == 0) { k = 0; printf("\n"); prtc(); } } } if(ndh11) { for(i=0; i<ndh11; i++) { if((i % dh_lpu) == 0) { sprintf(syscmd, "/etc/msf dh11 %d tty%02d", (i/dh_lpu), nttys); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } sync(); k = 1; printf("\nDH11\tUNIT %d\tLINE %d\t/dev/tty%02d", (i/dh_lpu), (i%dh_lpu), nttys); if((++nttys % 16) == 0) { k = 0; printf("\n"); prtc(); } } } if(nuh11) { for(i=0; i<nuh11; i++) { if((i % uh_lpu) == 0) { if(cputyp[cpi].p_bus == QBUS) sprintf(syscmd, "/etc/msf dhv11 %d tty%02d", (i/uh_lpu), nttys); else sprintf(syscmd, "/etc/msf dhu11 %d tty%02d", (i/uh_lpu), nttys); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } sync(); k = 1; printf("\n%s\tUNIT %d\tLINE %d\t/dev/tty%02d", uh_name, (i/uh_lpu), (i%uh_lpu), nttys); if((++nttys % 16) == 0) { k = 0; printf("\n"); prtc(); } } } if(dz_cnt) { for(i=0; i<dz_cnt; i++) { if((i % dz_lpu) == 0) { if(cputyp[cpi].p_bus == QBUS) sprintf(syscmd, "/etc/msf dzv11 %d tty%02d", (i/dz_lpu), nttys); else sprintf(syscmd, "/etc/msf dz11 %d tty%02d", (i/dz_lpu), nttys); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } } sync(); k = 1; printf("\n%s\tUNIT %d\tLINE %d\t/dev/tty%02d", dz_name, (i/dz_lpu), (i%dz_lpu), nttys); if((++nttys % 16) == 0) { k = 0; printf("\n"); prtc(); } } } if(k) printf("\n"); break; } /* * Make the pseudo TTYs. * * In phase 2, create them. * * In phase 3, ask if they changed, re-create if necessary. */ while(1) { if(phase < SUP2) break; if(skipit == NO) printf("\n****** DETERMINING NUMBER OF PSEUDO TTYS ******\n"); lseek(mem, (long)nl[X_NPTY].n_value, 0); read(mem, (char *)&npty, sizeof(npty)); if(skipit == YES) break; if(npty) printf("\nNumber of PTTYs = %d\n", npty); else { printf("\nNO PSEUDO TTYS FOUND!\n"); break; } if(phase == SUP2) { prtc(); } if(phase == SUP3) { phelp("cmp_info"); printf("\nHas number of PTTYs changed <y or n> ? "); j = yes(NOHELP); if(j == NO) break; } sprintf(syscmd, "/etc/msf ptty %d", npty); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } sync(); break; } /* * Make maus special files. * * In phase 2, create them. * * In phase 3, ask if they changed, re-create if necessary. */ while(1) { if(phase < SUP2) break; if(skipit == NO) printf("\n****** DETERMINING NUMBER OF MAUS SEGMENTS ******\n"); if(nl[X_NMAUSENT].n_value) { lseek(mem, (long)nl[X_NMAUSENT].n_value, 0); read(mem, (char *)&nmausent, sizeof(nmausent)); } else nmausent = 0; if(skipit == YES) break; if(nmausent) printf("\nNumber of MAUS segments = %d\n", nmausent); else { printf("\nMAUS NOT CONFIGURED!\n"); break; } printf("\n****** MAKING MAUS SPECIAL FILES ******\n"); sprintf(syscmd, "/etc/msf maus %d", nmausent); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } sync(); break; } /* * Create the real /etc/ttys and /etc/ttytype files. * * If phase 2, just create them. * * If phase 3, ask user they should be created, save old ones if yes. */ while(1) { if(phase < SUP2) break; if(phase != SUP3) { printf("\n****** CREATING /etc/ttys and /etc/ttytype "); printf("FILES ******\n"); } if(phase == SUP3) { while(1) { printf("\nCreate new ttys and ttytype files <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_ttys"); continue; } else break; } if(j == NO) break; printf("\nSaving current files: /etc/ttys.old "); printf("and /etc/ttytype.old!\n"); sprintf(syscmd, "cp /etc/ttys /etc/ttys.old"); if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } sprintf(syscmd, "cp /etc/ttytype /etc/ttytype.old"); if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } sync(); } if(crt == -1) crt = gcrt(); if(bttys(crt, ntty, npty) < 0) su_err(FATAL); break; } if(chngdir(homedir)) su_err(FATAL); /* * OLDCODE * Mount the /usr file system so we can load * or otherwise mundge the sysgen files. * Leave /usr mounted for later operations. */ /* if(usrmnt(MOUNT)) /* mount /usr file system */ /* su_err(FATAL); */ system("/etc/mount /usr >/dev/null 2>&1"); if((phase == SUP1) && rxflag) { printf("\n****** LOADING SYSGEN FILES ******\n"); iflop("SYSGEN #1"); if(chngdir("/usr")) su_err(FATAL); sprintf(syscmd, "tar xpbf 10 /dev/rrx%d ./sys/conf", rxunit); if(cputyp[tpi].p_sid == SID) strcat(syscmd, " ./sys/sys"); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG while(system(syscmd) != 0) { if(retry("SYSGEN FILES LOAD")) continue; else su_err(FATAL); } sync(); 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) { fmnt("SYSGEN #2"); chngdir("/usr/sys/ovsys"); system("ar x /mnt/LIB1_ov"); system("chog sys *"); system("chmod 444 *"); chngdir("../ovnet"); 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(chngdir("/usr")) su_err(FATAL); sprintf(syscmd, "tar xpbf 10 /dev/rrx%d ./sys", rxunit); iflop("SYSGEN #3"); #ifdef DEBUG printf("%s%s\n", debug, syscmd); #endif DEBUG while(system(syscmd) != 0) { if(retry("SYSGEN FILES LOAD")) continue; else su_err(FATAL); } sync(); rflop("SYSGEN #3"); } fmnt("SYSGEN #4"); if(cputyp[tpi].p_sid == NSID) { chngdir("/usr/sys/ovdev"); system("cp /mnt/asmfix? ."); system("ar x /mnt/LIB2_ov"); } else { chngdir("/usr/sys/net"); system("ar x /mnt/LIB3_id"); } system("chog sys *"); system("chmod 444 *"); fmnt(0); sync(); rflop("SYSGEN #4"); chngdir("/usr/sys"); if(cputyp[tpi].p_sid == SID) system("chmod 755 sys dev net"); else system("chmod 755 ovsys ovdev ovnet"); system("chog sys *"); if(chngdir(homedir)) su_err(FATAL); printf("\n"); } /* * Remove unused sysgen libraries depending on * whether or not CPU has split I/D space. */ if((phase == SUP1) && (rxflag == 0)) { if(cputyp[tpi].p_sid == SID) { system("rm -f /usr/sys/conf/mch_ov.o"); system("rm -rf /usr/sys/ovsys /usr/sys/ovdev /usr/sys/ovnet"); } else { system("rm -f /usr/sys/conf/mch_id.o"); system("rm -f /usr/sys/sys/LIB1_id /usr/sys/dev/LIB2_id"); system("rm -f /usr/sys/sys/*.o /usr/sys/net/*.o"); } sync(); } /* * Select the appropriate .profile for /usr/sys. * Save a copy in /usr/skel/sys_profile, so osload will get * the correct one if it has to reload sysgen (GROSS!). * If crt is -1, assume console TTY type didn't change. */ if(crt >= 0) { if(crt == YES) system("cp /usr/skel/sys_crt.profil /usr/sys/.profile"); else system("cp /usr/skel/sys_prt.profil /usr/sys/.profile"); system("cp /usr/sys/.profile /usr/skel/sys_profile"); } /* * Ask the user for the hostname. */ g_hostn: switch(phase) { case SUP0: skipit = YES; break; case SUP1: skipit = YES; break; case SUP2: skipit = NO; break; case SUP3: printf("\nChange the system's hostname <y or n> ? "); if(yes(NOHELP) == YES) skipit = NO; else skipit = YES; break; } if(skipit == NO) printf("\n****** NAMING YOUR ULTRIX-11 SYSTEM ******\n"); while(1) { if(skipit == YES) break; do printf("\nPlease enter your system's hostname <? for help> ? "); while(getline("h_hostn") <= 0); if(strlen(lbuf) > 16) { printf("\nHostname too long (16 char max)!\n"); continue; } j = 0; for(i=0; lbuf[i]; i++) { if((lbuf[i] >= 'a') && (lbuf[i] <= 'z')) continue; if((lbuf[i] >= '0') && (lbuf[i] <= '9')) continue; if(lbuf[i] == '-') continue; j++; } if(j) { printf("\nBad Hostname (lowercase alphanumeric only)!\n"); continue; } printf("%shostname is `%s' <y or n> ? ", confirm, lbuf); if(yes(NOHELP) != YES) continue; if((fi = fopen("/etc/rc", "r")) == NULL) { printf("\nCan't open /etc/rc file for reading!\n"); su_err(FATAL); } if((fo = fopen("/tmp/rc.setup", "w")) == NULL) { printf("\nCan't create /tmp/rc.setup file!\n"); su_err(FATAL); } while(1) { if(fgets(syscmd, SCSIZE, fi) == NULL) { fclose(fi); fclose(fo); break; } if(strlen(syscmd) == (SCSIZE - 1)) { printf("\n/etc/rc format error: line too long!\n"); su_err(FATAL); } if(strncmp(syscmd, "hostname", 8) == 0) fprintf(fo, "hostname %s\n", lbuf); else fprintf(fo, "%s", syscmd); } sprintf(syscmd, "cp /tmp/rc.setup /etc/rc"); if(system(syscmd) != 0) { printf("`%s' failed!\n", syscmd); su_err(FATAL); } unlink("/tmp/rc.setup"); sync(); shostname(&lbuf, strlen(lbuf)); break; } /* * Select alternate version of more commands by * mounting the /usr file system and executing * makefiles in /usr/bin & /usr/lib & /usr/ucb. * Also, unpack help data base (if loaded from floppy kit). * ONLY select commands once, use lock file to make sure. */ while(1) { if(phase != SUP1) break; if(access(uclock, 0) == 0) break; /* command select already done */ if(chngdir("/usr/bin")) su_err(FATAL); printf("\n****** SELECTING%sSPLIT I/D COMMANDS ", (cputyp[tpi].p_sid == SID) ? " " : " NON-"); printf("(/usr/bin, lib, ucb) ******\n"); system("rm -f e ex vi view edit"); #ifdef DEBUG printf("%sex lex pcc yacc awk s5make", debug); #endif DEBUG if(cputyp[tpi].p_sid == SID) { system("cp ex70 ex"); system("cp lex70 lex"); system ("cp pcc70 pcc"); system("cp yacc70 yacc"); system("cp awk70 awk"); system("cp s5make70 s5make"); } else { system("cp ex40 ex"); system("cp lex40 lex"); system("cp pcc40 pcc"); system("cp yacc40 yacc"); system("cp awk40 awk"); system("cp s5make40 s5make"); } sync(); link("ex", "edit"); link("ex", "e"); link("ex", "vi"); link("ex", "view"); system("chog bin ex"); chmod("ex", 01755); sync(); if(chngdir("/usr/lib")) su_err(FATAL); #ifdef DEBUG printf("%sccom lint\n", debug); #endif DEBUG if(cputyp[tpi].p_sid == SID) { system("ln /usr/c/oc2_id /usr/c/oc2"); system("cp sendmail70 sendmail"); system("cp ccom70 ccom"); system("chog bin ccom"); chmod("ccom", 0755); system("cp lint170 lint1"); } else { system("ln /usr/c/oc2_ov /usr/c/oc2"); system("cp sendmail40 sendmail"); system("cp ccom140 ccom1"); system("cp ccom240 ccom2"); system("chog bin ccom1 ccom2"); chmod("ccom1", 0755); chmod("ccom2", 0755); system("cp lint140 lint1"); } sync(); if(rxflag) { if(chngdir("help")) su_err(FATAL); system("unpack U11_help >/dev/null 2>&1"); sync(); } if(chngdir("/usr/ucb")) su_err(FATAL); if(cputyp[tpi].p_sid == SID) system("cp Mail70 mail"); else system("cp Mail40 mail"); sync(); if(chngdir(homedir)) su_err(FATAL); creat(uclock, 0444); /* say command select done */ sync(); break; } /* * Remove alternate command files (/usr/bin & /usr/lib). * ONLY if lock file exists (selection done). * It is possible this could happen more than once, but * that is ok. */ while(1) { if(phase != SUP1) break; if(access(uclock, 0) != 0) break; /* select not done yet, CAN'T HAPPEN */ #ifdef DEBUG printf("%sremove /usr/bin & /usr/lib commands <y or n> ? ", debug); if(yes(NOHELP) != YES) break; #endif DEBUG if(chngdir("/usr/bin")) su_err(FATAL); system("rm -f ex40 lex40 pcc40 yacc40 awk40 s5make40"); system("rm -f ex70 lex70 pcc70 yacc70 awk70 s5make70"); sync(); if(chngdir("/usr/lib")) su_err(FATAL); system("rm -f ccom70 ccom140 ccom240 lint140 lint170"); system("rm -f sendmail40 sendmail70"); if(cputyp[tpi].p_sid == SID) { unlink("/usr/c/oc2_ov"); unlink("ccom1"); unlink("ccom2"); } else { unlink("/usr/c/oc2_id"); unlink("ccom"); } sync(); if(chngdir("/usr/ucb")) su_err(FATAL); system("rm -f Mail40 Mail70"); sync(); if(chngdir(homedir)) su_err(FATAL); break; } /* * Set up LPR printer ports, if any. */ while(1) { if(phase < SUP2) break; while(1) { printf("\nSet up line printer spooler and printer ports <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_lpr"); continue; } else break; } if(j == NO) break; system("/usr/etc/lprsetup"); break; } /* * Find out if user wants to set up user file * systems at this time, do setup if so. */ while(1) { if((phase < SUP2) && (ontarget == YES)) break; while(1) { if(phase <= SUP2) printf("\nSet up user file systems"); else printf("\nChange (or set up new) user file systems"); printf(" <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_cufs"); continue; } else break; } if(j == NO) break; /* * Following depends on drive type info obtained by * make special files code. This is ok because that * portion of the MSF code is always executed. */ if(pdconf(MKFS) == 0) { phelp("no_disks"); /* Sorry, no disks available! */ break; } prtc(); phelp("dsk_mntd"); /* tell user to make sure disks mounted */ prtc(); /* * Get drive type info again. * This ensures MSCP disk sizes correct and * on-line status is correct. */ for(dip=di_info; dip->di_typ; dip++) { if(dip->di_nunit == 0) continue; (*dip->di_func)(MKFS, dip, mem); } for(dip=di_info; dip->di_typ; dip++) { if(dip->di_nunit == 0) continue; /* controller not configured */ for(i=0; i<dip->di_nunit; i++) { if(dip->di_dt[i] == 0) continue; /* non-existent drive */ if(sd_info[dip->di_dt[i]].sd_flags&SD_FLOPPY) continue; /* we don't do floppy disks */ if(sd_info[dip->di_dt[i]].sd_flags&SD_ML11) continue; /* we don't do ML11 disks */ /* TODO: system disk cntlr number HP HM HJ, RA, RC, RQ ????? */ if((sd_info[dip->di_dt[i]].sd_flags&SD_SYSDSK) && (i == sdunit) && (dip->di_cn == sdcntlr) && ((sd_info[dip->di_dt[i]].sd_flags&SD_USRDSK) == 0)) continue; /* system disk, no free file systems */ if(usedisk(i, dip) == NO) continue; /* user says don't use this disk drive */ setdisk(i, dip); /* setup user file system(s) on disk */ } } break; } /* * Load and/or unload optional software. * Call setup.osl to do the actual loading/unloading. * Retry if setup.osl fails. * If not on the target CPU, assume it has no load device * and load optional software during phase 1. */ while(1) { if((phase < SUP2) && (ontarget == YES)) break; if((phase == SUP1) && (ontarget == NO)) phelp("ntp_warn"); while(1) { printf("\nLoad/unload optional software <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_osl"); continue; } else break; } sprintf(syscmd, "setup_osl %d %.2s %d %c %d", cputyp[tpi].p_type, loadev, rxflag ? rq_dt[rxunit] : 0, loadev[3], rd2); if((fo = fopen(osload, "w")) != NULL) { fprintf(fo, "/.setup/%s\n", syscmd); fclose(fo); chmod(osload, 0755); system("chog bin /bin/osload"); } else printf("\nCAUTION: can't create %s!\n", osload); if(j == NO) break; system(syscmd); /* * TODO: setup_osl sometimes returns an error status, * has to do with using <CTRL/C> during setup_osl. if(system(syscmd) != 0) { printf("\nOptional software load/unload failed!\n"); printf("\nTry again <y or n> ? "); if(yes(NOHELP) == YES) continue; else break; } * TODO: end */ sync(); break; } /* * Ask the user if the /usr/spool directory * should be coverted to a symbolic link. * * /usr/spool can already be a symbolic link. * Target file system must have enough free space. * Current and target /usr/spool can't be same directories. * TODO: what if user types <CTRL/C>? */ while(1) { if(phase < SUP2) break; while(1) { if(phase == SUP2) printf("\nMake "); else printf("\nMake (or change) "); printf("symbolic link for /usr/spool <y or n> ? "); j = yes(HELP); if(j == HELP) { phelp("h_ussl"); continue; } else break; } if(j == NO) break; while(1) { do { printf("\nSymbolic link base directory name "); printf("(? for help): "); } while(getline("h_slbdn") <= 0); if(lbuf[0] == '/') p = &lbuf[1]; else p = &lbuf[0]; if(strlen(p) > DIRSIZ) { printf("\nName too long (%d char max)!\n", DIRSIZ); continue; } sprintf(&sl_bdn, "/%s", p); sprintf(&sl_dst, "%s/spool", sl_bdn); break; } /* * Make sure destination base directory exists. */ if(lstat(&sl_bdn, &statb) < 0) { printf("\n%s does not exist!\n", &sl_bdn); continue; } if((statb.st_mode&S_IFMT) != S_IFDIR) { printf("\n%s is not a directory!\n", &sl_bdn); continue; } /* * Make sure /usr/spool exists and see if * it is a symbolic link. */ if(lstat(sl_usd, &statb) < 0) { printf("\n%s does not exist!\n", sl_usd); su_err(FATAL); } if((statb.st_mode&S_IFMT) != S_IFDIR) { if((statb.st_mode&S_IFMT) == S_IFLNK) { sl_islink = YES; i = readlink(sl_usd, &sl_rlb, BUFSIZ); if(i <= 0) { printf("\nreadlink on %s failed!\n", sl_usd); continue; } else sl_rlb[i] = '\0'; if(i > SL_MAXPL) { printf("\n%s symbolic link pathname too long!\n", sl_usd); continue; } else { sprintf(&sl_src, "%s", sl_rlb); /* save src directory base name for later use */ for(p = &sl_rlb[1]; (*p != '/'); p++); *p = '\0'; sprintf(&sl_sbdn, "%s", &sl_rlb); } } else { printf("\n%s is not a directory!\n", sl_usd); su_err(FATAL); } } else sprintf(&sl_src, "%s", sl_usd); /* src dir is /usr/spool */ if(strcmp(&sl_src, &sl_dst) == 0) { printf("\nCan't move spool from %s to %s!\n", &sl_src, &sl_dst); continue; } /* * Mount the dst file system. * Mount the src file system, only if * /usr/spool was already a symbolic link. * Dismount first, incase already mounted. */ sl_mnt(UMOUNT, NOERR, &sl_bdn); if(sl_mnt(MOUNT, ERR, &sl_bdn)) continue; if(sl_islink) { sl_mnt(UMOUNT, NOERR, &sl_sbdn); if(sl_mnt(MOUNT, ERR, &sl_sbdn)) continue; } printf("\nSize of %s in Kbytes:\n\n", &sl_src); sprintf(&syscmd, "du -s %s", &sl_src); system(&syscmd); printf("\nFile system free space (see %s):\n\n", &sl_bdn); system("df"); printf("\nIs there room for %s in %s <y or n> ? ", sl_usd, &sl_bdn); if(yes(NOHELP) != YES) continue; /* * Make sure the dst directory exists. */ if(lstat(&sl_dst, &statb) < 0) { /* dir does not exist */ if(mkdir(&sl_dst, 0775) < 0) { /* create it */ printf("\nCan't make %s directory!\n", &sl_dst); continue; } } else { /* dir exists, check it */ if((statb.st_mode&S_IFMT) != S_IFDIR) { printf("\n%s exists, but is not a directory!\n", &sl_dst); continue; } } /* * Set protection modes and ownership just to be sure. * Values are bogus, but used because of history. */ sprintf(&syscmd, "chmod 775 %s", &sl_dst); system(&syscmd); sprintf(&syscmd, "chown root %s", &sl_dst); system(&syscmd); sprintf(&syscmd, "chgrp other %s", &sl_dst); system(&syscmd); printf("\nMoving files from %s to %s...\n", &sl_src, &sl_dst); sprintf(&syscmd, "cd %s; tar cf - . | (cd %s; tar xpf -)", &sl_src, &sl_dst); if(system(&syscmd) != 0) { printf("\nTAR command failed: cannot move files!\n"); continue; } /* * Remove the old /usr/spool files (src directory). * If /usr/spool was already a symbolic link, * unlink /usr/spool and rm -r src directory. * Otherwise, just rm -r /usr/spool. */ if(sl_islink) { /* If /usr/spool already a symlink */ unlink(sl_usd); /* unlink it & blow away src dir */ sprintf(&syscmd, "rm -rf %s", sl_src); system(&syscmd); } else /* else, blow away /usr/spool */ system("rm -rf /usr/spool"); /* * Make a symbolic link from dst dir to /usr/spool. */ printf("\nMaking Symbolic link: %s -> %s\n", sl_usd, &sl_dst); if(symlink(&sl_dst, sl_usd) < 0) { printf("\nCan't create symbolic link: %s -> %s\n", sl_usd, &sl_dst); continue; } /* * Dismount dst file system. * Dismount src file system, only if * /usr/spool was already a symbolic link. */ sl_mnt(UMOUNT, NOERR, &sl_bdn); if(sl_islink) sl_mnt(UMOUNT, NOERR, &sl_sbdn); break; } supdone(mem); } /* * Mount/umount file system for symbolic links. * * opr = mount or umount * err = allow or ignore errors * dir = directory name to mount * * Mount/umount by directory name requires an entry for * the file system in the /etc/fstab. */ sl_mnt(opr, err, dir) int opr; int err; char *dir; { register int i; char cmd[100]; sprintf(&cmd, "/etc/%s %s%s", (opr==MOUNT) ? "mount" : "umount", dir, (err==ERR) ? " " : " >/dev/null 2>&1"); i = system(&cmd); if((err == ERR) && (i != 0)) { printf("\n%s of %s failed!\n", (opr==MOUNT) ? "Mount" : "Dismount", dir); printf("%s must exist and be in the /etc/fstab!\n", dir); } return(i); } /* pmsg(str) char **str; { register int i; for(i=0; str[i]; i++) printf("\n%s", str[i]); fflush(stdout); } */ /* * 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 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() { signal(SIGINT, intr); ab_flag = 1; longjmp(savej, 1); } retry(str) char *str; { printf("\n%s FAILED: try again <y or n> ? ", str); if(yes(NOHELP) == YES) return(1); else return(0); } iflop(fn) char *fn; { printf("\n\7\7\7Insert (%s) diskette into RX%d unit %d", fn, rq_dt[rxunit], rxunit); if(rq_dt[rxunit] == RX50) printf(" %s", rxpos(rxunit)); printf("\n"); prtc(); } rflop(fn) char *fn; { printf("\n\7\7\7Remove (%s) diskette from RX%d unit %d", fn, rq_dt[rxunit], rxunit); if(rq_dt[rxunit] == RX50) 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 == YES) ? rxp_tl : rxp_lr); case 3: return(rxp_lr); default: return("(?)"); } } /* * Get a line of text from the terminal, * replace the newline with a NULL. * Return the string length (not counting the NULL). * Return 0 if the user typed only <RETURN>. * 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); /* user typed only <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] == '?') || (strcmp("help", lbuf) == 0)) { if(hlp) phelp(hlp); else printf("\nSorry no additional help available!\n"); return(-1); } return(cc); } } prtc() { printf("\nPress <RETURN> to continue: "); fflush(stdout); while(getchar() != '\n') ; } /* * Create /etc/ttys and /etc/ttytype. * First line depends on console CRT or hardcopy. * Remaining lines depend on _ntty from kernel. * * ttys ttytype * CRT 22console vt100 console * Hardcopy 24console dw3 console */ #define TTMAX 80 /* MAX terminal type name length */ char ttylast[TTMAX+1]; /* Last tty type name used (for default) */ char *tt_vt100 = "vt100"; char *tt_dw3 = "dw3"; bttys(crt, ntty, npty) { register int i; FILE *fi, *fo; char p, n; int ask; char *tp; if((fo = fopen("/tmp/ttys.setup", "w")) == NULL) { printf("\nCan't create /tmp/ttys.setup file!\n"); return(-1); } if(crt == YES) fprintf(fo, "22console\n"); else fprintf(fo, "24console\n"); if(ntty) for(i=0; i<ntty; i++) fprintf(fo, "00tty%02d\n", i); if(npty > 0) { for(i=0; i<npty; i++) { p = 'p' + (i / 16); if((i % 16) < 10) n = '0' + (i % 16); else n = 'a' + ((i % 16) - 10); fprintf(fo, "00tty%c%c\n", p, n); } } fclose(fo); sprintf(syscmd, "cp /tmp/ttys.setup /etc/ttys"); if(system(syscmd) != 0) { printf("\n`%s' failed!\n", syscmd); return(-1); } unlink("/tmp/ttys.setup"); sync(); if(phase == SUP3) { printf("\nWas number of pseudo TTYs the only change <y or n> ? "); if(yes(NOHELP) == YES) { printf("\nNo need to remake /etc/ttytype file!\n"); return; } } ttylast[0] = '\0'; /* init default tty type to no default */ if((fo = fopen("/tmp/ttytype.setup", "w")) == NULL) { printf("\nCan't create /tmp/ttytype.setup file!\n"); return(-1); } tp = asktt(CONSOLE, 0, crt); /* ask for console terminal type */ fprintf(fo, "%s\tconsole\n", tp); if(ntty) { while(1) { printf("\nAssume (for now) all remaining terminals "); printf("are vt100 <y or n> ? "); ask = yes(HELP); if(ask == HELP) { phelp("h_gta"); continue; } break; } for(i=0; i<ntty; i++) { if(ask == YES) tp = tt_vt100; else tp = asktt(OTHER, i, NO); fprintf(fo, "%s\ttty%02d\n", tp, i); } } fclose(fo); sprintf(syscmd, "cp /tmp/ttytype.setup /etc/ttytype"); if(system(syscmd) != 0) { printf("\n`%s' failed!\n", syscmd); return(-1); } unlink("/tmp/ttytype.setup"); sync(); } /* * Ask user for terminal type (for ttytype file entry). * * tt = terminal type (console/other). * tn = tty## (0 for console). * crt = console is CRT or PRT. * * NOTE: some variables used by this routine are * defined just in front of bttys(), above. */ asktt(tt, tn, crt) int tt; int tn; int crt; { register int cc; char *p; while(1) { do { printf("\nTerminal type for "); if(tt == CONSOLE) printf("CONSOLE terminal "); else printf("TTY%02d ", tn); if(ttylast[0]) p = &ttylast; else if(tt == CONSOLE) p = (crt==YES) ? tt_vt100 : tt_dw3; else p = tt_vt100; printf("< %s > ? ", p); } while((cc = getline("h_gtt")) < 0); if(cc == 0) /* user typed <RETURN>, use default */ return(p); if(cc == 1) continue; /* in case user type y or n */ if((strcmp("yes", &lbuf) == 0) || (strcmp("no", &lbuf) == 0)) continue; /* in case user types yes or no */ if(cc > TTMAX) { printf("\nName too long (%d char max)!\n", TTMAX); continue; } sprintf(&ttylast, "%s", &lbuf); return(&ttylast); } } /* * Zap the newline at the end of a string * read by fgets(), i.e., replace nl with 0. */ zapnl(s) char *s; { register int i; for(i=0; s[i]; i++) if(s[i] == '\n') { s[i] = '\0'; break; } } /* * Write the current phase number to * the setup.info file. * No error checking, because file may not * even exist. */ char pnbuf; wrtpn(pn) { register int fd; if((fd = open(info, 1)) < 0) return; pnbuf = pn + '0'; write(fd, (char *)&pnbuf, 1); close(fd); sync(); } /* * Routines to fish the disk drive type * info out of the running kernel (/dev/mem). * BAD DEPENDENCY: routines need to know how each * disk driver defines NED and drive types. * * usage - identifies section of code calling ??_gdti(), * ONLY USED BY ra_gdti(). * MSF, called by make special files code. * MKFS, called by setup user file systems code. * dip - pointer to entry in di_info[]. * mem - open file descriptor for /dev/mem. * * Note: * The data structures used by these routines * are located before main(), so code in main can * access them. */ /* * RK05 * NED = -1 * RK05 = 1 */ rk_gdti(usage, dip, mem) register struct di_info *dip; { register int i, j; lseek(mem, (long)nl[X_NRK].n_value, 0); read(mem, (char *)&nrk, sizeof(nrk)); lseek(mem, (long)nl[X_RK_DT].n_value, 0); read(mem, (char *)&rk_dt, sizeof(rk_dt)); dip->di_nunit = nrk; for(i=0; i<nrk; i++) { if(rk_dt[i] != 1) dip->di_dt[i] = 0; /* NED (configured but not found) */ else { for(j=0; sd_info[j].sd_lname; j++) if(sd_info[j].sd_type == RK05) break; dip->di_dt[i] = j; /* save index into drive info table */ } } } /* * RP02/3 * NED = -1 * RP02 = 0 * RP03 = 1 * Note: must read each configured RP02/3 unit to * force update of rp_dt[]. */ rp_gdti(usage, dip, mem) register struct di_info *dip; { register int i, j; for(i=0; i<nrp; i++) { mknod(dsk_sfn, 020400, (dip->di_rmaj<<8) | (i<<3)); if((j = open(dsk_sfn, 0)) >= 0) { read(j, (char *)&syscmd, 512); close(j); } unlink(dsk_sfn); } lseek(mem, (long)nl[X_NRP].n_value, 0); read(mem, (char *)&nrp, sizeof(nrp)); lseek(mem, (long)nl[X_RP_DT].n_value, 0); read(mem, (char *)&rp_dt, sizeof(rp_dt)); lseek(mem, (long)nl[X_RP_SIZES].n_value, 0); read(mem, (char *)&rp_sizes, sizeof(rp_sizes)); dip->di_nunit = nrp; for(i=0; i<nrp; i++) { if(rp_dt[i] < 0) dip->di_dt[i] = 0; /* NED (configured but not found) */ else { for(j=0; sd_info[j].sd_lname; j++) /* setup uses (RP02=2, RP03=3, so we add 2) */ if(sd_info[j].sd_type == (rp_dt[i] + 2)) break; dip->di_dt[i] = j; /* save index into drive info table */ } } } /* * MSCP (UDA50 RC25 RQDX RUX50) * NED = 0 * See /usr/include/sys/ra_info.h for drive types. * * Note: (usage argument) * * If usage == MSF (called from make special files code), * just get drive type info. If usage == MKFS (called from * setup user file systems code), get drive type info and * force all possilbe drives on-line by attempting open. * This ensures the size info is correct. * * Note: MSCP drive type info arrays are non-semetrical * ra_index must be used to access drive type info. */ int raload = NO; /* RA info already loaded */ ra_gdti(usage, dip, mem) register struct di_info *dip; { register int i, j; int cn, ind; int raunits; /* * Read in the controller and drive type info. */ /* * OLDCODE: for MKFS must get drive type info * each time. if(raload == NO) { */ raload = YES; lseek(mem, (long)nl[X_NUDA].n_value, 0); read(mem, (char *)&nuda, sizeof(nuda)); lseek(mem, (long)nl[X_NRA].n_value, 0); read(mem, (char *)&nra, MAXUDA); lseek(mem, (long)nl[X_UD_SIZES].n_value, 0); read(mem, (char *)&ud_sizes, sizeof(ud_sizes)); lseek(mem, (long)nl[X_RQ_SIZES].n_value, 0); read(mem, (char *)&rq_sizes, sizeof(rq_sizes)); lseek(mem, (long)nl[X_RC_SIZES].n_value, 0); read(mem, (char *)&rc_sizes, sizeof(rc_sizes)); lseek(mem, (long)nl[X_RA_MAS].n_value, 0); read(mem, (char *)&ra_mas, sizeof(daddr_t)*nuda); raunits = 0; for(i=0; i<MAXUDA; i++) raunits += nra[i]; lseek(mem, (long)nl[X_RA_INDEX].n_value, 0); read(mem, (char *)&ra_index, MAXUDA); lseek(mem, (long)nl[X_RA_CTID].n_value, 0); read(mem, (char *)&ra_ctid, MAXUDA); /* * If called from make user file systems code, * make sure size and on-line information in ra_drv[] * is updated by attempting to open each configured drive. */ if(usage == MKFS) { for(i=0; i<nuda; i++) for(j=0; j<nra[i]; j++) { ind = (dip->di_rmaj << 8) | (i << 6) | (j << 3) | 7; /* TODO: some user may have /dev/setup.dsf! */ /* check for it??? */ mknod(dsk_sfn, 020400, ind); if((ind = open(dsk_sfn, 0)) >= 0) close(ind); unlink(dsk_sfn); } } lseek(mem, (long)nl[X_RA_DRV].n_value, 0); read(mem, (char *)&ra_drv, sizeof(struct ra_drv) * raunits); /* } */ cn = dip->di_cn; ind = ra_index[cn]; dip->di_nunit = nra[cn]; for(i=0; i<nra[cn]; i++) { if(ra_drv[ind+i].ra_dt == 0) { dip->di_dt[i] = 0; /* NED (configured but not found) */ } else { for(j=0; sd_info[j].sd_lname; j++) if(sd_info[j].sd_type == ra_drv[ind+i].ra_dt) break; dip->di_dt[i] = j; /* save index into drive info table */ } } /* * Change the controller name from MSCP to * the real name (UDA50, RQDX, etc.). */ dip->di_typ = ra_gcti(ra_ctid[cn]); /* * Change the two character ULTRIX-11 mnemonic to * ra, rc, rd, rx according to the controller type. * Also, save RD/RX drive types in rq_dt[] if controller * is RQDX1/2/3 (for iflop()). */ switch((ra_ctid[cn] >> 4) & 017) { case UDA50: case UDA50A: case KDA50: dip->di_name[1] = 'a'; /* RA60/RA80/RA81 */ break; case KLESI: dip->di_name[1] = 'c'; /* RC25 */ break; case RQDX1: case RQDX3: dip->di_name[1] = 'd'; /* RD31/RD32/RD51/RD52/RD53/RD54 */ for(i=0; i<nra[cn]; i++) rq_dt[i] = ra_drv[ind+i].ra_dt; if(rxflag) { if((rq_dt[1] != RX50) && (rq_dt[1] != RX33)) rd2 = YES; } break; case RUX1: dip->di_name[1] = 'x'; /* RUX50 */ break; default: dip->di_name[1] = 'a'; /* UNKNOWN (can't happen) */ break; } } /* * Return a pointer to the controller name string * according to the controller type ID. */ /* TODO: some names will change */ ra_gcti(ctid) { switch((ctid >> 4) & 017) { case UDA50: return("UDA50"); case KDA50: return("KDA50"); case KLESI: return("KLESI"); case UDA50A: return("UDA50A"); case RQDX1: return("RQDX1"); case RQDX3: return("RQDX3"); case RUX1: return("RUX1"); default: return("UNKNOWN"); } } /* * RX02 * RX02 driver does not have drive type info. * Always 2 RX02 if HX configured. */ hx_gdti(usage, dip, mem) register struct di_info *dip; { register int i; dip->di_nunit = 2; for(i=0; sd_info[i].sd_lname; i++) if(sd_info[i].sd_type == RX02) break; dip->di_dt[0] = i; /* unit 0 = RX02 */ dip->di_dt[1] = i; /* unit 1 = RX02 */ } /* * RL01/2 * NED = -1 * RL01 = 10240 * RL02 = 20480 */ rl_gdti(usage, dip, mem) register struct di_info *dip; { register int i, j; lseek(mem, (long)nl[X_NRL].n_value, 0); read(mem, (char *)&nrl, sizeof(nrl)); lseek(mem, (long)nl[X_RL_DT].n_value, 0); read(mem, (char *)&rl_dt, sizeof(rl_dt)); dip->di_nunit = nrl; for(i=0; i<nrl; i++) { if(rl_dt[i] < 0) dip->di_dt[i] = 0; /* NED (configured but not found) */ else { for(j=0; sd_info[j].sd_lname; j++) if(sd_info[j].sd_type == rl_dt[i]) break; dip->di_dt[i] = j; /* save index into drive info table */ } } } /* * MASSBUS (HP HM HJ) * NED = 0 * See /usr/include/sys/hp_info.h for drive types. * * Note: MASSBUS drive type info arrays are non-semetrical * hp_index must be used to access drive type info. */ int hpload = NO; /* HP info already loaded */ hp_gdti(usage, dip, mem) register struct di_info *dip; { register int i, j; int cn, ind; int hpunits; /* * Read in the controller and drive type info. */ if(hpload == NO) { hpload = YES; lseek(mem, (long)nl[X_NHP].n_value, 0); read(mem, (char *)&nhp, MAXRH); lseek(mem, (long)nl[X_HP_SIZES].n_value, 0); read(mem, (char *)&hp_sizes, sizeof(hp_sizes)); hpunits = 0; for(i=0; i<MAXRH; i++) hpunits += nhp[i]; lseek(mem, (long)nl[X_HP_INDEX].n_value, 0); read(mem, (char *)&hp_index, MAXRH); } lseek(mem, (long)nl[X_HP_DT].n_value, 0); read(mem, (char *)&hp_dt, hpunits); cn = dip->di_cn; ind = hp_index[cn]; dip->di_nunit = nhp[cn]; for(i=0; i<nhp[cn]; i++) { if(hp_dt[ind+i] == 0) dip->di_dt[i] = 0; /* NED (configured but not found) */ else { for(j=0; sd_info[j].sd_lname; j++) if(sd_info[j].sd_type == hp_dt[ind+i]) break; dip->di_dt[i] = j; /* save index into drive info table */ } } /* * Change the controller name from MASBUS to * the real name (RH11 or RH70). */ if(cputype == 70) dip->di_typ = "RH70"; else dip->di_typ = "RH11"; } /* * RK06/7 * NED = -1 * RK06 = 0 * RK07 = 02000 */ hk_gdti(usage, dip, mem) register struct di_info *dip; { register int i, j; lseek(mem, (long)nl[X_NHK].n_value, 0); read(mem, (char *)&nhk, sizeof(nhk)); lseek(mem, (long)nl[X_HK_DT].n_value, 0); read(mem, (char *)&hk_dt, sizeof(hk_dt)); lseek(mem, (long)nl[X_HK_SIZES].n_value, 0); read(mem, (char *)&hk_sizes, sizeof(hk_sizes)); dip->di_nunit = nhk; for(i=0; i<nhk; i++) { if(hk_dt[i] < 0) dip->di_dt[i] = 0; /* NED (configured but not found) */ else { for(j=0; sd_info[j].sd_lname; j++) if(sd_info[j].sd_type == hk_dt[i]) break; dip->di_dt[i] = j; /* save index into drive info table */ } } } /* * Mount or unmount the /usr file system. * * mnt = 0 for unmount, mnt = 1 for mount * * Don't mount if /usr already mounted, and * don't unmount if not mounted. Also, * don't unmount if setup didn't mount /usr. */ int usrmntd = NO; int su_didit = NO; char *mntcmd = "/etc/mount /usr"; char *umntcmd = "/etc/umount /usr"; /* TODO: routine not used */ usrmnt(mnt) { switch(mnt) { case MOUNT: if(usrmntd == YES) break; if(access("/usr/bin", 0) == 0) { usrmntd = YES; su_didit = NO; break; } while(system(mntcmd) != 0) { if(retry("Mount of /usr file system")) continue; else return(1); } usrmntd = YES; su_didit = YES; break; case UMOUNT: if(usrmntd == NO) break; if(su_didit == NO) break; while(system(umntcmd) != 0) { if(retry("Dismount of /usr file system")) continue; else return(1); } usrmntd = NO; break; default: return(1); } return(0); } /* * Change directory, * print error message if chdir() fails. */ chngdir(dir) char *dir; { if(chdir(dir) < 0) { printf("\nCannot change directory to %s!\n", dir); return(1); } else return(0); } /* * Fatal error routine. * Depending on the error type (et), * print error messages, sync, and exit. */ su_err(et) { signal(SIGINT, SIG_IGN); chdir("/"); system("/etc/umount -a >/dev/null 2>&1"); sync(); if(et) { if(et == FATAL) printf("\n****** FATAL ERROR DURING SETUP PHASE %d ******", phase); phelp("abort"); } exit(1); } /* * Normal exit routine, * called at the end of each phase. * TODO: need messages about goto IG do sysgen. * may exec a copy of sysgen????? */ char *cd_warn = "\nWARNING: alternate commands (*40 & *70) not removed from "; supdone(mem) { int clean; signal(SIGINT, SIG_IGN); if(mem > 0) close(mem); /* I know, but I don't like loose ends! */ chdir(homedir); if(ontarget == YES) printf("\n\7\7\7****** ULTRIX-11 Setup Phase %d Completed ******\n", phase); #ifdef DEBUG if(ontarget == YES) { printf("%sdo end of phase %d cleanup <y or n> ? ", debug, phase); if(yes(NOHELP) == YES) clean = YES; else clean = NO; } #else DEBUG clean = YES; #endif DEBUG if((clean == NO) || (phase == SUP3)) wrtpn(phase); else if((phase == SUP1) && (ontarget == NO)) wrtpn(SUP1); else wrtpn(phase+1); if((phase == SUP1) && (ontarget == YES)) { unlink(rclock); unlink(uclock); } if((phase == SUP2) && (clean == YES)) { sprintf(syscmd, "mv /profile /.profile"); if(system(syscmd) != 0) printf("\nWARNING: `%s' failed!\n", syscmd); chmod("/.profile", 0644); unlink("/profile"); sync(); } chdir("/"); /* * OLDCODE if(usrmnt(UMOUNT)) printf("\nWARNING: dismount of /usr failed!\n"); */ system("/etc/umount -a >/dev/null 2>&1"); sync(); if(phase == SUP1) { if(ontarget == YES) phelp("eop1_otp"); else phelp("eop1_ntp"); } else if(phase == SUP2) phelp("eop2"); else phelp("eop3"); exit(0); } /* * Print disk configuration. * Printout altered slightly by usage argument: * * usage = MSF (make special files) * usage = MKFS (make user file systems) * * If usage == MKFS, return number of available disks. */ pdconf(usage) { register struct di_info *dip; register int j, d; printf("\nULTRIX-11 System's Disk Configuration:\n"); if(usage == MKFS) { printf("\n* = SYSTEM DISK -- no partitions available for user "); printf("file systems."); } printf("\nX = disk not configured, "); printf("NED = disk configured but not present.\n"); printf("\nDisk Cntlr System Unit Unit Unit Unit "); printf("Unit Unit Unit Unit"); printf("\nCntlr # Disk 0 1 2 3 "); printf("4 5 6 7"); printf("\n----- ----- ------ ---- ---- ---- ---- "); printf("---- ---- ---- ----"); d = 0; for(dip=di_info; dip->di_typ; dip++) { if(dip->di_nunit == 0) continue; printf("\n%-6s %-5d ", dip->di_typ, dip->di_cn); if((sd_info[dip->di_dt[sdunit]].sd_flags&SD_SYSDSK) == 0) printf(" "); else printf("UNIT %c ", sd_info[dip->di_dt[0]].sd_swap[2]); for(j=0; j<8; j++) { if(j >= dip->di_nunit) printf("X "); else if(dip->di_dt[j] == 0) printf("NED "); else { printf("%-4s", sd_info[dip->di_dt[j]].sd_uname); d++; } if((j == sdunit) && (usage == MKFS) && (sd_info[dip->di_dt[j]].sd_flags&SD_SYSDSK) && ((sd_info[dip->di_dt[j]].sd_flags&SD_USRDSK) == 0)) { printf("* "); d--; } else printf(" "); } } printf("\n"); return(d); } /* * Ask the user if this disk drive is to be * used for user file storage. Return YES or NO. * * dip drive info structure pointer * unit unit number */ usedisk(unit, dip) register struct di_info *dip; int unit; { register int j; while(1) { pdoc(unit, dip); /* print disk unit on cntlr message */ printf("file systems available.\n"); while(1) { printf("\nSet up user file system(s) on this disk "); printf("(? for help) <y or n> ? "); j = yes(HELP); if(j == HELP) phelp("h_udisk"); else break; } return(j); } } /* * Set up user file system(s) on the specified disk drive. * Make the fstab entry and, possilby, make an empty * file system. */ setdisk(unit, dip) register struct di_info *dip; int unit; { register int i, j; int fs, fd; struct filsys *fp; int isfs, isv3fs; int didmkfs, opt; int fseflag; struct stat statb; spt(unit, dip); /* Setup partition table for this disk */ while(1) { do { if(ppt(unit, dip)) { printf("\nNo more partitions available on this disk!\n"); return; } if(phase == SUP3) phelp("ufs_warn"); printf("\nSelect a disk partition (? for help, "); printf("`.' if done with this disk).\n"); printf("\nDisk partition < "); for(i=0; i<8; i++) if(pt_info[i].pt_flags == 0) printf("%d ", i); printf("> ? "); } while(getline("h_sdp") <= 0); if(strlen(lbuf) != 1) { printf("\nInvalid response!\n"); continue; } if(lbuf[0] == '.') { printf("%sfinished with this disk <y or n> ? ", confirm); if(yes(NOHELP) == YES) return; else continue; } if((lbuf[0] < '0') || (lbuf[0] > '7')) { printf("\n%s - bad partition number!\n", lbuf); continue; } fs = lbuf[0] - '0'; if(pt_info[fs].pt_flags&PT_NUP) { printf("\nSorry, %s disk does not use partition %d!\n", sd_info[dip->di_dt[unit]].sd_uname, fs); continue; } if(pt_info[fs].pt_flags&PT_SYS) { printf("\nSorry, partition %d used by the system!\n", fs); continue; } if(pt_info[fs].pt_flags&PT_USER) { printf("\nSorry, partition %d is already used!\n", fs); continue; } if(pt_info[fs].pt_flags&PT_OP) { printf("\nSorry, partition %d ", fs); printf("overlaps an existing file system!\n"); continue; } printf("%sset up user file system on partition %d <y or n> ? ", confirm, fs); if(yes(NOHELP) != YES) continue; /* * Set up superblock volname and fsname, * mounted on directory name, and * block/raw disk names. */ sprintf(bdisk, "%s", dsfn(BLOCK, unit, fs, dip)); sprintf(rdisk, "%s", dsfn(RAW, unit, fs, dip)); if((sd_info[dip->di_dt[unit]].sd_flags&SD_SYSDSK) && (unit == sdunit) && (dip->di_cn == sdcntlr)) sprintf(volname, "sd_%.3s", &bdisk[5]); else sprintf(volname, "ud_%.3s", &bdisk[5]); for(ufsnum=1; ufsnum<100; ufsnum++) { sprintf(fsname, "user%d", ufsnum); sprintf(mntdir, "/user%d", ufsnum); if(access(&mntdir, 0) == 0) continue; /* directory exists, this name already used */ else break; /* TODO: may want to warn if bdisk or mntdir already in fstab */ } /* TODO: may ask user for 6 char name ????? */ if(ufsnum >= 100) { /* PANIC: all 99 names used! */ printf("\nSorry, all 99 possible file system names used!\n"); su_err(FATAL); } /* * Warn the user if a file system exists on the selected partition. * If it's not a V3.0 1K file system, say can access via rawfs(8). * Check s_fsize & s_isize to see if file system exists, * check superblock magic numbers to see if its a V3.0 file system. */ opt = 0; /* opt tells how to deal with existing file systems */ fseflag = NO; if((fd = open(rdisk, 0)) < 0) { printf("\n%s: open failed!\n", rdisk); su_err(FATAL); } j = sizeof(struct filsys); lseek(fd, (long)(SUPERB*BSIZE), 0); if(read(fd, (char *)&syscmd, j) != j) { printf("\n%s: superblock read failed!\n", rdisk); su_err(FATAL); } close(fd); fp = (struct filsys *)&syscmd; isfs = YES; isv3fs = NO; if((fp->s_isize <= (SUPERB+1)) || (fp->s_fsize <= 0L) || (fp->s_fsize > 16777216L) || (fp->s_isize >= fp->s_fsize)) isfs = NO; if(isfs == YES) { /* see if it's a V3.0 file system */ if((fp->s_magic[0] != S_0MAGIC) || (fp->s_magic[1] != S_1MAGIC) || (fp->s_magic[2] != S_2MAGIC) || (fp->s_magic[3] != S_3MAGIC)) isv3fs = NO; else isv3fs = YES; } printf("\nSuperblock check indicates: "); if(isfs == NO) printf("no "); else printf("\n\n\t"); if(isfs == YES) { if(isv3fs == YES) printf("An "); else printf("A non "); printf("ULTRIX-11 V3.0 "); } printf("file system exists on partition %d!", fs); if(isfs == YES) { printf("\n\tSuperblock fsname = %.6s", fp->s_fname); printf("\n\tSuperblock volname = %.6s", fp->s_fpack); } printf("\n"); if((isfs == YES) && (isv3fs == NO)) { phelp("ufs_fe1"); printf("\nOk to overwrite existing file system <y or n> ? "); if(yes(NOHELP) != YES) opt = 3; /* preserve filsys, don't use, mark part. used */ } if((isfs == YES) && (isv3fs == YES)) { phelp("ufs_fe1"); while(1) { do { phelp("ufs_fe2"); printf("\nOption < 1 2 3 > ? "); } while(getline(NOHELP) <= 0); if((strlen(lbuf) != 1) || (lbuf[0] < '1') || (lbuf[0] > '3')) { printf("\nInvalid option!\n"); continue; } opt = lbuf[0] - '0'; break; } } while(1) { didmkfs = NO; if((isfs == YES) && (isv3fs == NO)) { if(opt == 3) j = NO; /* preserve filsys, don't use it */ else j = YES; break; } if((isfs == YES) && (isv3fs == YES)) { if(opt == 1) j = YES; /* overwrite file system, use it */ else j = NO; /* (opt==2), preserve filsys, use it */ /* (opt==3), preserve filsys, don't use */ break; } printf("\nMake an empty file system on partition "); printf("%d (? for help) <y or n> ? ", fs); j = yes(HELP); if(j == HELP) phelp("h_mkfs"); else break; } if(j == NO) { if(opt != 3) { printf("%salready a file system on partition %d <y or n> ? ", confirm, fs); if(yes(NOHELP) != YES) continue; } } else { /* answer must have been YES */ printf("%smake a file system on partition %d <y or n> ? ", confirm, fs); if(yes(NOHELP) != YES) continue; if(mfsdisk(unit, fs, dip)) continue; /* mkfs failed */ didmkfs = YES; } /* * Mark partition, and any overlapping ones, used. */ pt_info[fs].pt_flags |= PT_USER; for(j=0; j<8; j++) { if(j == fs) continue; if(pt_info[fs].pt_op&(1 << j)) pt_info[j].pt_flags |= PT_OP; } if(opt == 3) { if(fstab(FST_RMV, bdisk, mntdir)) printf("\nPartition %d (%s): /etc/fstab entry removed!\n", fs, bdisk); continue; /* preserve filsys, but don't use it */ /* mark partition used (done above) */ } /* * If the device (bdisk) and the fsname match an entry in the * fstab and the fsname matches an existing mount directory, * then, we assume this is an existing user file system. * Otherwise, we treate it as a new file system. */ if((isfs == YES) && (isv3fs == YES) && (opt == 2)) { sprintf(fmntdir, "/%.6s", fp->s_fname); if(fstab(FST_SCH, &bdisk, &fmntdir) && (access(&fmntdir, 0) == 0)) { sprintf(fsname, "%.6s", fp->s_fname); sprintf(mntdir, "%s", fmntdir); fseflag = YES; } } /* * Print fsname, volname, mounted on directory. * User may need this info later. * First time only, tell user values can be changed. */ printf("\nSuperblock file system name (fsname):\t%s", fsname); printf("\nSuperblock volume label (volname):\t%s", volname); printf("\nUser file system will be mounted on:\t%s\n", mntdir); if(firstfs == YES) { firstfs = NO; printf("\nNote: you can change these values, refer to System "); printf("\n Management Guide chapter 4 for instructions.\n"); } if((isfs == YES) && (didmkfs == NO)) { printf("\nRe-labeling file system superblock...\n"); sprintf(syscmd, "/etc/labelit %s %s %s -n", rdisk, fsname, volname); while(system(syscmd) != 0) { if(retry(syscmd)) continue; else su_err(FATAL); } } /* * Make the mounted on directory. * We know it does not already exist, check above. * Don't make mount directory if this is an existing file system * being reused, mount directory already exists. */ if(fseflag == NO) { sprintf(syscmd, "mkdir %s", mntdir); if(system(syscmd) != 0) printf("\nWARNING: %s failed!\n", syscmd); chmod(&mntdir, 0755); } /* * Mount the file system and chmod 0755. * Make the lost+found directory. */ sprintf(syscmd, "/etc/mount %s %s", bdisk, mntdir); if(system(syscmd) != 0) printf("\nWARNING: (%s) file system mount failed!\n", syscmd); else { while(1) { if(chngdir(mntdir)) break; if(lstat(lpfdir, &statb) >= 0) { if((statb.st_mode&S_IFMT) != S_IFDIR) { printf("\n%s: lost+found exists, but ", mntdir); printf("is not a directory (see fsck(8))!\n"); } break; } mkdir(lpfdir, 0700); if(chngdir(lpfdir)) break; for(i=0; i<25; i++) { sprintf(&syscmd, "junk%d", i); j = creat(&syscmd, 0666); if(j < 0) continue; write(j, (char *)&syscmd, SCSIZE); close(j); } sync(); sync(); system("rm -f junk*"); break; } chngdir(homedir); } chmod(&mntdir, 0755); sprintf(syscmd, "/etc/umount %s", bdisk); if(system(syscmd) != 0) printf("\nWARNING: (%s) file system dismount failed!\n",syscmd); if(fseflag == NO) fstab(FST_ENT, &bdisk, &mntdir); /* add entry to /etc/fstab */ printf("\n%sile system table (/etc/fstab):\n\n", (fseflag == NO) ? "New f" : "F"); system("cat /etc/fstab"); prtc(); } } /* * Set up the disk partition table. * * unit disk unit number * dip drive info table pointer */ spt(unit, dip) register struct di_info *dip; int unit; { register struct dksize *dsp; register struct rasize *rsp; int i, j, nbpc; long i_sb, i_eb, j_sb, j_eb; for(i=0; i<8; i++) { pt_info[i].pt_op = 0; pt_info[i].pt_nb = 0L; pt_info[i].pt_sb = 0L; pt_info[i].pt_flags = 0; if(((dip->di_flags&DI_NPD) == 0) && ((sd_info[dip->di_dt[unit]].sd_pmask&(1 << i)) == 0)) pt_info[i].pt_flags |= PT_NUP; /* nonusable partition */ } switch(dip->di_bmaj) { case RK_BMAJ: pt_info[0].pt_sb = 0L; pt_info[0].pt_nb = (long)rk_size; for(i=1; i<8; i++) pt_info[i].pt_flags |= PT_NUP; return(0); case RP_BMAJ: nbpc = RP23_BPC; dsp = &rp_sizes; break; case RA_BMAJ: switch((ra_ctid[dip->di_cn] >> 4) & 017) { case UDA50: case UDA50A: case KDA50: rsp = &ud_sizes; break; case KLESI: rsp = &rc_sizes; break; case RQDX1: case RQDX3: rsp = &rq_sizes; break; case RUX1: /* THIS CANNOT HAPPEN */ printf("\n(spt) - can't use RUX1!\n"); return(1); default: /* THIS CAN'T HAPPEN */ printf("\n(spt) - unknown controller type!\n"); return(1); } /* * RA sizes tables use following magic numbers: * (ud_sizes, rc_sizes, rq_sizes) * -1, partition ends at end of disk. * -2, partition ends at start of maintenance area. * Note: for the purposes of mkfs -1 and -2 mean the same. * This prevents a file system on partition 7 from * overlapping the maintenance area. */ for(i=0; i<8; i++) { if(rsp->nblocks) { pt_info[i].pt_sb = rsp->blkoff; pt_info[i].pt_nb = rsp->nblocks; } else pt_info[i].pt_flags |= PT_NUP; /* See comment above (-1 & -2 same in this case) */ if(rsp->nblocks < 0L) { pt_info[i].pt_nb = ra_drv[ra_index[dip->di_cn]+unit].d_un.ra_dsize - rsp->blkoff; pt_info[i].pt_nb -= ra_mas[dip->di_cn]; } rsp++; } nbpc = 0; break; case RL_BMAJ: /* all partitions start at block 0 */ pt_info[7].pt_nb = (long)rl_dt[unit]; /* drive type = unit size */ pt_info[7].pt_op = 3; /* operlaps 0 and 1 */ pt_info[0].pt_nb = 10240L; /* RL01 & RL02 both use partition 0 */ i = 2; if(rl_dt[unit] == RL02) { pt_info[1].pt_nb = 10240L; } else i = 1; for(; i<7; i++) pt_info[i].pt_flags |= PT_NUP; /* TODO: should use sd_smask, but that's just too bad! -- Fred Canter */ if(sd_info[dip->di_dt[unit]].sd_flags&SD_SYSDSK) { if((rl_dt[unit] == RL02) && (unit == sdunit)) { pt_info[0].pt_flags |= PT_SYS; pt_info[1].pt_flags |= PT_SYS; pt_info[7].pt_flags |= PT_OP; } if((rl_dt[unit] == RL01) && ((unit == 0) || (unit == 1))) { pt_info[0].pt_flags |= PT_SYS; pt_info[7].pt_flags |= PT_OP; } } return(0); case HX_BMAJ: /* THIS CAN'T HAPPEN */ printf("\n(spt) - can't use RX02!\n"); return(1); case HP_BMAJ: case HM_BMAJ: case HJ_BMAJ: switch(sd_info[dip->di_dt[unit]].sd_type) { case RP04: case RP05: case RP06: nbpc = RP456_BPC; dsp = &hp_sizes; break; case RM02: case RM03: nbpc = RM23_BPC; dsp = &hp_sizes[8]; break; case RM05: nbpc = RM5_BPC; dsp = &hp_sizes[16]; break; case ML11: /* THIS CAN'T HAPPEN */ printf("\n(spt) - can't use ML11!\n"); return(1); default: /* THIS CAN'T HAPPEN */ printf("\n(spt) - unknown drive type!\n"); return(1); } break; case HK_BMAJ: nbpc = RK67_BPC; dsp = &hk_sizes; break; default: /* THIS CAN'T HAPPEN */ printf("\n(spt) - unknown controller type!\n"); return(1); } if(nbpc) /* get partition sizes, unless this is MSCP disk */ for(i=0; i<8; i++) { if(dsp->nblocks) { pt_info[i].pt_sb = (long)dsp->cyloff * (long)nbpc; pt_info[i].pt_nb = dsp->nblocks; } else pt_info[i].pt_flags |= PT_NUP; dsp++; } for(i=0; i<8; i++) { /* find overlapping partitions */ if(pt_info[i].pt_flags&PT_NUP) continue; /* non usable partition */ i_sb = pt_info[i].pt_sb; i_eb = pt_info[i].pt_sb + pt_info[i].pt_nb - 1; for(j=0; j<8; j++) { if(pt_info[j].pt_flags&PT_NUP) continue; /* non usable partition */ if(j == i) continue; /* can't overlap itself */ j_sb = pt_info[j].pt_sb; j_eb = pt_info[j].pt_sb + pt_info[j].pt_nb - 1; if(((i_sb >= j_sb) && (i_sb <= j_eb)) || ((i_eb >= j_sb) && (i_eb <= j_eb)) || ((j_sb >= i_sb) && (j_sb <= i_eb)) || ((j_eb >= i_sb) && (j_eb <= i_eb)) || ((j_sb <= i_eb) && (j_eb >= i_sb))) pt_info[i].pt_op |= (1 << j); } } /* * If this is the system disk, * mark any partitions used by the system unusable. * Also, mark any partitions which overlap them unusable. */ if((sd_info[dip->di_dt[unit]].sd_flags&SD_SYSDSK) && (unit == sdunit) && (dip->di_cn == sdcntlr)) { for(i=0; i<8; i++) { if(sd_info[dip->di_dt[unit]].sd_smask&(1<<i)) { pt_info[i].pt_flags |= PT_SYS; for(j=0; j<8; j++) if(pt_info[i].pt_op & (1<<j)) pt_info[j].pt_flags |= PT_OP; } } } return(0); } /* * Print the disk partition layout table (pt_info[]). * Show only the available partitions. * Return 1 if no available partitions remain. */ ppt(unit, dip) register struct di_info *dip; int unit; { register int i, j; int npa; npa = 0; for(i=0; i<8; i++) if(pt_info[i].pt_flags == 0) npa++; pdoc(unit, dip); /* print disk unit # on cntlr message */ printf("disk partition layout:"); printf("\n(See also, System Management Guide Appendix D)\n"); printf("\nPart- Start Size in Overlapping Partition"); printf("\nition Block # K bytes Partitions Available"); printf("\n----- ------- ------- --------------- ---------"); for(i=0; i<8; i++) { if(pt_info[i].pt_flags&PT_NUP) continue; printf("\n%5d %7D %7D ",i,pt_info[i].pt_sb/2,pt_info[i].pt_nb/2); for(j=0; j<8; j++) { if((pt_info[i].pt_op&(1<<j))) printf("%d ", j); else printf(" "); } printf(" "); if(pt_info[i].pt_flags&PT_SYS) printf("NO: used by the system!"); else if(pt_info[i].pt_flags&PT_USER) printf("NO: already used!"); else if(pt_info[i].pt_flags&PT_OP) printf("NO: overlaps used partition!"); else printf("YES: available for use!"); } printf("\n"); if(npa == 0) return(1); else return(0); } /* * Make a file system the specified disk. * TODO: directory naming scheme will break if there * are more than 10 mounted user file systems! */ char mfscmd[100]; mfsdisk(unit, fs, dip) register struct di_info *dip; int unit,fs; { register char *p; p = dsfn(RAW, unit, fs, dip); /* node name (/dev/r??##) */ sprintf(mfscmd, "/etc/mkfs %s %D %s %d %s %s", p, (long)pt_info[fs].pt_nb/2, sd_info[dip->di_dt[unit]].sd_lname, cputyp[tpi].p_type, fsname, volname); printf("\n%s\n", mfscmd); while(system(mfscmd) != 0) { if(retry(&mfscmd)) continue; else return(1); } return(0); } /* * Return a pointer to a special device name string. * RAW /dev/r??## or /dev/r??# * BLK /dev/??## or /dev/??# */ char dsfname[15]; dsfn(mode, unit, fs, dip) register struct di_info *dip; int mode, unit, fs; { if(dip->di_flags&DI_NPD) sprintf(dsfname, "/dev%s%s%d", (mode==RAW) ? "/r" : "/", dip->di_name, unit); else if(dip->di_flags&DI_MSCP) sprintf(dsfname, "/dev%s%.2s%d%d", (mode==RAW) ? "/r" : "/", sd_info[dip->di_dt[unit]].sd_lname, unit, fs); else sprintf(dsfname, "/dev%s%s%d%d", (mode==RAW) ? "/r" : "/", dip->di_name, unit, fs); return(&dsfname); } /* * Prints: * DISK Unit # on ?????? Controller # -- */ pdoc(unit, dip) register struct di_info *dip; int unit; { printf("\n%s Unit %d on %s Controller ", sd_info[dip->di_dt[unit]].sd_uname, unit, dip->di_typ); if(dip->di_flags&DI_MASS) printf("%d ", dip->di_cn); printf("-- "); } /* * Add an entry to the /etc/fstab for * the new user file system. * * flag - FST_SCH = return true if entry is in the fstab * FST_ENT = make new fstab entry (discard any existing entry) * bdisk - block special file (/dev/??##) * mntdir - mounted on directory (/user##) * * If making a new entry, * remove any fstab entry that matches bdisk or mntdir. */ fstab(flag, bdisk, mntdir) int flag; char *bdisk; char *mntdir; { register FILE *fo; register struct fstab *fstp; int pn, j, match; if(flag != FST_SCH) { if((fo = fopen("/tmp/setup.fstab", "w")) == NULL) { printf("\nCreate of /tmp/setup.fstab file failed!\n"); su_err(FATAL); } } pn = 2; match = 0; while(1) { if((fstp = getfsent()) == NULL) break; /* end of fstab */ if(flag == FST_SCH) { if(fsequal(bdisk, fstp->fs_spec) && fsequal(mntdir, fstp->fs_file)) { match++; break; } else continue; } if(fsequal(bdisk, fstp->fs_spec)) { match++; continue; /* bdisk matches, discard */ } if(flag == FST_ENT) { if(fsequal(mntdir, fstp->fs_file)) continue; /* mntdir matches, discard */ } if(fsequal("/", fstp->fs_file)) j = 1; else j = pn++; fprintf(fo, "%s:%s:%s:%d:%d\n", fstp->fs_spec, fstp->fs_file, fstp->fs_type, fstp->fs_freq, j); } endfsent(); if(flag == FST_SCH) return(match); if(flag == FST_ENT) { if(strcmp("/", mntdir) == 0) j = 1; else j = pn++; fprintf(fo, "%s:%s:rw:1:%d\n", bdisk, mntdir, j); /* add new entry */ } fclose(fo); sprintf(syscmd, "cp /tmp/setup.fstab /etc/fstab"); if(system(syscmd) != 0) { printf("\n%s failed!\n", syscmd); su_err(FATAL); } unlink("/tmp/setup.fstab"); sync(); return(match); } /* * Ask if console terminal is a CRT, * do stty and select correct .profile if so. */ /* * TODO: need to deal with following: * * .cshrc and .login file for root * change 24 -> 22 for console in /etc/ttys * change dw3 to vt100 in /etc/ttytpye * fix profiles & csh files for any possible console login account * need to deal with speeds < 1200 BPS (no backspace/erase on CRT) */ gcrt() { register int j, crt; while(1) { crt = NO; printf("\nIs the console terminal a CRT (video terminal) <y or n> ? "); j = yes(HELP); if(j == YES) { crt = YES; system("cp /crt.profile /profile"); system("stty 9600"); system("stty dec crt"); } else if(j == NO) { system("stty 300"); system("stty dec prterase"); system("cp /prt.profile /profile"); } else if(j == HELP) { phelp("h_crt"); continue; } printf("%sconsole is a %s terminal <y or n> ? ", confirm, (crt == YES) ? "VIDEO" : "HARDCOPY"); if(yes(NOHELP) != YES) continue; break; } return(crt); } fsequal(fs, fst) char *fs; /* bdisk or mntdir */ char *fst; /* fstab: fs_spec or fs_file */ { register int i; register char *p; char str[20]; p = fst; for(i=0; i<20; i++) { str[i] = *p++; if(str[i] == ':') { str[i] = '\0'; break; } } return(!strcmp(fs, &str)); } 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 su_err(FATAL); } break; } } get_dst() { register int cc; register struct dst_table *dst_ptr; again: printf("\nChoose the Geographic Area for the daylight savings time from the table below\n"); printf("\n\t\tGeographic Area\tSelection\n"); printf("\t\t---------------\t---------\n"); for(dst_ptr=dst_table;dst_ptr->dst_area;dst_ptr++) { printf("\t\t%s",dst_ptr->dst_area); if(strlen(dst_ptr->dst_area) > 7) printf("\t"); else printf("\t\t"); printf("%4d\n",dst_ptr->dst_id); } do printf("\nEnter the selection number <%d> ",DST_USA); while((cc = getline("h_dstarea")) < 0); if(cc == 0) return(DST_USA); /* USA (default) */ cc = atoi(lbuf); if((cc < DST_USA) || (cc > DST_EET)) { printf("Enter a number between %d and %d\n",DST_USA,DST_EET); goto again; } return(cc); }