/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ static char Sccsid[] = "@(#)cmx1.c 3.0 4/22/86"; /* * ULTRIX-11 communications exerciser (cmx). * * DH11/DHU11/DHV11/DZ11/DZV11/DZQ11/DL11 * * PART 1 - (cmx1.c) * * Part 1 does the initial setup and argument processing * then writes the results into the `cmx_?#.arg' file, * (? = dh, dhu, dhv, dz, dzv, dzq, dl # = unit number). * The first 16 DL11 lines are treated as DL unit 0 and the * second 16 are DL11 unit 1. DL11 line 0 is the console and * cannot be tested ! * It then calls part 2 which is the actual exerciser. * The program is split this way to optimize memory usage. * * Fred Canter 10/21/82 * Bill Burns 4/84 * added DHU/DHV support * added iostats printout (ala disk exer's) * added DZQ support * added check that all lines of a DH/DZ/DZV/DZQ are not * enabled in ttys, when maintenance loopback mode * is used. * added event flag code * * This program exercises one DH11, DHU11/DHV11, DZ11/DZV11/DZQ11, * or DL11 unit, (a DL11 unit is actually 16 DL11's) * either in maintenance loop back mode or with line * turnaroud connectors on the mux panel. * * Maintenance loopback mode: * * 1. Maintenance loopback mode for DH11 and DZ11/DZV11/DZQ11 * automatically loops back all lines. This means that all * terminal lines on DH11 and DZ11/DZV11/DZQ11 devices must be * disabled in the `/etc/ttys' file. * * 2. The DHU11/DHV11 controllers allow loopback on individual lines. * When testing DHU11/DHV11 devices only the lines that are * being tested need to be disabled in the `/etc/ttys' file. * * Turnaround connectors: * * With turnaround connectors, only the line(s) to be * exercised must be disabled in `/etc/ttys'. * **************************************************************** * WARNING WARNING WARNING WARNING WARNING WARNING * * * * For the DH11, DZ11/DZV11/DZQ11 and DL11 type * * controllers, when exercised in maintenance loop * * back mode character output on the transmit lines is * * NOT disabled ! Prior to running this exerciser the * * customers equipment, other than terminals, must be * * disconnected from the lines to be exercised or * * disabled, if it would be affected by the test data on * * the lines. Also (cmx) will not function properly * * unless the currently running ULTRIX-11 kernel is * * named `unix'. * * * **************************************************************** * * USAGE: * * cmx [-h] -unit [-m] [-l # [#]] [-u #] [-b #] [-n #] * [-e #] [-s[#]] [-i] [-z #] * * -unit Unit number and type - dh#, dhu#, dhv#, dz#, dzv#, dzq#, * must be given. * For the DL11, unit 0 is dl 1 - 15, & unit 1 is dl 16 - 31 * DL line 0 is the console, can't be tested ! * * -h Print the help message. * * -m Suppress maintenance loop back mode. * Line turnaround connector will be required. * * -l # # Select line(s), default is all lines. * # = line, # = bit rate (optional) * ( bit rate must be specified for DL's, via -l or -b ) * * -u # Do not run line #, multiple lines may be deselected. * * -b # Select bit rate # for all lines, overrides bit rate set by -l. * ( bit rate must be set for DL's, via -l or -b ) * * -n # Limit the number of data mismatch errors to be printed to #. * The default is 5 and the maximum is 132. * * -e # Set the data error limit to #, default = 100, maximum = 1000. * If the limit is exceeded, the line is deselected. * Also the line is deselected after 5 receiver timeouts. * * -s# Specify time intervals for periodic I/O statistics printouts. * The time interval (#) is in minutes and can range * from 1 to 720 (12 hours). * The default time interval is 1/2 hour. * If no time interval is specified (-s only), * the I/O statistics are not printed. * * -i Inhibit the one minute delay and warning message. * NOT DOCUMENTED FOR OR USED BY THE USER * * -z # Specifies the "exerciser number" in the script * which is the event flag bit that controla the * starting/stopping of the exerciser. * * Below option is gone due to event flag usage: * -r kfn Specify the run/stop control file name (kill filename). * */ #include <stdio.h> #include <a.out.h> #include <signal.h> #include <sys/param.h> /* Don't matter which one */ #include <sys/stat.h> #include <sys/devmaj.h> #define R 0 #define W 1 #define RW 2 char afn[20]; /* argument passing file name */ char argbuf[512]; /* argument passing buffer */ struct nlist nl[] = { { "_usermem" }, { "_sepid" }, { "" }, }; char dn[4]; /* DH/DHU/DHV/DZ/DZV/DZQ/DL device name */ char tdn[12] = "/dev/"; /* tty node name `/dev/tty??' */ char ttys[20]; /* one line ffrom `/etc/ttys' - ##tty## */ int unit; /* DH11/DHU11/DHV11/DZ11/DZV11/DZQ11/DL11 unit number */ int nline; /* number of lines per unit */ /* * Line activity table, * -1 = line not selected * 0 = line deselected via -u * 1 = line selected via -l (without bit rate) * >1 = line selected via -l (with bit rate) * for active lines, set to bit rate (sgtty) number. */ int lnact[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; char *help[] = { "\n\n(cmx) - ULTRIX-11 DH11/DHU11/DHV11/DZ11/DZV11/DL11 exerciser.", "\nUsage:", "\tcmx [-h] -unit [-m] [-l # [#]] [-u #] [-b #] [-n #] [-e #]", "\n\t-h\tPrint this help message.", "\n\t-unit\tUnit number and type - dh#, dhu#, dhv# dz#, dzv#, dzq# or dl#.", "\n\t-m\tSuppress maintenance loop back mode.", "\n\t-l # #\tSelect line(s) - # = line, # = bit rate.", "\n\t-u #\tDo not run line #, multiple lines may be deselected.", "\n\t-b #\tSelect bit rate # for all lines.", "\n\t-n #\tLimit the number of data mismatch errors printed to #.", "\t\tThe default is 5 and the maximum is 132.", "\n\t-e #\tSet the data error limit to #, default = 100, maximum = 1000.", "\t\tIf the limit is exceeded, the line is deselected.", "\t\tAlso the line is deselected after 5 receiver timeouts.", "", 0 }; struct stat statb; int dhflag, dhuflag, dhvflag, dzflag, dzvflag, dzqflag, dlflag; int nmflag, brflag, lsflag; int iflag, sflag; int ndep = 5; int ndel = 100; int istime = 30; #ifdef EFLG char *efbit; char *efids; int zflag; #else char *killfn = "cmx.kill"; #endif main(argc, argv) char *argv[]; int argc; { int stop(), intr(); register int i, j, k; register char *p, *n; int *ap; int fi, fo, ln, opnerr; int maj; int burst, maxcc, bufsiz; int mem, usermem, sepid; int lineon; setpgrp(0, 31111); signal(SIGTTOU, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGQUIT, stop); if(argc < 2) goto argerr; for(i=1; i<argc; i++) { p = argv[i]; if(*p++ != '-') { argerr: fprintf(stderr, "\ncmx: bad arg\n"); goto usage; } switch(*p) { case 'h': /* Print help message */ usage: for(j=0; help[j]; j++) fprintf(stderr, "\n%s", help[j]); exit(0); #ifdef EFLG case 'z': zflag++; i++; efbit = argv[i++]; efids = argv[i]; break; #else case 'r': i++; killfn = argv[i]; break; #endif case 'i': iflag++; break; case 'd': /* DH/DHU/DHV/DZ/DZV/DZQ/DL unit select */ dn[0] = *p++; if(*p == 'h') { if(*(p+1) == 'v') dhvflag++; else if(*(p+1) == 'u') dhuflag++; else dhflag++; } else if(*p == 'l') dlflag++; else if(*p == 'z') { if(*(p+1) == 'v') dzvflag++; else if(*(p+1) == 'q') dzqflag++; else dzflag++; } else { badu: fprintf(stderr, "\ncmx: bad unit\n"); goto usage; } dn[1] = *p++; if(dzvflag || dzqflag || dhuflag || dhvflag) p++; if(dhuflag || dhvflag) dn[0] = 'u'; if(*p < '0' || *p > '7') goto badu; unit = *p - '0'; dn[2] = *p++; dn[3] = 0; if(*p != 0) goto badu; break; case 'm': /* Suppress maintenance loop back mode */ nmflag++; break; case 'b': /* Set bit rate on all lines */ i++; p = argv[i]; if(*p < '0' || *p > '9') goto argerr; if((brflag = brcon(p)) < 0) { badbr: fprintf(stderr, "\ncmx: bad bit rate\n"); goto usage; } break; case 'l': /* line select */ i++; j = atoi(argv[i]); if(j < 0 || j > 15) { badln: fprintf(stderr, "\ncmx: bad line number\n"); goto usage; } lnact[j] = 1; lsflag++; if((argv[i+1] [0] == '-') || ((i+1) >= argc)) break; i++; if((k = brcon(argv[i])) < 0) goto badbr; lnact[j] = k; /* save bit rate */ break; case 'n': /* limit data error printouts */ i++; p = argv[i]; if(*p < '0' || *p > '9') goto argerr; ndep = atoi(p); if(ndep < 0 || ndep > 132) { fprintf(stderr, "\ncmx: bad error print limit, using default (5)\n"); ndep = 5; } break; case 'u': /* deselect a line */ i++; j = atoi(argv[i]); if(j < 0 || j > 15) goto badln; lnact[j] = 0; break; case 'e': /* set data error limit */ i++; p = argv[i]; if(*p < '0' || *p > '9') goto argerr; ndel = atoi(p); if (ndel < 0 || ndel > 1000) { fprintf(stderr, "\ncmx: bad data error limit, using default (100)\n"); ndel = 100; } break; case 's': sflag++; p++; if(*p < '0' || *p >'9') break; sflag = 0; istime = atoi(p); if(istime <= 0) istime = 30; if(istime > 720) istime = 720; break; default: goto argerr; } } if(!zflag) { if(isatty(2)) { fprintf(stderr,"cmx: detaching... type \"sysxstop\" to stop\n"); fflush(stderr); } if((i = fork()) == -1) { printf("cmx: Can't fork new copy !\n"); exit(1); } if(i != 0) exit(0); } setpgrp(0, 31111); if((dhflag + dhuflag + dhvflag + dzflag + dzvflag + dzqflag + dlflag) != 1) goto badu; if(dzflag) { nline = 8; maj = DZ_RMAJ << 8; } else if(dzvflag || dzqflag) { nline = 4; maj = DZ_RMAJ << 8; } else if(dlflag) { nline = 16; maj = CO_RMAJ << 8; /* NOT DL_RMAJ !!! */ } else if(dhvflag) { nline = 8; maj = UH_RMAJ << 8; } else if(dhuflag) { nline = 16; maj = UH_RMAJ << 8; } else { nline = 16; maj = DH_RMAJ << 8; } /* * Set the character count burst size and maximum * character count based on the amount of free memory * after the ULTRIX-11 kernel. * The symbol `usermem' is read from the kernel * to obtain the free memory value. * If free memory exceeds 256 kb then the burst is 16 * and the maximum count is 128, otherwise the burst * is 8 and the maximum count is 64. */ nlist("/unix", nl); if(nl[0].n_type == 0) { fprintf(stderr, "\ncmx: Can't access /unix namelist\n"); exit(1); } if((mem = open("/dev/mem", R)) < 0) { fprintf(stderr, "\ncmx: Can't open /dev/mem\n"); exit(1); } lseek(mem, (long)nl[0].n_value, 0); read(mem, (char *)&usermem, sizeof(usermem)); lseek(mem, (long)nl[1].n_value, 0); read(mem, (char *)&sepid, sizeof(sepid)); close(mem); if((usermem >= 4096) && sepid) { burst = 32; maxcc = 0177; bufsiz = 132; } else { burst = 16; maxcc = 077; bufsiz = 68; } /* * In order to prevent overrun errors, the burst size * is reduced in some cases. */ if(dlflag) burst = 1; if(!dlflag && !dzflag && !dzvflag && !dzqflag) burst = burst/4; /* * Set up line activity table. * If -l was specified, turn on selected lines. * If not turn on all lines, * except those deselected by [-u #]. * If -b specified, set all lines to selected * bit rate. */ for(i=0; i<16; i++) { if(lnact[i] > 0) { /* line selected */ if((i >= 4) && dzvflag) { fprintf(stderr,"\ncmx: DZV has only 4 lines\n"); exit(1); } if((i >= 4) && dzqflag) { fprintf(stderr,"\ncmx: DZQ has only 4 lines\n"); exit(1); } if((i >= 8) && dzflag) { fprintf(stderr, "\ncmx: DZ has only 8 lines\n"); exit(1); } if((i >= 8) && dhvflag) { fprintf(stderr,"\ncmx: DHV has only 8 lines\n"); exit(1); } if(dlflag && (i == 0) && (unit == 0)) { fprintf(stderr, "\ncmx: DL 0 is console, can't exercise !\n"); exit(1); } if(brflag) lnact[i] = brflag; /* set bit rate */ } else if(lnact[i] < 0) { if(!lsflag) { if(brflag) lnact[i] = brflag; else lnact[i] = 1; } } else lnact[i] = -1; } /* * For the DL11 only, make sure that all selected lines * also have the bit rate specified. The randum bit rate * pattern cannot be used with the DL11 because the bit * rate is not programmable. */ if(dlflag) { for(i=0; i<16; i++) if(lnact[i] == 1) { fprintf(stderr,"\ncmx: DL line %d selected,",i); fprintf(stderr," without specifing bit rate !\n"); exit(1); } } /* * Read the `/etc/ttys' and print an error message * if any of the tty lines on this DH/DZ/DZV/DL are enabled. * This is necessary to prevent the test data outputted on * the line from being seen as input from a terminal * by ULTRIX-11. */ if(freopen("/etc/ttys", "r", stdin) == NULL) { fprintf(stderr, "\ncmx: Can't open `/etc/ttys' file\n"); exit(1); } opnerr = 0; fgets(ttys, 20, stdin); /* skip first line in /etc/ttys */ while(fgets(ttys, 20, stdin) != NULL) { if((ttys[0] > '0') && (ttys[0] < '4')) { /* line enabled */ /* ln = atoi(&ttys[5]); */ /* new */ p = &ttys[2]; n = &tdn[5]; for(;*p != '\n'; p++, n++) *n = *p; *n = '\0'; /* new */ /* sprintf(&tdn, "/dev/tty%02d", ln); */ if(stat(&tdn, &statb) < 0) { fprintf(stderr, "\ncmx: Can't stat %s\n", tdn); exit(1); } if(maj != (statb.st_rdev & 0177400)) continue; /* not this device */ for(j=0; j<nline; j++) { if((statb.st_rdev & 0377) != (j + (unit*nline))) continue; lineon++; if(lnact[j] >= 0) { /* line selected */ /*fprintf(stderr,"\ncmx: tty%02d on %s line %02d",ln,dn,j); */ fprintf(stderr,"\ncmx: %s on %s line %02d",&tdn,dn,j); fprintf(stderr,", must be disabled in `/etc/ttys' file."); opnerr++; } } } } if(opnerr) { fprintf(stderr, "\n"); exit(1); } if(lineon && (dhflag||dzflag||dzvflag||dzqflag) && (nmflag == 0)) { fprintf(stderr, "\ncmx: All lines on %s must be disabled in the \n", dn); fprintf(stderr, "`/etc/ttys' file, when using maintenance loopback mode !\n"); exit(1); } fclose(stdin); /* * Create the DH/DHU/DHV/DZ/DZV/DL nodes: * * `/dev/dh#??', `/dev/uh#??', `/dev/dz#??', or `/dev/dl#??' * */ for(i=0; i<nline; i++) { sprintf(&tdn, "/dev/%s%02d", dn, i); unlink(tdn); if(lnact[i] >= 0) if(mknod(tdn, 020600, (maj | (i+(unit*nline)))) < 0) { fprintf(stderr, "\ncmx: Can't create %s", tdn); fprintf(stderr, ", must be super-user !\n"); exit(1); } } /* * Write needed data into the `cmx_??#.arg' file, * and call part 2 of the exerciser (cmxr). */ ap = &argbuf; *ap++ = maj; *ap++ = unit; *ap++ = dzflag; *ap++ = dzvflag; *ap++ = dzqflag; *ap++ = dhuflag; *ap++ = dhvflag; *ap++ = dlflag; *ap++ = sflag; *ap++ = istime; *ap++ = ndep; *ap++ = ndel; *ap++ = bufsiz; *ap++ = burst; *ap++ = maxcc; *ap++ = brflag; *ap++ = nmflag; #ifdef EFLG *ap++ = zflag; #endif for(i=0; i<16; i++) *ap++ = lnact[i]; sprintf(&afn, "cmx_%s.arg", dn); if((fo = creat(afn, 0644)) < 0) { fprintf(stderr, "\ncmx: Can't create %s file\n", afn); exit(1); } if(write(fo, (char *)&argbuf, 512) != 512) { fprintf(stderr, "\ncmx: %s write error\n", afn); exit(1); } close(fo); fflush(stdout); if(iflag == 0) iprint(dn); signal(SIGQUIT, SIG_IGN); #ifdef EFLG if(zflag) execl("cmxr", "cmxr", dn, efbit, efids, (char *)0); else execl("cmxr", "cmxr", dn, (char *)0); #else execl("cmxr", "cmxr", dn, killfn, (char *)0); #endif fprintf(stderr, "\ncmx: Can't exec cmxr\n"); exit(1); } /* * Convert a bit rate, i.e., 9600 to * the bit rate number used by sgtty. */ brcon(brp) char *brp; { switch(atoi(brp)) { case 110: return(3); break; case 300: return(7); break; case 1200: return(9); break; case 2400: return(11); break; case 4800: return(12); break; case 9600: return(13); break; default: return(-1); } } stop() { exit(0); } iprint(dn) char *dn; { fprintf(stderr, "\n\n\7\7\7****** WARNING WARNING WARNING ******\n"); fprintf(stderr, "\nTest data will be transmitted on %s output lines.", dn); fprintf(stderr, "\nCustomer equipment which may be affected by"); fprintf(stderr, "\nthe test data must be disconnected or disabled."); fprintf(stderr, "\nData transmission will begin in one minute !"); fprintf(stderr, "\nTo abort transmission type control \\ \n"); sleep(60); }