dpk@BRL-VGR.ARPA (11/14/84)
Subject: Short summary of the problem Index: <source directory>/<source file> 4.2BSD Description: Detailed description of the problem, suggestion, or complaint. Repeat-By: Procedure to repeat the problem. Fix: Description of how to fix the problem. If you don't know the fix, don't include this section or "Fix:". ---------- Remove this line and what's below it. (only for reference) ------ <source directory> ::= bin | etc | games | ideas | lib | local | man | misc | sys | ucb | usr.bin | usr.lib
dpk@BRL-VGR.ARPA (11/14/84)
Subject: netstat is grossly inefficient for stupid reason Index: ucb/netstat/inet.c 4.2BSD Fix Description: In inet.c:inetname(), netstat stupidly checks for the special case of INADDR_ANY (a non-host) only after a linear search through the entire host table. What is worse, it will search the ENTIRE table for every INADDR_ANY socket, looking for the non-existent entry. Repeat-By: Run "netstat -a" and watch how slow it is. To be more graphic, start up a bunch of processes which hang an accept() on INTERNET sockets (say 50 or 100), and make sure your host table has several hundred entries (like the ARPA host table). Your netstat -a will take FOREVER to complete. Fix: This fix is trivial and will make netstat go MUCH MUCH faster, over an order of magnitude faster on our system for a netstat -a. I have included a diff listing, although the line number will be off by a constant due to a header we stuck on the file (~8 lines). Basically, move the check for INADDR_ANY before the search through the host table which you KNOW will fail. This is a reposting since it did not make it to Berkeley or onto the Bug List from MT. XINU. This fix is EASY. diff inet.c.old inet.c 4c4 < * $Revision: 1.2 $ --- > * $Revision: 1.3 $ 6a7,9 > * Revision 1.3 84/07/04 01:09:36 dpk > * Moved check for INADDR_ANY in inetname for efficiency > * 12c15 < static char RCSid[] = "@(#)$Header: inet.c,v 1.2 84/07/04 01:07:20 dpk BRL $"; --- > static char RCSid[] = "@(#)$Header: inet.c,v 1.3 84/07/04 01:09:36 dpk BRL $"; 312a316,319 > if (in.s_addr == INADDR_ANY) { /* A quick check for the easy case */ > strcpy(line, "*"); > return (line); > } 329,331c336 < if (in.s_addr == INADDR_ANY) < strcpy(line, "*"); < else if (cp) --- > if (cp)
dpk@BRL-VGR.ARPA (11/24/84)
Subject: Tar is inefficient, ignores blocksize Index: bin/tar.c 4.2BSD 2.9BSD SysV (and others) Fix Description: While technically not a bug, one can always hope that such unnecessary inefficiency is removed from the system. A letter on the net mentioning tar's behavior of always reading or writing blocks of 512 bytes from or to files prompted me to analyze it and see just how bad it was. It was quite bad. It always reads or writes in blocks of 512. This is quite inefficient on systems with a blocksize greater than 512 bytes. What's more, it spent an inordinate amount of time in the bcopy() routine. First off, when extracting files it is totally unnecessary to bcopy() the data around, since you can immediately write it out to disk. Some further work allowed me to actually buffer the data going to disk in blocks of max(diskblocksize,tapeblocksize). For creating tar archives, some bcopy()s are unavoidable, but the number can be greatly reduced by having the writing to tape and reading from disk "get into sync" so that you begin reading and writing in tapeblocksize and avoiding all bcopy()s. I have made an analysis of the behavior before and after the improvements to tar were made and as you would expect the greatest benefit is achieved when the files involved are significantly larger than the tapeblocksize. The following figures summarize the behavior of three version of tar. Ntar is the new tar, Tar is 4.2BSD tar, and Tar5 is the System V version of Tar under the BRL/SYSV package. Create an archive of large files (1 Meg): Ntar 0.3u 1.9s Tar 1.8u 4.9s Tar5 4.7u 4.8s Create an archive of small files (1 Meg): Ntar 4.2u 6.8s Tar 4.4 9.4 Tar5 7.7 9.1 Create an archive of /bin (4.2BSD) Ntar 1.4u 2.9s Tar 2.3 5.5 Tar5 5.2 6.7 Extract an archive of Large files (created above) Ntar 0.2u 4.2s Tar 1.6 14.0 Extract an archive of small files (created above) Ntar 2.6 17.1 Tar 4.4 25.5 Tar5 7.4 29.9 This inefficency is also present in earlier TARs and is worse in most cases because the "bcopy()" routine (probably named something else or included in the {read/write}tape() routines) is not nearly as efficient as the Berkeley version. Repeat-By: Time tar for extraction and creation. The time is significant. Gprof or prof the tar program and analyze the results. You will find that it is spending a large portion of its time in bcopy() and the number of calls to the read/write system call for files on disk is also unreasonable. Fix: There were serveral basic changes: - readtape replaced with a routine readtbuf which is passed a pointer to a pointer and a maximum number of bytes to be accepted, returns a pointer to the new data, and the amount there. - small readtape() routine that emulates old behavior. - writetbuf that take a pointer to data and a count of blocks. It is smart enough to detect that the buffers contain at least tapeblock characters and issues a write without bcopying. This routine also returns the number blocks left to fill the tape block buffer. This is used to "get into sync". - dynamically allocated big buffers and assured they were page aligned. - changed the putfile and extract functions to use these changes to advantage. A "diff -e" editor script follows based on the original 4.2BSD tar and a regular diff follows that for other sites. The changes should also be almost directly applicable to other versions of TAR. ARPA sites for whom BRL has copies of your ATT source license, can obtain a copy by sending a message to "~dpk@vgr". #################################### diff -e tar.c.old tar.c 1109c while (n-- > 0) { bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); buffer += TBLOCK; if (recno >= nblock) { if (write(mt, tbuf, TBLOCK*nblock) < 0) { fprintf(stderr, "tar: tape write error\n"); done(2); } recno = 0; } } /* Tell the user how much to write to get in sync */ return (nblock - recno); . 1107c n -= nblock; buffer += (nblock * TBLOCK); . 1101,1103c /* * Special case: We have an empty tape buffer, and the * users data size is >= the tape block size: Avoid * the bcopy and dma direct to tape. BIG WIN. Add the * residual to the tape buffer. */ while (recno == 0 && n >= nblock) { if (write(mt, buffer, TBLOCK*nblock) < 0) { . 1090,1091c writetbuf(buffer, n) register char *buffer; register int n; . 1086,1087c if (size > ((nblock-recno)*TBLOCK)) size = (nblock-recno)*TBLOCK; *bufpp = (char *)&tbuf[recno]; recno += (size/TBLOCK); return (size); . 1064a char *bufp; int nread; readtbuf (&bufp, TBLOCK); bcopy(bufp, buffer, TBLOCK); return(TBLOCK); } readtbuf(bufpp, size) char **bufpp; int size; { . 1062c readtape (buffer) . 710a bytes -= nread; blocks -= (((nread-1)/TBLOCK)+1); . 703,705c } else if (write(ofile, bufp, (int) bytes) < 0) { . 694,697c for (; blocks > 0;) { register int nread; char *bufp; register int nwant; nwant = NBLOCK*TBLOCK; if (nwant > (blocks*TBLOCK)) nwant = (blocks*TBLOCK); nread = readtbuf(&bufp, nwant); if (bytes > nread) { if (write(ofile, bufp, nread) < 0) { . 609d 590a if (bigbuf != buf) #ifndef vax free(bigbuf); #else free(origbuf); #endif . 589a #endif vax while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 && blocks > 0) { register int nblks; nblks = ((i-1)/TBLOCK)+1; if (nblks > blocks) nblks = blocks; hint = writetbuf(bigbuf, nblks); blocks -= nblks; } . 586,588c if ((origbuf = malloc(maxread+pagesize)) == 0) { maxread = TBLOCK; bigbuf = buf; } else { bigbuf = (char *)(((int)origbuf+pagesize)&~(pagesize-1)); } . 584c hint = writetape((char *)&dblock); maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); #ifndef vax if ((bigbuf = malloc(maxread)) == 0) { maxread = TBLOCK; bigbuf = buf; } #else /* * The following is for 4.2BSD and related systems to force * the buffer to be page aligned. The kernel will avoid * bcopy()'s on disk IO this way by manipulating the page tables. */ { int pagesize = getpagesize(); . 534a close(infile); . 416a int maxread; int hint; /* amount to write to get "in sync" */ . 410a #ifdef vax char *origbuf; #endif char *bigbuf; . 400c readtbuf(&bufp, TBLOCK); . 391c char *bufp; . 222a #else /* * The following is for 4.2BSD and related systems to force * the buffer to be page aligned. The kernel will avoid * bcopy()'s on disk IO this way by manipulating the page tables. */ { int pagesize = getpagesize(); tbuf = (union hblock *)malloc((nblock*TBLOCK)+pagesize); tbuf = (union hblock *)(((int)tbuf+pagesize)&~(pagesize-1)); } #endif vax . 221a #ifndef vax . 21a #define writetape(b) writetbuf(b, 1) #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) . 1a static char RCSid[] = "@(#)$Header: tar.c,v 1.4 84/11/14 00:08:15 root Exp $"; #endif #ifndef lint . 0a /* * T A R . C * * $Revision: 1.4 $ * * $Log: tar.c,v $ * Revision 1.4 84/11/14 00:08:15 root * New more efficient version. Minimizes the number of bcopys * and maximizes block buffering. Page aligns block buffers. * * Revision 1.3 84/02/23 20:24:42 dpk * Added missing close(infile) to prevent running out of fd's * * Revision 1.2 84/02/23 20:17:02 dpk * Added distinctive RCS header * */ . ###################### cut here ######################### diff tar.c.old tar.c 0a1,17 > /* > * T A R . C > * > * $Revision: 1.4 $ > * > * $Log: tar.c,v $ > * Revision 1.4 84/11/14 00:08:15 root > * New more efficient version. Minimizes the number of bcopys > * and maximizes block buffering. Page aligns block buffers. > * > * Revision 1.3 84/02/23 20:24:42 dpk > * Added missing close(infile) to prevent running out of fd's > * > * Revision 1.2 84/02/23 20:17:02 dpk > * Added distinctive RCS header > * > */ 1a19,22 > static char RCSid[] = "@(#)$Header: tar.c,v 1.4 84/11/14 00:08:15 root Exp $"; > #endif > > #ifndef lint 21a43,46 > #define writetape(b) writetbuf(b, 1) > #define min(a,b) ((a) < (b) ? (a) : (b)) > #define max(a,b) ((a) > (b) ? (a) : (b)) > 221a247 > #ifndef vax 222a249,261 > #else > /* > * The following is for 4.2BSD and related systems to force > * the buffer to be page aligned. The kernel will avoid > * bcopy()'s on disk IO this way by manipulating the page tables. > */ > { > int pagesize = getpagesize(); > > tbuf = (union hblock *)malloc((nblock*TBLOCK)+pagesize); > tbuf = (union hblock *)(((int)tbuf+pagesize)&~(pagesize-1)); > } > #endif vax 391c430 < char buf[TBLOCK]; --- > char *bufp; 400c439 < readtape(buf); --- > readtbuf(&bufp, TBLOCK); 410a450,453 > #ifdef vax > char *origbuf; > #endif > char *bigbuf; 416a460,461 > int maxread; > int hint; /* amount to write to get "in sync" */ 534a580 > close(infile); 584c630,644 < writetape((char *)&dblock); --- > hint = writetape((char *)&dblock); > maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); > #ifndef vax > if ((bigbuf = malloc(maxread)) == 0) { > maxread = TBLOCK; > bigbuf = buf; > } > #else > /* > * The following is for 4.2BSD and related systems to force > * the buffer to be page aligned. The kernel will avoid > * bcopy()'s on disk IO this way by manipulating the page tables. > */ > { > int pagesize = getpagesize(); 586,588c646,651 < while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { < writetape(buf); < blocks--; --- > if ((origbuf = malloc(maxread+pagesize)) == 0) { > maxread = TBLOCK; > bigbuf = buf; > } else { > bigbuf = (char *)(((int)origbuf+pagesize)&~(pagesize-1)); > } 589a653,664 > #endif vax > > while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 > && blocks > 0) { > register int nblks; > > nblks = ((i-1)/TBLOCK)+1; > if (nblks > blocks) > nblks = blocks; > hint = writetbuf(bigbuf, nblks); > blocks -= nblks; > } 590a666,671 > if (bigbuf != buf) > #ifndef vax > free(bigbuf); > #else > free(origbuf); > #endif 609d689 < char buf[TBLOCK]; 694,697c774,784 < for (; blocks-- > 0; bytes -= TBLOCK) { < readtape(buf); < if (bytes > TBLOCK) { < if (write(ofile, buf, TBLOCK) < 0) { --- > for (; blocks > 0;) { > register int nread; > char *bufp; > register int nwant; > > nwant = NBLOCK*TBLOCK; > if (nwant > (blocks*TBLOCK)) > nwant = (blocks*TBLOCK); > nread = readtbuf(&bufp, nwant); > if (bytes > nread) { > if (write(ofile, bufp, nread) < 0) { 703,705c790 < continue; < } < if (write(ofile, buf, (int) bytes) < 0) { --- > } else if (write(ofile, bufp, (int) bytes) < 0) { 710a796,797 > bytes -= nread; > blocks -= (((nread-1)/TBLOCK)+1); 1062c1149 < readtape(buffer) --- > readtape (buffer) 1064a1152,1163 > char *bufp; > int nread; > > readtbuf (&bufp, TBLOCK); > bcopy(bufp, buffer, TBLOCK); > return(TBLOCK); > } > > readtbuf(bufpp, size) > char **bufpp; > int size; > { 1086,1087c1185,1189 < bcopy((char *)&tbuf[recno++], buffer, TBLOCK); < return (TBLOCK); --- > if (size > ((nblock-recno)*TBLOCK)) > size = (nblock-recno)*TBLOCK; > *bufpp = (char *)&tbuf[recno]; > recno += (size/TBLOCK); > return (size); 1090,1091c1192,1194 < writetape(buffer) < char *buffer; --- > writetbuf(buffer, n) > register char *buffer; > register int n; 1101,1103c1204,1212 < bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); < if (recno >= nblock) { < if (write(mt, tbuf, TBLOCK*nblock) < 0) { --- > > /* > * Special case: We have an empty tape buffer, and the > * users data size is >= the tape block size: Avoid > * the bcopy and dma direct to tape. BIG WIN. Add the > * residual to the tape buffer. > */ > while (recno == 0 && n >= nblock) { > if (write(mt, buffer, TBLOCK*nblock) < 0) { 1107c1216,1217 < recno = 0; --- > n -= nblock; > buffer += (nblock * TBLOCK); 1109c1219,1233 < return (TBLOCK); --- > > while (n-- > 0) { > bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); > buffer += TBLOCK; > if (recno >= nblock) { > if (write(mt, tbuf, TBLOCK*nblock) < 0) { > fprintf(stderr, "tar: tape write error\n"); > done(2); > } > recno = 0; > } > } > > /* Tell the user how much to write to get in sync */ > return (nblock - recno); ################### End of Bug Report ####################
brad@bradley.UUCP (11/30/84)
Also watch out for tar in doing updates. My system is 2.9 11/44 and if I run 'tar cv files' then later run 'tar uv morefiles' tar writes in blocksize of 20(default). Well on my tape drive, you can only update tar tapes that use /dev/mt0 and are blocked at 512. tar uses /dev/rmt0 default with 20. The result is that the 'tar uv' is stuck out on the end with an EOF bewtween the files. And sometimes you can not read the second file becuse (at least on my machine) the EOF seems to be 512 bytes, and the tar gets directory checksum error. You have to fudge to get the second file. I haven't yet fixed it (I think it is a bug), but will shortly. Am I the only one with a tape drive that can't update large block tar files? Tape drive is a Cipher 900X. Bradley Smith UUCP: {cepu,ihnp4,noao,uiucdcs}!bradley!brad Text Processing ARPA: cepu!bradley!brad@UCLA-LOCUS Bradley University PH: (309) 676-7611 Ext. 446 Peoria, IL 61625
dpk@BRL-VGR.ARPA (03/08/85)
Subject: RSH can hang in rcmd() Index: ucb/rsh.c 4.2BSD Fix lib/libc/net/rcmd.c 4.2BSD Fix Description: Rsh can hang indefinitly in rcmd for two reasons: 1. The accept for the second TCP connection can fail to complete do to remote failure, 2. If the remote end fails at the right time, the local end will never discover the failure if it has no data to send (which results in the send side being shutdown). Repeat-By: 1. Wait for rsh to connect to the remote end and send the name of the local reserved socket, and then have the daemon exit. The rcmd() subroutine will have gone into an accept waiting for the remote side to issue a connect() which it never will. 2. Difficult, but happened regularly with our rsh'ing of batch and unbatch for news. Create an rsh connection where the local end only reads from the connection. Kill the remote side. The rsh will not discover the fact. The "right time" is when the local side has acked all the data received so far, and has yet to receive more. In this state he is content forever unless he is doing keepalives. Fix: 1. Add a sanity time in the startup code of rsh to about the program with an error indication if the rcmd function takes too long. While I was modifing rsh.c, I removed an extraneous external definition for "error()" which does not exist. 2. In the rcmd() function, set keepalive on both of the sockets to the remote host to allow detection of a downed host. --------------------------------------------- Context diffs follow for ucb/rsh.c and lib/libc/net/rcmd.c RCS file: RCS/rsh.c,v retrieving revision 1.2 diff -c -r1.2 rsh.c *** /tmp/,RCSt1010538 Thu Mar 7 15:54:48 1985 --- rsh.c Thu Mar 7 15:44:14 1985 *************** *** 19,25 * rsh - remote shell */ /* VARARGS */ - int error(); char *index(), *rindex(), *malloc(), *getpass(), *sprintf(), *strcpy(); struct passwd *getpwuid(); --- 19,24 ----- * rsh - remote shell */ /* VARARGS */ char *index(), *rindex(), *malloc(), *getpass(), *sprintf(), *strcpy(); struct passwd *getpwuid(); *************** *** 28,33 int options; int rfd2; int sendsig(); #define mask(s) (1 << ((s) - 1)) --- 27,33 ----- int options; int rfd2; int sendsig(); + int timeout(); #define mask(s) (1 << ((s) - 1)) *************** *** 115,120 fprintf(stderr, "rsh: shell/tcp: unknown service\n"); exit(1); } rem = rcmd(&host, sp->s_port, pwd->pw_name, user ? user : pwd->pw_name, args, &rfd2); if (rem < 0) --- 115,122 ----- fprintf(stderr, "rsh: shell/tcp: unknown service\n"); exit(1); } + signal (SIGALRM, timeout); + alarm(120); /* Sanity timer */ rem = rcmd(&host, sp->s_port, pwd->pw_name, user ? user : pwd->pw_name, args, &rfd2); alarm(0); *************** *** 117,122 } rem = rcmd(&host, sp->s_port, pwd->pw_name, user ? user : pwd->pw_name, args, &rfd2); if (rem < 0) exit(1); if (rfd2 < 0) { --- 119,125 ----- alarm(120); /* Sanity timer */ rem = rcmd(&host, sp->s_port, pwd->pw_name, user ? user : pwd->pw_name, args, &rfd2); + alarm(0); if (rem < 0) exit(1); if (rfd2 < 0) { *************** *** 218,221 { (void) write(rfd2, (char *)&signo, 1); } --- 221,230 ----- { (void) write(rfd2, (char *)&signo, 1); + } + + timeout() + { + fputs("rsh: rcmd: timeout\n", stderr); + exit(14); } ------------------------------------------------------------------- RCS file: RCS/rcmd.c,v retrieving revision 1.1 diff -c -r1.1 rcmd.c *** /tmp/,RCSt1010907 Thu Mar 7 16:14:34 1985 --- rcmd.c Fri Mar 1 01:00:01 1985 *************** *** 25,30 char c; int lport = IPPORT_RESERVED - 1; struct hostent *hp; hp = gethostbyname(*ahost); if (hp == 0) { --- 25,31 ----- char c; int lport = IPPORT_RESERVED - 1; struct hostent *hp; + int on = 1; hp = gethostbyname(*ahost); if (hp == 0) { *************** *** 54,59 perror(hp->h_name); return (-1); } lport--; if (fd2p == 0) { write(s, "", 1); --- 54,62 ----- perror(hp->h_name); return (-1); } + if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof on) < 0) + perror("setsockopt (SO_KEEPALIVE)"); + lport--; if (fd2p == 0) { write(s, "", 1); *************** *** 82,87 goto bad; } } *fd2p = s3; from.sin_port = ntohs((u_short)from.sin_port); if (from.sin_family != AF_INET || --- 82,89 ----- lport = 0; goto bad; } + if (setsockopt(s3, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof on) < 0) + perror("setsockopt (SO_KEEPALIVE)"); *fd2p = s3; from.sin_port = ntohs((u_short)from.sin_port); if (from.sin_family != AF_INET ||
ron@BRL.ARPA (09/27/85)
Subject: Short summary of the problem Index: games/scene 4.3BSD Description: Gibert and Sullivan quote attributed to wrong work. Repeat-By: Run fortune until you see this: I'm very good at integral and differential calculus, I know the scientific names of beings animalculous; In short, in matters vegetable, animal, and mineral, I am the very model of a modern Major-General. -- Gilbert & Sullivan, "H.M.S. Pinafore" Fix: Change the last line to read: -- Gilbert & Sullivan, "The Pirates of Penzance"
ron@BRL.ARPA (10/14/86)
Subject: Short summary of the problem Index: lib/libc/gen/getusershell.c 4.3BSD Description: Setusershell and endusershell are ineffective and sometimes dump core. Repeat-By: Do a few getusershell calls with an interspersed setusershell and/or endusershell. Fix: The problem is that getusershell.c is horrible. Endusershell may free things that have not been malloced. There are two separate instances of the shells pointer one local to getusershell. Setusershell sets a different one than the one getusershell uses. A fixed up version follows: /* * Copyright (c) 1985 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getusershell.c 5.2 (Berkeley) 3/9/86"; #endif LIBC_SCCS and not lint #include <sys/param.h> #include <sys/file.h> #include <sys/stat.h> #include <ctype.h> #include <stdio.h> #define SHELLS "/etc/shells" /* * Do not add local shells here. They should be added in /etc/shells */ static char *okshells[] = { "/bin/sh", "/bin/csh", 0 }; static int inprogress; static char **shells, *strings; extern char **initshells(); /* * Get a list of shells from SHELLS, if it exists. */ char * getusershell() { char *ret; static char **shp; if (!inprogress) shp = initshells(); ret = *shp; if (*shp != NULL) shp++; return (ret); } endusershell() { if (shells != NULL) free((char *)shells); shells = NULL; if (strings != NULL) free(strings); strings = NULL; inprogress = 0; } setusershell() { endusershell(); } static char ** initshells() { register char **sp, *cp; register FILE *fp; struct stat statb; extern char *malloc(), *calloc(); inprogress = 1; if (shells != NULL) free((char *)shells); shells = NULL; if (strings != NULL) free(strings); strings = NULL; if ((fp = fopen(SHELLS, "r")) == (FILE *)0) return(okshells); if (fstat(fileno(fp), &statb) == -1) { (void)fclose(fp); return(okshells); } if ((strings = malloc((unsigned)statb.st_size)) == NULL) { (void)fclose(fp); return(okshells); } shells = (char **)calloc((unsigned)statb.st_size / 3, sizeof (char *)); if (shells == NULL) { (void)fclose(fp); free(strings); strings = NULL; return(okshells); } sp = shells; cp = strings; while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { while (!isspace(*cp) != '/' && *cp != '\0') cp++; if (*cp == '#' || *cp == '\0') continue; *sp++ = cp; while (!isspace(*cp) && *cp != '#' && *cp != '\0') cp++; *cp++ = '\0'; } *sp = (char *)0; (void)fclose(fp); return (shells); }
ron@BRL.ARPA (10/14/86)
Subject: chsh won't change shell back
Index: bin/passwd.c 4.3BSD
Description:
Chsh won't change shell to one that is earlier in /etc/shells
file than the one you are using.
Repeat-By:
Chsh to the a later shell in the file (say tcsh) and then
try to switch back to csh.
Fix:
Chsh verifies that the shell you are switching from is in
/etc/shells by calling getusershell until it matches. It
then verifies the new shell by calling getusershell, but it
does not rewind the file by calling set/endusershell.
Add endusershell call prior to the second lookup
/*
* Allow user to give shell name w/o preceding pathname.
*/
if (u == 0) {
valid = newshell;
} else {
!!! endusershell();
for (valid = getusershell(); valid; valid = getusershell()) {
ron@BRL.ARPA (10/14/86)
Subject: FTP daemon doesn't like Bourne shell users
Index: etc/ftpd/ftpd.c 4.3BSD
Description:
The FTP daemon denies access to users who have the default
login shell (/bin/sh).
Repeat-By:
chsh to /bin/sh and then try to FTP to your account.
Fix:
Ftpd attempts to verify the user's shell against those in
/etc/shells to prevent accounts like finger from being FTP
targets. However, getpwent returns a string with a null
in it if the shell field is blank and Ftpd tries to compare
this against /bin/sh and misses.
This fix avoids the check if the user is using the default system
shell. Add the if statement around the getusershell lookup.
if(*pw->pw_shell != 0) {
while ((cp = getusershell()) != NULL)
if (strcmp(cp, pw->pw_shell) == 0)
break;
endusershell();
if (cp == NULL)
return (0);
}
ron@BRL.ARPA (10/14/86)
Subject: Warning to those who would change proc.h Index: sys/h/proc.h 4.3BSD Description: Changing the length of the proc structure so that it is not double word aligned anymore will cause the system to crash in bizarre ways. Repeat-By: Add a word to the proc structure and then put a load on the system. Soon things like ps will stop working and then the whole machine will experience a strange trap. Fix: 1. Don't change the proc structure. 2. If you do, pad it out to the next double word.
ron@BRL.ARPA (10/14/86)
Subject: Unable to set vv address on subnet
Index: sys/vaxif/if_vv.c 4.3BSD
Description:
Ifconfig returns an error when you try to set the address on
the proteon when using subneting.
Repeat-By:
ifconfig vv0 128.63.4.3 netmask 255.255.255.0
Fix:
The vv driver checks to see if the local net part of
address corresponds to the hardware address of the interface
installed in your system. The subnet mask can not be set
before the address because the mask has to be tied to a
particular internet address.
The fix is to make the vv driver mask off all but the lowest
eight bits of the address before making the validity check.
This is OK since the device can only deal with eight local
address bits. In vvioctl:
/*
* Attempt to check agreement of protocol address
* and board address.
*/
switch (ifa->ifa_addr.sa_family) {
case AF_INET:
if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xFF) !=
vv_softc[ifp->if_unit].vs_host)
error = EADDRNOTAVAIL;
break;
}
break;
ron@BRL.ARPA (10/23/86)
Subject: RCP clobbers files. Index: bin/rcp.c 4.3BSD Description: Rcp will silently make a file zero lenght if it is specified as both the source and destination of a copy. It is difficult to predict when this will happen as there is no sure way to verify that two CPU's are in fact using the same filesystem. In addiiton, when rcp is called with one argument it just silently exit without saying anything. Repeat-By: 1. create a file with non-zero lenght called foo on machine host issue command on host: rcp host:foo foo the file will now be zero length. 2. type "rcp foo" Fix: Make rcp non-destructive in it's copies. Rather than doing an initial creat, just open the file. Then copy all the blocks. When the files are the same, each block will be read and written back into the same place it was read. Then do an ftruncate to fix up the file length. Add usage message when too few arguments. *** 118,123 **** --- 114,125 ---- } } rem = -1; + + if(argc <= 1){ + fprintf(stderr,"Usage: rcp [-p] f1 f2; or: rcp [-rp] f1...fn d2\n"); + exit(1); + } + if (argc > 2) targetshouldbedirectory = 1; (void) sprintf(cmd, "rcp%s%s%s", *************** *** 605,611 **** } continue; } ! if ((of = creat(nambuf, mode)) < 0) { bad: error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); continue; --- 607,613 ---- } continue; } ! if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) { bad: error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); continue; *************** *** 649,654 **** --- 651,657 ---- if (count != 0 && wrerr == 0 && write(of, bp->buf, count) != count) wrerr++; + ftruncate(of, size); (void) close(of); (void) response(); if (setimes) {