169793Sobrien/* $FreeBSD$ */ 269793Sobrien 369793Sobrien#include <paths.h> 469793Sobrien 532672Sache#include "EXTERN.h" 632672Sache#include "common.h" 732672Sache#include "INTERN.h" 832672Sache#include "util.h" 932672Sache#include "backupfile.h" 1032672Sache 1195601Sgadvoid my_exit(int _status); /* in patch.c */ 1232672Sache 1332672Sache#ifndef HAVE_STRERROR 1432672Sachestatic char * 1532672Sacheprivate_strerror (errnum) 1632672Sache int errnum; 1732672Sache{ 1832672Sache extern char *sys_errlist[]; 1932672Sache extern int sys_nerr; 2032672Sache 2132672Sache if (errnum > 0 && errnum <= sys_nerr) 2232672Sache return sys_errlist[errnum]; 2332672Sache return "Unknown system error"; 2432672Sache} 2532672Sache#define strerror private_strerror 2632672Sache#endif /* !HAVE_STRERROR */ 2732672Sache 2897028Sgad/* 2997028Sgad * Rename a file, copying it if necessary. 3097028Sgad */ 3132672Sacheint 3295601Sgadmove_file(char *from, char *to) 3332672Sache{ 3497028Sgad char bakname[512]; 3597028Sgad Reg1 char *s; 3697028Sgad Reg2 int i; 3797028Sgad Reg3 int fromfd; 3832672Sache 3997028Sgad /* to stdout? */ 4032672Sache 4197028Sgad if (strEQ(to, "-")) { 4232672Sache#ifdef DEBUGGING 4397028Sgad if (debug & 4) 4497028Sgad say2("Moving %s to stdout.\n", from); 4532672Sache#endif 4697028Sgad fromfd = open(from, 0); 4797028Sgad if (fromfd < 0) 4897028Sgad pfatal2("internal error, can't reopen %s", from); 49191910Ssepotvin while ((i = read(fromfd, buf, buf_size)) > 0) 5097028Sgad if (write(1, buf, i) != 1) 5197028Sgad pfatal1("write failed"); 5297028Sgad Close(fromfd); 5397028Sgad return 0; 5497028Sgad } 5532672Sache 5697028Sgad if (origprae) { 5797028Sgad Strcpy(bakname, origprae); 5897028Sgad Strcat(bakname, to); 5997028Sgad } else { 6032672Sache#ifndef NODIR 6197028Sgad char *backupname = find_backup_file_name(to); 6297028Sgad if (backupname == (char *) 0) 6397028Sgad fatal1("out of memory\n"); 6497028Sgad Strcpy(bakname, backupname); 6597028Sgad free(backupname); 6632672Sache#else /* NODIR */ 6797028Sgad Strcpy(bakname, to); 6897028Sgad Strcat(bakname, simple_backup_suffix); 6932672Sache#endif /* NODIR */ 7097028Sgad } 7132672Sache 7297028Sgad if (stat(to, &filestat) == 0) { /* output file exists */ 7397028Sgad dev_t to_device = filestat.st_dev; 7497028Sgad ino_t to_inode = filestat.st_ino; 7597028Sgad char *simplename = bakname; 7632672Sache 7797028Sgad for (s = bakname; *s; s++) { 7897028Sgad if (*s == '/') 7997028Sgad simplename = s + 1; 8097028Sgad } 8197028Sgad /* 8297028Sgad * Find a backup name that is not the same file. 8397028Sgad * Change the first lowercase char into uppercase; 8497028Sgad * if that isn't sufficient, chop off the first char 8597028Sgad * and try again. 8697028Sgad */ 8797028Sgad while (stat(bakname, &filestat) == 0 && 8897028Sgad to_device == filestat.st_dev && 8997028Sgad to_inode == filestat.st_ino) { 9097028Sgad /* Skip initial non-lowercase chars. */ 9197028Sgad for (s=simplename; *s && !islower((unsigned char)*s); 9297028Sgad s++) 9397028Sgad ; 9497028Sgad if (*s) 9597028Sgad *s = toupper((unsigned char)*s); 9697028Sgad else 9797028Sgad Strcpy(simplename, simplename + 1); 9897028Sgad } 9997028Sgad while (unlink(bakname) >= 0) 10097028Sgad ; /* while() is for benefit of Eunice */ 10132672Sache#ifdef DEBUGGING 10297028Sgad if (debug & 4) 10397028Sgad say3("Moving %s to %s.\n", to, bakname); 10432672Sache#endif 10597028Sgad if (rename(to, bakname) < 0) { 10697028Sgad say4("Can't backup %s, output is in %s: %s\n", to, from, 10797028Sgad strerror(errno)); 10897028Sgad return -1; 10997028Sgad } 11097028Sgad while (unlink(to) >= 0) 11197028Sgad ; 11232672Sache } 11332672Sache#ifdef DEBUGGING 11497028Sgad if (debug & 4) 11597028Sgad say3("Moving %s to %s.\n", from, to); 11632672Sache#endif 11797028Sgad if (rename(from, to) < 0) { /* different file system? */ 11897028Sgad Reg4 int tofd; 11932672Sache 12097028Sgad tofd = creat(to, 0666); 12197028Sgad if (tofd < 0) { 12297028Sgad say4("Can't create %s, output is in %s: %s\n", 12397028Sgad to, from, strerror(errno)); 12497028Sgad return -1; 12597028Sgad } 12697028Sgad fromfd = open(from, 0); 12797028Sgad if (fromfd < 0) 12897028Sgad pfatal2("internal error, can't reopen %s", from); 129191910Ssepotvin while ((i = read(fromfd, buf, buf_size)) > 0) 13097028Sgad if (write(tofd, buf, i) != i) 13197028Sgad pfatal1("write failed"); 13297028Sgad Close(fromfd); 13397028Sgad Close(tofd); 13432672Sache } 13597028Sgad Unlink(from); 13697028Sgad return 0; 13732672Sache} 13832672Sache 13997028Sgad/* 14097028Sgad * Copy a file. 14197028Sgad */ 14232672Sachevoid 14395601Sgadcopy_file(char *from, char *to) 14432672Sache{ 14597028Sgad Reg3 int tofd; 14697028Sgad Reg2 int fromfd; 14797028Sgad Reg1 int i; 14832672Sache 14997028Sgad tofd = creat(to, 0666); 15097028Sgad if (tofd < 0) 15197028Sgad pfatal2("can't create %s", to); 15297028Sgad fromfd = open(from, 0); 15397028Sgad if (fromfd < 0) 15497028Sgad pfatal2("internal error, can't reopen %s", from); 155191910Ssepotvin while ((i = read(fromfd, buf, buf_size)) > 0) 15697028Sgad if (write(tofd, buf, i) != i) 15797028Sgad pfatal2("write to %s failed", to); 15897028Sgad Close(fromfd); 15997028Sgad Close(tofd); 16032672Sache} 16132672Sache 16297028Sgad/* 16397028Sgad * Allocate a unique area for a string. 16497028Sgad */ 16532672Sachechar * 16695601Sgadsavestr(char *s) 16732672Sache{ 16897028Sgad Reg3 char *rv; 16997028Sgad Reg2 char *t; 17032672Sache 17197028Sgad if (!s) 17297028Sgad s = "Oops"; 17397028Sgad t = s; 17497028Sgad while (*t++) 17597028Sgad ; 17697028Sgad rv = malloc((MEM) (t - s)); 17797028Sgad if (rv == Nullch) { 17897028Sgad if (using_plan_a) 17997028Sgad out_of_mem = TRUE; 18097028Sgad else 18197028Sgad fatal1("out of memory\n"); 18297028Sgad } else { 18397028Sgad t = rv; 18497028Sgad while ((*t++ = *s++)); 18597028Sgad } 18697028Sgad return rv; 18732672Sache} 18832672Sache 18932672Sache#if defined(lint) && defined(CANVARARG) 19032672Sache 19132672Sache/*VARARGS ARGSUSED*/ 19232672Sachesay(pat) char *pat; { ; } 19332672Sache/*VARARGS ARGSUSED*/ 19432672Sachefatal(pat) char *pat; { ; } 19532672Sache/*VARARGS ARGSUSED*/ 19632672Sachepfatal(pat) char *pat; { ; } 19732672Sache/*VARARGS ARGSUSED*/ 19832672Sacheask(pat) char *pat; { ; } 19932672Sache 20032672Sache#else 20132672Sache 20297028Sgad/* 20397028Sgad * Vanilla terminal output (buffered). 20497028Sgad */ 20532672Sachevoid 20632672Sachesay(pat,arg1,arg2,arg3) 20732672Sachechar *pat; 20832672Sachelong arg1,arg2,arg3; 20932672Sache{ 21097028Sgad fprintf(stderr, pat, arg1, arg2, arg3); 21197028Sgad Fflush(stderr); 21232672Sache} 21332672Sache 21497028Sgad/* 21597028Sgad * Terminal output, pun intended. 21697028Sgad */ 21732672Sachevoid /* very void */ 21832672Sachefatal(pat,arg1,arg2,arg3) 21932672Sachechar *pat; 22032672Sachelong arg1,arg2,arg3; 22132672Sache{ 22297028Sgad fprintf(stderr, "patch: **** "); 22397028Sgad fprintf(stderr, pat, arg1, arg2, arg3); 22497028Sgad my_exit(1); 22532672Sache} 22632672Sache 22797028Sgad/* 22897028Sgad * Say something from patch, something from the system, then silence... 22997028Sgad */ 23032672Sachevoid /* very void */ 23132672Sachepfatal(pat,arg1,arg2,arg3) 23232672Sachechar *pat; 23332672Sachelong arg1,arg2,arg3; 23432672Sache{ 23597028Sgad int errnum = errno; 23632672Sache 23797028Sgad fprintf(stderr, "patch: **** "); 23897028Sgad fprintf(stderr, pat, arg1, arg2, arg3); 23997028Sgad fprintf(stderr, ": %s\n", strerror(errnum)); 24097028Sgad my_exit(1); 24132672Sache} 24232672Sache 24397028Sgad/* 24497028Sgad * Get a response from the user, somehow or other. 24597028Sgad */ 24632672Sacheint 24732672Sacheask(pat,arg1,arg2,arg3) 24832672Sachechar *pat; 24932672Sachelong arg1,arg2,arg3; 25032672Sache{ 25197028Sgad int ttyfd; 25297028Sgad int r; 25397028Sgad bool tty2 = isatty(2); 25432672Sache 25597028Sgad Sprintf(buf, pat, arg1, arg2, arg3); 25697028Sgad Fflush(stderr); 25797028Sgad write(2, buf, strlen(buf)); 25897028Sgad if (tty2) { /* might be redirected to a file */ 259191910Ssepotvin r = read(2, buf, buf_size); 26097028Sgad } else if (isatty(1)) { /* this may be new file output */ 26197028Sgad Fflush(stdout); 26297028Sgad write(1, buf, strlen(buf)); 263191910Ssepotvin r = read(1, buf, buf_size); 26497028Sgad } else if ((ttyfd = open(_PATH_TTY, 2)) >= 0 && isatty(ttyfd)) { 26532672Sache /* might be deleted or unwriteable */ 26697028Sgad write(ttyfd, buf, strlen(buf)); 267191910Ssepotvin r = read(ttyfd, buf, buf_size); 26897028Sgad Close(ttyfd); 26997028Sgad } else if (isatty(0)) { /* this is probably patch input */ 27097028Sgad Fflush(stdin); 27197028Sgad write(0, buf, strlen(buf)); 272191910Ssepotvin r = read(0, buf, buf_size); 27397028Sgad } else { /* no terminal at all--default it */ 27497028Sgad buf[0] = '\n'; 27597028Sgad buf[1] = 0; 27697028Sgad say1(buf); 27797028Sgad return 0; /* signal possible error */ 27897028Sgad } 27997028Sgad if (r <= 0) 28097028Sgad buf[0] = 0; 28197028Sgad else 28297028Sgad buf[r] = '\0'; 28397028Sgad if (!tty2) 28497028Sgad say1(buf); 28532672Sache 28697028Sgad if (r <= 0) 28797028Sgad return 0; /* if there was an error, return it */ 28897028Sgad else 28997028Sgad return 1; 29032672Sache} 29132672Sache#endif /* lint */ 29232672Sache 29397028Sgad/* 29497028Sgad * How to handle certain events when not in a critical region. 29597028Sgad */ 29632672Sachevoid 29795601Sgadset_signals(int reset) 29832672Sache{ 29932672Sache#ifndef lint 30097028Sgad static RETSIGTYPE (*hupval)(),(*intval)(); 30132672Sache 30297028Sgad if (!reset) { 30397028Sgad hupval = signal(SIGHUP, SIG_IGN); 30497028Sgad if (hupval != SIG_IGN) 30597028Sgad hupval = (RETSIGTYPE(*)())my_exit; 30697028Sgad intval = signal(SIGINT, SIG_IGN); 30797028Sgad if (intval != SIG_IGN) 30897028Sgad intval = (RETSIGTYPE(*)())my_exit; 30997028Sgad } 31097028Sgad Signal(SIGHUP, hupval); 31197028Sgad Signal(SIGINT, intval); 31232672Sache#endif 31332672Sache} 31432672Sache 31597028Sgad/* 31697028Sgad * How to handle certain events when in a critical region. 31797028Sgad */ 31832672Sachevoid 31995601Sgadignore_signals(void) 32032672Sache{ 32132672Sache#ifndef lint 32297028Sgad Signal(SIGHUP, SIG_IGN); 32397028Sgad Signal(SIGINT, SIG_IGN); 32432672Sache#endif 32532672Sache} 32632672Sache 32797028Sgad/* 32897028Sgad * Make sure we'll have the directories to create a file. 32997028Sgad * If `striplast' is TRUE, ignore the last element of `filename'. 33097028Sgad */ 33132672Sachevoid 33232672Sachemakedirs(filename,striplast) 33332672SacheReg1 char *filename; 33432672Sachebool striplast; 33532672Sache{ 33697028Sgad char tmpbuf[256]; 33797028Sgad Reg2 char *s = tmpbuf; 33897028Sgad char *dirv[20]; /* Point to the NULs between elements. */ 33997028Sgad Reg3 int i; 34097028Sgad Reg4 int dirvp = 0; /* Number of finished entries in dirv. */ 34132672Sache 34297028Sgad /* 34397028Sgad * Copy `filename' into `tmpbuf' with a NUL instead of a slash 34497028Sgad * between the directories. 34597028Sgad */ 34697028Sgad while (*filename) { 34797028Sgad if (*filename == '/') { 34897028Sgad filename++; 34997028Sgad dirv[dirvp++] = s; 35097028Sgad *s++ = '\0'; 35197028Sgad } else { 35297028Sgad *s++ = *filename++; 35397028Sgad } 35432672Sache } 35597028Sgad *s = '\0'; 35697028Sgad dirv[dirvp] = s; 35797028Sgad if (striplast) 35897028Sgad dirvp--; 35997028Sgad if (dirvp < 0) 36097028Sgad return; 36132672Sache 36297028Sgad strcpy(buf, "mkdir"); 36397028Sgad s = buf; 36497028Sgad for (i = 0; i <= dirvp; i++) { 36597028Sgad struct stat sbuf; 36632672Sache 36797028Sgad if (stat(tmpbuf, &sbuf) && errno == ENOENT) { 36897028Sgad while (*s) 36997028Sgad s++; 37097028Sgad *s++ = ' '; 37197028Sgad strcpy(s, tmpbuf); 37297028Sgad } 37397028Sgad *dirv[i] = '/'; 37432672Sache } 37597028Sgad if (s != buf) 37697028Sgad system(buf); 37732672Sache} 37832672Sache 37997028Sgad/* 38097028Sgad * Make filenames more reasonable. 38197028Sgad */ 38232672Sachechar * 38395601Sgadfetchname(char *at, int strip_leading, int assume_exists) 38432672Sache{ 38597028Sgad char *fullname; 38697028Sgad char *name; 38797028Sgad Reg1 char *t; 38897028Sgad char tmpbuf[200]; 38997028Sgad int sleading = strip_leading; 39032672Sache 39197028Sgad if (!at) 39297028Sgad return Nullch; 39397028Sgad while (isspace((unsigned char)*at)) 39497028Sgad at++; 39532672Sache#ifdef DEBUGGING 39697028Sgad if (debug & 128) 39797028Sgad say4("fetchname %s %d %d\n",at,strip_leading,assume_exists); 39832672Sache#endif 39997028Sgad if (strnEQ(at, _PATH_DEVNULL, sizeof _PATH_DEVNULL - 1)) 40097028Sgad /* So files can be created by diffing against /dev/null. */ 40197028Sgad return Nullch; 40297028Sgad name = fullname = t = savestr(at); 40332672Sache 40497028Sgad /* Strip off up to `sleading' leading slashes and null terminate. */ 40597028Sgad for (; *t && !isspace((unsigned char)*t); t++) 40697028Sgad if (*t == '/') 40797028Sgad if (--sleading >= 0) 40897028Sgad name = t + 1; 40997028Sgad *t = '\0'; 41032672Sache 41197028Sgad /* 41297028Sgad * If no -p option was given (957 is the default value!), 41397028Sgad * we were given a relative pathname, 41497028Sgad * and the leading directories that we just stripped off all exist, 41597028Sgad * put them back on. 41697028Sgad */ 41797028Sgad if (strip_leading == 957 && name != fullname && *fullname != '/') { 41897028Sgad name[-1] = '\0'; 41997028Sgad if (stat(fullname, &filestat) == 0 && 42097028Sgad S_ISDIR(filestat.st_mode)) { 42197028Sgad name[-1] = '/'; 42297028Sgad name = fullname; 42397028Sgad } 42432672Sache } 42532672Sache 42697028Sgad name = savestr(name); 42797028Sgad free(fullname); 42832672Sache 42997028Sgad if (stat(name, &filestat) && !assume_exists) { 43097028Sgad char *filebase = basename(name); 43197028Sgad int pathlen = filebase - name; 43232672Sache 43397028Sgad /* Put any leading path into `tmpbuf'. */ 43497028Sgad strncpy(tmpbuf, name, pathlen); 43532672Sache 43697028Sgad#define try(f, a1, a2) \ 43797028Sgad (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0) 43897028Sgad if (try("RCS/%s%s", filebase, RCSSUFFIX) || 43997028Sgad try("RCS/%s%s", filebase, "") || 44097028Sgad try( "%s%s", filebase, RCSSUFFIX) || 44197028Sgad try("SCCS/%s%s", SCCSPREFIX, filebase) || 44297028Sgad try( "%s%s", SCCSPREFIX, filebase)) 44397028Sgad return name; 44497028Sgad free(name); 44597028Sgad name = Nullch; 44697028Sgad } 44732672Sache 44897028Sgad return name; 44932672Sache} 45032672Sache 45132672Sachechar * 45295601Sgadxmalloc(unsigned int size) 45332672Sache{ 45497028Sgad register char *p = (char *) malloc (size); 45597028Sgad if (!p) 45697028Sgad fatal("out of memory"); 45797028Sgad return p; 45832672Sache} 459