# /* * getty -- adapt to terminal speed on dialup, and call login */ #include <local-system> /* * Modified 10/77 Piers Lauder * changes: * generally tidied up * new terminal types */ #define AUSAM /* * piers lauder oct '77 * * "login" incorporated into "getty" * ( users must now type CTRL-d at end of session * to allow "init" to collect statistics ) * * Piers Lauder Feb '78 - May '78 * * the whole AUSAM works ... */ #define DISK_LIMIT /* * Piers Lauder Apr '78 * * if disk llimits to be implemented */ #define LOGIN_TIME /* * Piers Lauder Apr '78 * * Print out time and date on logon. * This is mentioned in the manual, so if you want it ... */ #define T_STOPS 0200 /* ** Piers Lauder Jul '78 ** ** Set tab stops for terminals that need programming */ #define INITIALISE #define INITFILE ".profile" #define RX 05 /* read and execute */ /* ** Greg Rose 24 July '78 ** ** Automatically run an initialisation shell file after logging ** in. The name of the file is ".profile" a la PWB-Unix. */ #ifdef AUSAM #define TTY_GROUP #include <ttygroup.h> /* ** Ian Johnstone Sep '78 ** ** Include code for the support of terminal groups ** and terminal masks. A terminal group table from ** <local-system> is searched with the third argument ** passed to getty - this generates a bit-mask which ** is &'ed with the 'pw_tmask' field from the passwd ** entry for the user. If result is non-zero ** then a login will be allowed. This allows good ** control over which users can use which terminals. ** Will only work if AUSAM defined */ #endif AUSAM /* * terminals */ #ifdef AGSM #define LOG '#' #define TEKTRONICS 'g' #define LA36 'd' #define DIALUP 'u' #define LS120 'D' #define STRANSDATA 'T' #define TRANSDATA 't' #define VT52_5 'V' #define ELECTRIC 'S' #define QUME 'q' #define QUME5 'Q' #define TELERAY 'W' #define COPS10 '8' /* at 19200 baud */ #define LOG1200 'B' /* specially for basser */ #endif AGSM #ifdef BASSER #define TEKTRONICS 'T' #define LA36 'l' #define CDC713 'c' #define DIABLO ('d'|T_STOPS) #define SDIABLO ('D'|T_STOPS) #define IMLAC 'i' #define ASR33 '-' #define NCR260 'N' #define ADM1_A 'a' #endif BASSER #ifdef EECF #define LOG '#' #define FASTLOG '4' #define VT05 'v' #define TEK4014 'T' #define LA36 'd' #define ELECTRIC 'S' #define QUME5 'Q' #define LS120 'D' #define TELERAY 'W' #endif EECF /* * Unused terminals types * #define DIAL_IN '0' #define IBM2741 '1' */ /* * tty flags */ #define HUPCL 01 #define XTABS 02 #define LCASE 04 #define ECHO 010 #define CRMOD 020 #define RAW 040 #define ODDP 0100 #define EVENP 0200 #define ANYP 0300 #define INVCASE 04000 #define FLOWCNTRL 0100000 /* * Delay algorithms */ #define NL1 000400 #define NL2 001000 #define NL3 001400 #define TAB1 002000 #ifndef INVCASE #define TAB2 004000 #define TAB3 006000 #endif #define CR1 010000 #define CR2 020000 #define CR3 030000 #define FF1 040000 #ifndef FLOWCNTRL #define BS1 0100000 #endif #ifdef BASSER #define ERASE '\b' #else #define ERASE '#' #endif BASSER #define KILL '@' /* * speeds */ #define B110 3 #define B134_5 4 #define B150 5 #define B300 7 #define B600 8 #define B1200 9 #define B2400 11 #define B4800 12 #define B9600 13 #define EXTB 15 #define SIGINT 2 #define SIGQIT 3 struct sgtty { char sgispd, sgospd; char sgerase, sgkill; int sgflag; } tmode; char nlbel[] "\r\n\007"; struct tab { char tname; /* this table name */ char nname; /* successor table name */ int iflags; /* initial flags */ int fflags; /* final flags */ char ispeed; /* input speed */ char ospeed; /* output speed */ char *message; /* login message */ } itab[] { #ifdef DIAL_IN /* table DIAL_IN-1-2 300,150,110 */ { DIAL_IN, 1, EVENP+RAW+NL1+CR1+HUPCL, EVENP+CR1+XTABS+HUPCL, B300, B300, "\n\r\033;\007" }, { 1, 2, EVENP+RAW+NL1+CR1, EVENP+ECHO+FF1+CR2+TAB1+NL1, B150, B150, "\n\r\033:\006\006\017" }, { 2, DIAL_IN, ANYP+RAW+NL1+CR1, ANYP+ECHO+XTABS+CR1, B110, B110, nlbel }, #endif #ifdef ASR33 /* table ASR33 -- ASR33 110 */ { ASR33, ASR33, ANYP+RAW+NL1+CR1, ANYP+ECHO+CRMOD+XTABS+CR1+LCASE, B110, B110, nlbel }, #endif #ifdef IBM2741 /* table IBM2741 -- 134_5 */ { IBM2741, IBM2741, EVENP+RAW+NL1, EVENP+NL1, B134_5, B134_5, "\n" }, #endif #ifdef UFO /* table '9' -- 9600 */ { '9', '9', ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD+FF1, B9600, B9600, "\n\r\033;" }, #endif #ifdef VT05 /* table VT05 -- vt05 */ { VT05,VT05, ANYP+RAW+NL2, ANYP+NL2+ECHO+CRMOD, B2400, B2400, "\035\035\035\035\037\037\037\037" }, #endif #ifdef LOG /* table LOG -- LOG device twixt here and remote UNIX sites .... */ { LOG, LOG, ANYP+RAW, ANYP+ECHO+XTABS+CRMOD, B4800, B4800, nlbel }, #endif #ifdef FASTLOG /* table FASTLOG -- FASTLOG device twixt here and our 11/40 .... */ { FASTLOG, FASTLOG, ANYP+RAW, ANYP+ECHO+XTABS+CRMOD, B9600, B9600, nlbel }, #endif #ifdef LA36 /* table LA36 -- LA36 */ { LA36, LA36, ANYP+RAW, ANYP+XTABS+ECHO+CRMOD, B300, B300, nlbel }, #endif #ifdef DIALUP /* table DIALUP -- DIALUP */ { DIALUP, DIALUP, ANYP+RAW+HUPCL, ANYP+XTABS+ECHO+CRMOD+HUPCL, B300, B300, nlbel }, #endif #ifdef LS120 /* table LS120 -- LS120 */ { LS120, LS120, ANYP+RAW, ANYP+NL1+CR1+XTABS+ECHO+CRMOD, B1200, B1200, nlbel }, #endif #ifdef LOG1200 /* table LOG1200 -- Basser leased line login */ { LOG1200, LOG1200, ANYP+RAW, ANYP+XTABS+ECHO+CRMOD, B1200, B1200, nlbel }, #endif #ifdef VT52_5 /* table VT52_5 -- vt52/5 */ { VT52_5, VT52_5, ANYP+RAW, ANYP+ECHO+CRMOD, B4800, B4800, nlbel }, #endif #ifdef COPS10 /* table COPS10 -- for COPS10 at 19200 */ { COPS10, COPS10, ANYP+RAW, ANYP+ECHO+CRMOD+XTABS, EXTB, EXTB, nlbel }, #endif #ifdef TELERAY /* table TELERAY -- for TELERAY at 4800 */ { TELERAY, TELERAY, ANYP+RAW, ANYP+ECHO+CRMOD+XTABS, B4800, B4800, nlbel }, #endif #ifdef ELECTRIC /* table ELECTRIC -- for ELECTRIC at 2400 */ { ELECTRIC, ELECTRIC, ANYP+RAW, ANYP+ECHO+CRMOD+XTABS, B2400, B2400, "\035\037", }, #endif #ifdef DIABLO /* table DIABLO-'D' -- Diablo Hyterm at 1200-300 baud */ { DIABLO, SDIABLO, EVENP+RAW+FLOWCNTRL, EVENP+FLOWCNTRL+CRMOD, B1200, B1200, nlbel }, { SDIABLO, DIABLO, EVENP+RAW, EVENP+CRMOD, B300, B300, nlbel }, #endif #ifdef IMLAC /* table IMLAC-9-10 -- IMLAC 9600-4800-300 baud */ { IMLAC, 9, ANYP+RAW, ANYP+XTABS, B9600, B9600, nlbel }, { 9, 10, ANYP+RAW, ANYP+XTABS, B4800, B4800, nlbel }, { 10, IMLAC, ANYP+RAW, ANYP+XTABS, B300, B300, nlbel }, #endif #ifdef NCR260 /* table NCR260 -- NCR260 needs inverted case and special delays */ { NCR260, NCR260, EVENP+RAW+NL2+CR3+INVCASE, EVENP+XTABS+ECHO+CRMOD+NL2+CR3+INVCASE, B300, B300, nlbel }, #endif NCR260 #ifdef ADM1_A /* table ADM1_A -- ADM1_A needs special delays */ { ADM1_A, ADM1_A, EVENP+RAW+NL1, EVENP+XTABS+ECHO+CRMOD+NL1, B9600, B9600, "\033*\007" }, #endif MEMOREX #ifdef CDC713 /* table CDC713 -- CDC713 */ { CDC713, CDC713, EVENP+RAW, EVENP+XTABS+ECHO+CRMOD, B300, B300, nlbel }, #endif #ifdef TEKTRONICS /* table TEKTRONICS -- tektronics at 4800bd */ { TEKTRONICS, TEKTRONICS, ANYP+RAW+FF1, ANYP+CRMOD+XTABS+FF1+LCASE+ECHO, B4800, B4800, "\033\014\007" }, #endif #ifdef TEK4014 /* table TEK4014 -- tektronics at 1200bd */ { TEK4014, TEK4014, ANYP+RAW+FF1, ANYP+CRMOD+XTABS+FF1+ECHO, B1200, B1200, "\033;\033\014\007" }, #endif #ifdef QUME /* table QUME -- qume sprint printer at 300bd */ { QUME, QUME, ANYP+RAW, ANYP+ECHO+CRMOD+XTABS, B600, B600, nlbel }, #endif #ifdef QUME5 /* table QUME5 -- qume sprint printer at 1200bd */ { QUME5, QUME5, ANYP+RAW, ANYP+ECHO+CRMOD, B1200, B1200, "\r\033\037\013\0332\033(08,16,24,32,40,48,56,64,72,80,88,96,A4,B2,C0,C8,D6,E4,F2.\n\007", /* set to 12-pitch; clear tabs; set tabs every 8 */ }, #endif #ifdef TRANSDATA /* table TRANSDATA-'z' -- transdata at 300-2400bd */ { STRANSDATA, TRANSDATA, EVENP+RAW, EVENP+ECHO+CRMOD+XTABS, B300, B300, nlbel }, { TRANSDATA, STRANSDATA, EVENP+RAW, EVENP+ECHO+CRMOD+XTABS, B2400, B2400, nlbel }, #endif }; #define NITAB sizeof itab/sizeof itab[0] #define NAMZ 133 char name[NAMZ]; int crmod; int upper; int lower; #ifdef AUSAM char ttyx[] "/dev/ttyx"; #ifdef TTY_GROUP unsigned ttygmask; /* store tty group mask for current terminal here */ #endif TTY_GROUP #endif TTY_GROUP main(argc, argv) char **argv; { register struct tab *tabp; register tname; register i; #ifdef AUSAM #ifdef TTY_GROUP if( argc > 3 ) { ttyx[8] = *argv[2]; ttygmask = 0177777; /* assume all unless find matching group */ for( i = 0; i < NTTYGRPS; i++ ) if( *argv[3] == tty_groups[i].tchar ) { ttygmask = tty_groups[i].tmask; break; } } #else if ( argc > 2 ) { ttyx[8] = *argv[2]; } #endif TTY_GROUP else { printf( "Getty: wrong number of args !!\n" ); exit(1); /* init will not call getty wrongly */ } #else AUSAM tname = '0'; if (argc > 1) #endif AUSAM tname = *argv[1]; for (;;) { nice(-5); /* give getty a little help */ for(tabp = itab; tabp < &itab[NITAB]; tabp++) # ifndef T_STOPS if(tabp->tname == tname) # else if ( (tabp->tname & 0177) == tname ) # endif T_STOPS break; if(tabp >= &itab[NITAB]) tabp = itab; tmode.sgispd = tabp->ispeed; tmode.sgospd = tabp->ospeed; tmode.sgflag = tabp->iflags; tmode.sgerase = 0; tmode.sgkill = 0; stty(0, &tmode); printf( "%s%s login: ", tabp->message, SYSTEMID); if(getname()) { tmode.sgflag = tabp->fflags; if(crmod) tmode.sgflag =| CRMOD; if(upper) tmode.sgflag =| LCASE; if(lower) tmode.sgflag =& ~LCASE; #ifdef BASSER tmode.sgerase = tmode.sgflag&LCASE ? '#' : ERASE; #else tmode.sgerase = ERASE; #endif BASSER tmode.sgkill = KILL; stty(0, &tmode); # ifdef T_STOPS if ( tabp->tname & T_STOPS ) /* set tab stops */ { printf( "\0332\033\t\001\0339\033B" ); for ( i = 9 ; i < 132 ; i =+ 8 ) printf( "\033\t%c\0331", i ); } # endif T_STOPS #ifndef AUSAM execl("/bin/login", "login", name, 0); exit(1); #else login(); #endif AUSAM } sleep( 1 ); tname = tabp->nname; } } getname() { register char *np; register c; static cs; crmod = 0; upper = 0; lower = 0; np = name; do { while (read(0, &cs, 1) <= 0) sleep(1); if ((c = cs&0177) == 0) return(0); putchar( c ); if (c>='a' && c <='z') lower++; else if (c>='A' && c<='Z') { upper++; c =+ 'a'-'A'; } else if (c==ERASE) { if (np > name) np--; continue; } else if (c==KILL) { np = name; continue; } *np++ = c; } while (c!='\n' && c!='\r' && np <= &name[NAMZ]); *--np = 0; if ( np == name ) return( 0 ); if (c == '\r') { putchar( '\n' ); crmod++; } else putchar( c ); return(1); } #ifdef AUSAM #ifdef DISK_LIMIT /* choose TDU algorithm */ #define SHARELINKS /* links shared equally -> recursive directory search */ /*#define OWNER /* only owner charged for links -> inode search */ #endif DISK_LIMIT #include <param.h> #include <stat16.h> struct statbuf statb; #include <passwd.h> #include <lnode.h> #include <utmp.h> struct utmp utmp; #ifdef DISK_LIMIT #ifdef SHARELINKS long tdu(), malformed(); char *nextpath(); long t_blocks, t_files; char pathname[200]; #define PATHEND (&pathname[(sizeof pathname)]) #endif SHARELINKS #ifdef OWNER unsigned tdu(); unsigned t_blocks, t_files; #endif unsigned size(); int derror; #endif DISK_LIMIT long time(); #include "decays.h" struct { int hiword; unsigned loword; }; struct { unsigned u; }; #define ETOOMANYU 37 login() { register char *np; register i; long ttime; struct lnode llimits; struct pwent pe; # ifdef SHARELINKS unsigned parino; # endif SHARELINKS extern end, errno; /* ** extract user particulars from password file */ pe.pw_strings[LNAME] = name; { register t = SSIZ; char *pbuf = &end; for ( ;; ) { if ( sbrk( SSIZ ) == -1 ) { perror( "" ); goto out; } if ( (i = getpwuid( &pe , pbuf , t )) < 0 ) { printf( "Who?\n" ); goto out; } if ( i < t ) break; t =+ SSIZ; } } /* ** if password is non-null, verify it */ if ( *(np = pe.pw_pword) ) { register char *namep; int sflags; char pwbuf[PASSWDZ]; sflags = tmode.sgflag; if ( sflags & ECHO ) { tmode.sgflag =& ~ ECHO; stty(0, &tmode); } printf( "Password: " ); namep = pwbuf; while ((i=getchar()) != '\n') { if (i <= 0) goto out; if (namep < &pwbuf[PASSWDZ-1]) *namep++ = i; } *namep++ = '\0'; if ( sflags & ECHO ) { tmode.sgflag = sflags; stty(0, &tmode); } putchar( '\n' ); namep = crypt(pwbuf); for ( i=0 ; i<8 ; i++ ) if ( *namep++ != *np++ ) { printf( "Wrong password.\n" ); goto out; } } # ifdef TTY_GROUP if( pe.pw_uid && !(pe.pw_tmask&ttygmask) ) { if( pe.pw_tmask ) printf("You are not authorized to use this terminal\n"); else printf("Consult the system supervisor\n"); sleep(2); goto out; }; # endif TTY_GROUP # ifdef SHARELINKS /* ** get inode of parent directory of DIRPATH (N.B. ".." is not good enough) */ { register char *dp; char dbuf[SSIZ]; if ( (np = pe.pw_strings[DIRPATH]) == 0 || *np == 0 ) np = "/"; for ( dp = dbuf; *dp++ = *np++; ) if ( dp >= &dbuf[SSIZ] ) { printf( "%s: too long!\n", pe.pw_strings[DIRPATH] ); goto out; } while ( *--dp != '/' ) if ( dp <= dbuf ) { printf( "Bad directory path: %s\n", pe.pw_strings[DIRPATH] ); goto out; } if ( dp == dbuf ) /* root! */ dp++; *dp = 0; if ( newstat( dbuf, &statb ) < 0 ) { printf( "Parent directory: " ); perror( dbuf ); goto out; } parino = statb.sb_inumber; } # endif SHARELINKS /* ** move over to the user's home directory */ if ( newstat( pe.pw_strings[DIRPATH] , &statb ) < 0 || chdir(pe.pw_strings[DIRPATH]) < 0 ) { perror( pe.pw_strings[DIRPATH] ); goto out; } /* ** We are now committed to the user, and subsequent errors are fatal */ /* ** copy the message-of-the-day to keep the user guessing... */ if ((i = open("/etc/motd", 0)) >= 0) { char mbuf[512]; while( write(1, mbuf, read( i, mbuf, 512)) == 512); close(i); } ttime = time(); /* ** get limits from system, if they already exist */ llimits.l_uid = pe.pw_uid; if ( limits( &llimits, L_OTHLIM ) >= 0 ) { printf( "You already have %d process%srunning\n", llimits.l_refcount, llimits.l_refcount == 1 ? " " : "es " ); pe.pw_flags = llimits.l_flags; } else { /* ** limits don't exist, so set them up */ #ifdef DISK_LIMIT if ( pe.pw_dlimit && pe.pw_uid ) { register t; derror = 0; errno = 0; #ifdef SHARELINKS t_blocks = 0; t_files = 0; i = tdu( nextpath( pathname, pe.pw_strings[DIRPATH] ), parino ) >> 16; /* N.B. statb set up above */ #endif #ifdef OWNER i = tdu( pe.pw_uid ); /* N.B. statb set up above */ #endif if ( i.u > pe.pw_dlimit || derror ) { if ( !derror ) { printf( "\n\t%3.3s WARNING - disc limit of %l blocks exceeded by %l\n" , &"1st2nd3rd "[pe.pw_warn*3], pe.pw_dlimit, i-pe.pw_dlimit ); printf( "\t(total of %l units consists of %l blocks in %l files)\n" ,i.u #ifdef OWNER ,t_blocks ,t_files #endif #ifdef SHARELINKS ,t_blocks.hiword ,t_files.hiword #endif ); } if ( ++pe.pw_warn > NDLIMWARN || derror || i.u > (pe.pw_doverflw+pe.pw_dlimit) ) { printf( "\t-- no more disc space allowed\n" ); pe.pw_warn = NDLIMWARN; pe.pw_flags =| DLIMIT; } else { t = NDLIMWARN - pe.pw_warn; printf( "\tyou have %d warning%sleft\n" ,t ,t==1?" ":"s " ); pe.pw_flags =& ~DLIMIT; } putchar( '\n' ); } else { pe.pw_warn = 0; pe.pw_flags =& ~DLIMIT; } } else { i = 0; pe.pw_warn = 0; pe.pw_flags =& ~DLIMIT; } llimits.l_duse = i; llimits.l_doverflw = pe.pw_doverflw; #endif DISK_LIMIT llimits.l_refcount = 0; llimits.l_shares = pe.pw_shares; for ( i=0 ; i<CMASKSIZE ; i++ ) llimits.l_cmask[i] = pe.pw_cmask[i]; llimits.l_dlimit = pe.pw_dlimit; llimits.l_plimit = pe.pw_plimit; llimits.l_climit = pe.pw_climit; llimits.l_flags = pe.pw_flags; /* ** decay usage by time since last access ** YES, it could be done better with ** floating point but the approx used ** here is pretty good and more reliable ** than dec FPU. */ if ( (i = (ttime - pe.pw_extime)/(60*60) -1) >= 0 ) { register unsigned u; u = decays[i >= 240 ? 238 : i ]; if ( pe.pw_usage > (8 * u) ) llimits.l_usage = pe.pw_usage - ((pe.pw_usage / u) * i * DECAYMULT); else llimits.l_usage = pe.pw_usage - ((pe.pw_usage * i * DECAYMULT) / u); if ( llimits.l_usage < 0 ) llimits.l_usage = 0; } else llimits.l_usage = pe.pw_usage; } /* ** tell limits */ if ( pe.pw_uid && pe.pw_dlimit ) printf( "\nYou are using %l out of %l disk units\n", llimits.l_duse, pe.pw_dlimit ); /* ** update password file */ updtpwent( &pe ); /* ** make login entries in utmp & wtmp files */ { register char *namep; for ( i=(sizeof utmp.u_u_name)+1 , np=utmp.u_u_name , namep=name ; --i && (*np++ = *namep++) ; ); if ( !i && *namep ) /* name too big for field */ utmp.u_u_name[0] = '\0'; } utmp.u_ttyid = ttyx[8]; utmp.u_u_id = pe.pw_uid; utmp.u_type = U_TYPE; utmp.u_logintime = ttime; { register f; if ((f = open("/etc/utmp", 1)) >= 0) { i = utmp.u_ttyid; if ( i >= '0' && i <= '9' ) i =- '0'; else if ( i >= 'a' && i <= 'z' ) i =- 'a' - 10; else i =- 'A' - 36; seek(f, i*(sizeof utmp), 0); write(f, &utmp, (sizeof utmp)); close(f); } /* ** N.B. wtmp may be AUTOlocked */ if ((f = open("/usr/adm/wtmp", 1)) >= 0) { seek(f, 0, 2); write(f, &utmp, (sizeof utmp)); close(f); } } #ifdef LOGIN_TIME /* ** print date */ printf( ctime( ttime ) ); #endif /* ** tell if any mail is waiting */ if(newstat(".mail", &statb) >= 0 && statb.sb_size1) printf( "You have mail.\n" ); /* ** give user control of tty */ chown(ttyx, pe.pw_uid); chmod( ttyx, 0602 ); /* ** now become the user (and lose root priviledges) */ if ( llimits.l_uid ) { if ( limits( &llimits , L_SETLIM ) < 0 ) { perror( pe.pw_strings[LNAME] ); sleep( 10 ); setuid( llimits.l_uid ); /* for wtmp consistency */ exit( -1 ); } setuid( llimits.l_uid ); } for ( i=3 ; i<15 ; i++ ) close( i ); nice(0); #ifdef INITIALISE /* ** execute the initialisaion file. */ { int pid, r, ret; if(access(INITFILE,RX) == 0) { if((pid = fork()) < 0) { /* parent - error */ perror("Can't initialise"); } else if(pid == 0) { /* child */ execl("/bin/sh","sh",INITFILE,0); perror("Can't exec shell"); exit(-1); } else { /* parent */ while((r = waitx(&ret)) > 0 && r != pid); if( ret ) printf("Initialisation failed\n"); } } } #endif INITIALISE /* ** become user's shell */ if ( (np = pe.pw_strings[SHELLPATH]) == 0 || *np == '\0' ) np = "/bin/sh"; execl(np, "-", 0); printf( "No Shell! " ); perror( np ); exit( -1 ); out: brk( &end ); } #ifdef SHARELINKS #define ERROR 0XFFFFFFFFL struct { int f_ino; char f_name[14]; char f_end; } dirbuf; /* * "tdu" returns the disc usage of the current directory * and all sub-directories. * Inodes are weighted at IWEIGHT blocks. * Links are shared equally. */ long tdu( pathend, parino ) char *pathend; unsigned parino; { register fd, i, posn; long inodes, blocks, t; unsigned dino; if ( pathend == 0 ) return( ERROR ); dino = statb.sb_inumber; inodes = 0X10000; t_files =+ 0X10000; blocks.loword = 0; blocks.hiword = size(); t_blocks =+ blocks; posn = 0; dirbuf.f_end = '\0'; loop: if ( ((fd = open( pathname , 0)) >= 0) && (seek( fd , posn , 0) >= 0) ) { while ( (i = read( fd , &dirbuf , 16 )) == 16 ) { posn =+ i; if ( dirbuf.f_ino ) if ( newstat( dirbuf.f_name , &statb ) >= 0 ) { if ( (statb.sb_flags & IFTYP) == IFDIR ) { if ( statb.sb_inumber != dino && statb.sb_inumber != parino ) { if ( dots() ) return( malformed( "separate directory!" ) ); if ( posn <= 32 ) return( malformed( "\".\" or \"..\" displaced!" ) ); if ( chdir( dirbuf.f_name ) >= 0 ) { close( fd ); blocks =+ tdu( nextpath( pathend, dirbuf.f_name ), dino ); *pathend = 0; chdir( pathname ); if ( derror ) return( ERROR ); goto loop; } else return( malformed() ); } else if ( posn > 32 ) return( malformed( "link displaced" ) ); else if ( !dots() ) return( malformed( "\".\" or \"..\" renamed!" ) ); } else { /* fixed point arithmetic */ t = (0X10000 / (statb.sb_nlinks&0377)); t_files =+ t; inodes =+ t; t = ((0X10000 * size()) / (statb.sb_nlinks&0377)); t_blocks =+ t; blocks =+ t; } } else return( malformed() ); } close( fd ); if ( i ) return( malformed( "bad length" ) ); return( blocks + inodes*IWEIGHT ); } else { dirbuf.f_name[0] = 0; return( malformed() ); } } unsigned size() { register unsigned b, ib; b = ((statb.sb_size0 & 0377) << 7) + (((statb.sb_size1 + 0777) >> 9) & 0177); if ( ib = b>>3 ) { b++; if ( ib =>> 5 ) { b =+ ib; /* indirect */ if ( ib > 8 ) b++; /* double indirect */ } } return( b ); } long malformed( s ) char *s; { extern errno; putchar( '\n' ); printf( "MALFORMED DIRECTORY in %s\n\t", pathname ); if ( errno ) perror( dirbuf.f_name ); else printf( "%s: %s\n", dirbuf.f_name, s ); derror++; return( ERROR ); } dots() { register char *sp = dirbuf.f_name; if ( *sp++ == '.' && ( *sp == '\0' || ( *sp++ == '.' && *sp == '\0' ) ) ) return( 1 ); return( 0 ); } char *nextpath( at, name ) register char *at, *name; { if ( *name != '/' ) *at++ = '/'; do if ( at >= PATHEND ) { derror++; return( 0 ); } while ( *at++ = *name++ ); return( --at ); } #endif SHARELINKS #ifdef OWNER #include <ino.h> #include <filsys.h> struct def_fs { char fs_bmajor; /* major device number for block special file */ char *fs_rname; /* raw special file */ } defv[] { { '\003', "/dev/rms0" } }; #define NDEF ((sizeof defv)/(sizeof defv[0])) #define NINODES 512 /* read 4K of inodes at a time */ #define BUFSIZ (NINODES*INODEZ) #define ERROR 0177777 /* return maximum usage on error */ /* * "tdu" returns the total disc usage for "uid" on the current file system . * Inodes are weighted at IWEIGHT blocks. * Links are ignored. * Errors return maximum usage. */ unsigned tdu( uid ) unsigned uid; { register char *buf; register union { char *cp; int i; } r; register union { struct def_fs *dp; struct filsys *fp; struct inode *ip; } p; unsigned ninodes, blocks, inodes; char *sbrk(); int f; unsigned size(); if ( !uid ) return( 0 ); /* don't bother with root */ for ( p.dp = defv ; p.dp < &defv[NDEF] ; p.dp++ ) if ( p.dp->fs_bmajor == statb.sb_major ) goto found; printf( "Unknown file system! - major device = 0%o\n", statb.sb_major ); derror++; return( ERROR ); found: for ( r.cp = p.dp->fs_rname ; *r.cp++ ; ); r.cp[-2] =+ statb.sb_minor; if ( (f = open( p.dp->fs_rname , 0 )) < 0 ) { perror( p.dp->fs_rname ); derror++; return( ERROR ); } if ( (buf = p.fp = sbrk( BUFSIZ )) == -1 ) { perror( "" ); close( f ); derror++; return( ERROR ); } seek( f , 512 , 0 ); read( f , buf , 512 ); /* super block */ ninodes = p.fp->s_isize*(512/INODEZ); inodes = 0; blocks = 0; for ( r.i = 0 ; r.i < ninodes ; ) { read( f , buf , BUFSIZ ); for ( p.ip = buf ; (r.i < ninodes) && (p.ip < &buf[BUFSIZ]) ; r.i++ , p.ip++ ) if ( ((p.ip->i_uidhib<<8)|(p.ip->i_uidlob&0377)) == uid ) { inodes++; blocks =+ size( p.ip ); } } brk( buf ); close( f ); t_blocks = blocks; t_files = inodes; return( blocks + inodes*IWEIGHT ); } unsigned size( ip ) register struct inode *ip; { register unsigned b, ib; b = ((ip->i_size0 & 0377) << 7) | (((ip->i_size1 + 0777) >> 9) & 0177); if ( ib = b>>3 ) { b++; if ( ib =>> 5 ) { b =+ ib; /* indirect */ if ( ib > 8 ) b++; /* double indirect */ } } return( b ); } #endif OWNER #endif AUSAM