Subject: Parallel fsck runs conflict with each other (#302) Index: etc/fsck/{setup,main}.c 2.11BSD Description: Parallel fsck runs (filesystems with the same 'passno' value in /etc/fstab) will use the same tempfile name for their work file resulting in total chaos. Repeat-By: Have more than one entry in /etc/fstab with the same sixth field: /dev/ra1g /usr ufs rw 1 4 /dev/ra0g /u1 ufs rw 1 4 Fsck will prompt _once_ for a tmp file name but _both_ (parallel) instances of fsck will use the name. Fix: Although fsck unlinks the tmp file after creating it there is a race condition which can result in multiple fsck processes using the same intermediate file. The results are not pretty. The fix is to append ".XXXXX" to the filename provided by the user and then call the 'mkstemp(3)' routine to generate a unique temporary file. Cut where indicated, saving to a file (/tmp/302) and then: patch -p0 < /tmp/301 cd /usr/src/etc/fsck make make install make clean ===========================cut here=================== *** /usr/src/etc/fsck/setup.c.old Wed Jun 13 08:45:47 1990 --- /usr/src/etc/fsck/setup.c Sat Feb 3 21:46:25 1996 *************** *** 5,11 **** */ #if !defined(lint) && defined(DOSCCS) ! static char sccsid[] = "@(#)setup.c 5.3 (Berkeley) 5/15/86"; #endif not lint #include --- 5,11 ---- */ #if !defined(lint) && defined(DOSCCS) ! static char sccsid[] = "@(#)setup.c 5.3.1 (2.11BSD) 1996/2/3"; #endif not lint #include *************** *** 28,33 **** --- 28,34 ---- int i, j, n; long size; BUFAREA *bp; + char junk[80 + sizeof (".XXXXX") + 1]; if (stat("/", &statb) < 0) errexit("Can't stat root\n"); *************** *** 112,136 **** pfatal("\nNEED SCRATCH FILE (%ld BLKS)\n",nscrblk); do { printf("ENTER FILENAME: "); ! if((n = getline(stdin,scrfile,sizeof(scrfile))) == EOF) errexit("\n"); - if(stat(scrfile,&statb) == 0 && - (statb.st_mode & S_IFMT) != S_IFREG) - errexit("Not a good scratch filename"); } while(n == 0); } ! sfile.wfdes=open(scrfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); if ((sfile.wfdes < 0) ! || ((sfile.rfdes = open(scrfile,0)) < 0)) { ! printf("Can't create %s\n",scrfile); ckfini(); return(0); } ! unlink(scrfile); /* make it invisible incase we exit */ ! if (hotroot && (stat(scrfile,&statb)==0) && ((statb.st_mode & S_IFMT) == S_IFREG) && (statb.st_dev==rootdev)) ! pfatal("TMP FILE (%s) ON ROOT WHEN CHECKING ROOT",scrfile); bp = &((BUFAREA *)mbase)[(msize/sizeof(BUFAREA))]; poolhead = NULL; while(--bp >= (BUFAREA *)mbase) { --- 113,137 ---- pfatal("\nNEED SCRATCH FILE (%ld BLKS)\n",nscrblk); do { printf("ENTER FILENAME: "); ! if((n = getline(stdin, scrfile, ! sizeof(scrfile) - 6)) == EOF) errexit("\n"); } while(n == 0); } ! strcpy(junk, scrfile); ! strcat(junk, ".XXXXX"); ! sfile.wfdes = mkstemp(junk); if ((sfile.wfdes < 0) ! || ((sfile.rfdes = open(junk,0)) < 0)) { ! printf("Can't create %s\n", junk); ckfini(); return(0); } ! unlink(junk); /* make it invisible incase we exit */ ! if (hotroot && (fstat(sfile.wfdes,&statb)==0) && ((statb.st_mode & S_IFMT) == S_IFREG) && (statb.st_dev==rootdev)) ! pfatal("TMP FILE (%s) ON ROOT WHEN CHECKING ROOT", junk); bp = &((BUFAREA *)mbase)[(msize/sizeof(BUFAREA))]; poolhead = NULL; while(--bp >= (BUFAREA *)mbase) { *** /usr/src/etc/fsck/main.c.old Wed Jun 13 08:42:32 1990 --- /usr/src/etc/fsck/main.c Sat Feb 3 21:42:38 1996 *************** *** 9,15 **** "@(#) Copyright (c) 1980 Regents of the University of California.\n\ All rights reserved.\n"; ! static char sccsid[] = "@(#)main.c 5.4 (Berkeley) 3/5/86"; #endif not lint #include --- 9,15 ---- "@(#) Copyright (c) 1980 Regents of the University of California.\n\ All rights reserved.\n"; ! static char sccsid[] = "@(#)main.c 5.4.1 (2.11BSD) 1996/2/3"; #endif not lint #include *************** *** 114,124 **** do { anygtr = 0; if (setfsent() == 0) ! errexit("Can't open checklist file: %s\n", FSTAB); while ((fsp = getfsent()) != 0) { ! if (strcmp(fsp->fs_type, FSTAB_RW) && strcmp(fsp->fs_type, FSTAB_RO) && ! strcmp(fsp->fs_type, FSTAB_RQ)) continue; if (preen == 0 || passno == 1 && fsp->fs_passno == passno) { --- 114,126 ---- do { anygtr = 0; if (setfsent() == 0) ! errexit("Can't open %s\n", FSTAB); while ((fsp = getfsent()) != 0) { ! if (strcmp(fsp->fs_vfstype, "ufs") || ! (strcmp(fsp->fs_type, FSTAB_RW) && strcmp(fsp->fs_type, FSTAB_RO) && ! strcmp(fsp->fs_type, FSTAB_RQ)) || ! fsp->fs_passno == 0) continue; if (preen == 0 || passno == 1 && fsp->fs_passno == passno) { *** /VERSION.old Wed Feb 7 19:51:21 1996 --- /VERSION Wed Feb 7 20:16:05 1996 *************** *** 1,4 **** ! Current Patch Level: 301 2.11 BSD ============ --- 1,4 ---- ! Current Patch Level: 302 2.11 BSD ============