From: alexlehm@iti.informatik.th-darmstadt.de (Alexander Lehmann)
Subject: bug in tmpnam fixed
Date: Thu, 20 Aug 1992 15:45:44 GMT
Organization: TH Darmstadt

I'm new monitoring this group, maybe this has been solved before:

There is a bug in the shared system library (Software Release 2.1) that
prevents the tmpnam function from working. It returns only one name for each
process.

The correct code should be as follows:

-------------------------------------------------------------------------------
#include <string.h>
#include <sys/file.h>
#include <errno.h>

#define TMPLATE "/tmp/t.XXXXXX"

static char tmpfilename[sizeof(TMPLATE)];

char *tmpnam( char *buffer )
{
  int pid=getpid();
  char *p;
  char c;

  strcpy(tmpfilename,TMPLATE);
  p=tmpfilename+sizeof(TMPLATE)-1; /* point to NUL char */
  while( *--p=='X' ) {
    *p='0'+pid%10;
    pid /= 10;
  }

  p++; /* point to 1st pid digit */

  for( c='a' ; !(access(tmpfilename,F_OK)==-1 && errno==ENOENT) ; c++ ) {
    if( c=='z' ) return NULL;
    *p=c;
  }

  return buffer ? strcpy( buffer, tmpfilename ) : tmpfilename;
}
-------------------------------------------------------------------------------

For some reason the orginal code probably used the following condition:

for( c='a' ; access(tmpfilename,F_OK)==-1 && errno!=ENOENT; c++ ) {

This condition is false if the file does exist, because access returns 0 and if
the file doesn't exist, since errno is 2.

I figured out a small fix in the libaray to change the condition to work, which
can be patched into the shared libaray using the following perl script:

-------------------------------------------------------------------------------
#! /usr/local/bin/perl

die "libsys_s.B.shlib doesn't exist\n" if( ! -r "libsys_s.B.shlib" );
open(LIB,"+>>libsys_s.B.shlib") || die "Can't access libsys_s.B.shlib\n";

seek(LIB,0x4930c,0) || die "Can't seek to patch position\n";

ord(getc(LIB))==0x78 &&
ord(getc(LIB))==0xff &&
ord(getc(LIB))==0xb8 &&
ord(getc(LIB))==0x80 &&
ord(getc(LIB))==0x67 &&
ord(getc(LIB))==0xd2 || die "File differs from original version\n";

seek(LIB,0x4930c,0) || die "Can't seek to patch position\n";

printf LIB "%c%c%c%c%c%c", 0x4a, 0x80, 0x67, 0xde, 0x60, 0xd2;

close LIB;
-------------------------------------------------------------------------------

to apply this patch, use the following procedure:

- copy libsys_s.B.shlib to some working directory
- turn the write permission on
- execute fixtmpnam.pl (it will complain, if something goes wrong)
- remove write permission again
- become root
- cp /usr/shlib/libsys_s.B.shlib to libsys_s.B.shlib.old
- turn write permission on for /usr/shlib/libsys_s.B.shlib
>>> danger here
- move (_don't copy_) libsys_s.B.shlib to /usr/shlib
>>>
- reboot the system

after that, programs using tmpnam should work correctly (e.g. cvs rdiff).

If you apply this patch, you'll have to be extremely carefull, since, if the
shared library gets broken, the computer won't start.

DON'T TRY THIS PATCH, IF YOU DON'T HAVE A 2ND DRIVE TO BOOT FROM.

I crashed my system once during this procedure and was only able to recover,
since I had a full os on my 2nd hard drive.

If you don't have a 2nd drive to boot from, you are well advised to replace the
linker library with function above. This means that you'll have to relink
programs that use tmpnam, but the procedure is less risky.
You can, of course, break the linker library with this procedure, so be just as
carefull.

O.K. I warned you, you're on your own now. Don't come back to me whining.

					bye ... Alexander Lehmann
-- 
Alexander Lehmann                      | "Wopp"
alexlehm@iti.informatik.th-darmstadt.de|         -  ( THHGTTG Pt.3 )
Newsgroups: comp.sys.next.programmer