[BACK]Return to util.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / patch

Diff for /src/usr.bin/patch/util.c between version 1.12 and 1.13

version 1.12, 2003/07/18 02:00:09 version 1.13, 2003/07/21 14:00:41
Line 1 
Line 1 
 /*      $OpenBSD$       */  /* $OpenBSD$     */
   
 #ifndef lint  #ifndef lint
 static char rcsid[] = "$OpenBSD$";  static char     rcsid[] = "$OpenBSD$";
 #endif /* not lint */  #endif                          /* not lint */
   
 #include "EXTERN.h"  #include "EXTERN.h"
 #include "common.h"  #include "common.h"
Line 10 
Line 10 
 #include "util.h"  #include "util.h"
 #include "backupfile.h"  #include "backupfile.h"
   
 void my_exit(int) __attribute__((noreturn));  void            my_exit(int) __attribute__((noreturn));
   
 /* Rename a file, copying it if necessary. */  /* Rename a file, copying it if necessary. */
   
 int  int
 move_file(from,to)  move_file(char *from, char *to)
 char *from, *to;  
 {  {
     char bakname[MAXPATHLEN];          char    bakname[MAXPATHLEN], *s;
     char *s;          int     i, fromfd;
     int i;  
     int fromfd;  
   
     /* to stdout? */          /* to stdout? */
   
     if (strEQ(to, "-")) {          if (strEQ(to, "-")) {
 #ifdef DEBUGGING  #ifdef DEBUGGING
         if (debug & 4)                  if (debug & 4)
             say("Moving %s to stdout.\n", from);                          say("Moving %s to stdout.\n", from);
 #endif  #endif
         fromfd = open(from, O_RDONLY);                  fromfd = open(from, O_RDONLY);
         if (fromfd < 0)                  if (fromfd < 0)
             pfatal("internal error, can't reopen %s", from);                          pfatal("internal error, can't reopen %s", from);
         while ((i=read(fromfd, buf, sizeof buf)) > 0)                  while ((i = read(fromfd, buf, sizeof buf)) > 0)
             if (write(1, buf, i) != 1)                          if (write(1, buf, i) != 1)
                 pfatal("write failed");                                  pfatal("write failed");
         close(fromfd);                  close(fromfd);
         return 0;                  return 0;
     }          }
           if (origprae) {
                   if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
                       strlcat(bakname, to, sizeof(bakname)) >= sizeof(bakname))
                           fatal("filename %s too long for buffer\n", origprae);
           } else {
                   char    *backupname = find_backup_file_name(to);
                   if (backupname == (char *) 0)
                           fatal("out of memory\n");
                   if (strlcpy(bakname, backupname, sizeof(bakname)) >= sizeof(bakname))
                           fatal("filename %s too long for buffer\n", backupname);
                   free(backupname);
           }
   
     if (origprae) {          if (stat(to, &filestat) == 0) { /* output file exists */
         if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||                  dev_t   to_device = filestat.st_dev;
             strlcat(bakname, to, sizeof(bakname)) >= sizeof(bakname))                  ino_t   to_inode = filestat.st_ino;
             fatal("filename %s too long for buffer\n", origprae);                  char    *simplename = bakname;
     } else {  
 #ifndef NODIR  
         char *backupname = find_backup_file_name(to);  
         if (backupname == (char *) 0)  
             fatal("out of memory\n");  
         if (strlcpy(bakname, backupname, sizeof(bakname)) >= sizeof(bakname))  
             fatal("filename %s too long for buffer\n", backupname);  
         free(backupname);  
 #else /* NODIR */  
         if (strlcpy(bakname, to, sizeof(bakname)) >= sizeof(bakname) ||  
             strlcat(bakname, simple_backup_suffix, sizeof(bakname)) >= sizeof(bakname))  
             fatal("filename %s too long for buffer\n", to);  
 #endif /* NODIR */  
     }  
   
     if (stat(to, &filestat) == 0) {     /* output file exists */                  for (s = bakname; *s; s++) {
         dev_t to_device = filestat.st_dev;                          if (*s == '/')
         ino_t to_inode  = filestat.st_ino;                                  simplename = s + 1;
         char *simplename = bakname;                  }
   
         for (s=bakname; *s; s++) {                  /*
             if (*s == '/')                   * Find a backup name that is not the same file. Change the
                 simplename = s+1;                   * first lowercase char into uppercase; if that isn't
         }                   * sufficient, chop off the first char and try again.
         /* Find a backup name that is not the same file.                   */
            Change the first lowercase char into uppercase;                  while (stat(bakname, &filestat) == 0 &&
            if that isn't sufficient, chop off the first char and try again.  */                      to_device == filestat.st_dev && to_inode == filestat.st_ino) {
         while (stat(bakname, &filestat) == 0 &&                          /* Skip initial non-lowercase chars.  */
                 to_device == filestat.st_dev && to_inode == filestat.st_ino) {                          for (s = simplename; *s && !islower(*s); s++)
             /* Skip initial non-lowercase chars.  */                                  ;
             for (s=simplename; *s && !islower(*s); s++) ;                          if (*s)
             if (*s)                                  *s = toupper(*s);
                 *s = toupper(*s);                          else
             else                                  memmove(simplename, simplename + 1,
                 memmove(simplename, simplename+1, strlen(simplename+1)+1);                                      strlen(simplename + 1) + 1);
         }                  }
         while (unlink(bakname) >= 0) ;  /* while() is for benefit of Eunice */                  unlink(bakname);
   
 #ifdef DEBUGGING  #ifdef DEBUGGING
         if (debug & 4)                  if (debug & 4)
             say("Moving %s to %s.\n", to, bakname);                          say("Moving %s to %s.\n", to, bakname);
 #endif  #endif
         if (link(to, bakname) < 0) {                  if (link(to, bakname) < 0) {
             /* Maybe `to' is a symlink into a different file system.                          /*
                Copying replaces the symlink with a file; using rename                           * Maybe `to' is a symlink into a different file
                would be better.  */                           * system. Copying replaces the symlink with a file;
             int tofd;                           * using rename would be better.
             int bakfd;                           */
                           int     tofd, bakfd;
   
             bakfd = creat(bakname, 0666);                          bakfd = creat(bakname, 0666);
             if (bakfd < 0) {                          if (bakfd < 0) {
                 say("Can't backup %s, output is in %s: %s\n", to, from,                                  say("Can't backup %s, output is in %s: %s\n",
                      strerror(errno));                                      to, from, strerror(errno));
                 return -1;                                  return -1;
             }                          }
             tofd = open(to, O_RDONLY);                          tofd = open(to, O_RDONLY);
             if (tofd < 0)                          if (tofd < 0)
                 pfatal("internal error, can't open %s", to);                                  pfatal("internal error, can't open %s", to);
             while ((i=read(tofd, buf, sizeof buf)) > 0)                          while ((i = read(tofd, buf, sizeof buf)) > 0)
                 if (write(bakfd, buf, i) != i)                                  if (write(bakfd, buf, i) != i)
                     pfatal("write failed");                                          pfatal("write failed");
             close(tofd);                          close(tofd);
             close(bakfd);                          close(bakfd);
                   }
                   unlink(to);
         }          }
         while (unlink(to) >= 0) ;  
     }  
 #ifdef DEBUGGING  #ifdef DEBUGGING
     if (debug & 4)          if (debug & 4)
         say("Moving %s to %s.\n", from, to);                  say("Moving %s to %s.\n", from, to);
 #endif  #endif
     if (link(from, to) < 0) {           /* different file system? */          if (link(from, to) < 0) {       /* different file system? */
         int tofd;                  int     tofd;
   
         tofd = creat(to, 0666);                  tofd = creat(to, 0666);
         if (tofd < 0) {                  if (tofd < 0) {
             say("Can't create %s, output is in %s: %s\n",                          say("Can't create %s, output is in %s: %s\n",
               to, from, strerror(errno));                              to, from, strerror(errno));
             return -1;                          return -1;
                   }
                   fromfd = open(from, O_RDONLY);
                   if (fromfd < 0)
                           pfatal("internal error, can't reopen %s", from);
                   while ((i = read(fromfd, buf, sizeof buf)) > 0)
                           if (write(tofd, buf, i) != i)
                                   pfatal("write failed");
                   close(fromfd);
                   close(tofd);
         }          }
         fromfd = open(from, O_RDONLY);          unlink(from);
         if (fromfd < 0)          return 0;
             pfatal("internal error, can't reopen %s", from);  
         while ((i=read(fromfd, buf, sizeof buf)) > 0)  
             if (write(tofd, buf, i) != i)  
                 pfatal("write failed");  
         close(fromfd);  
         close(tofd);  
     }  
     unlink(from);  
     return 0;  
 }  }
   
 /* Copy a file. */  /*
    * Copy a file.
    */
 void  void
 copy_file(from,to)  copy_file(char *from, char *to)
 char *from, *to;  
 {  {
     int tofd;          int     tofd, fromfd, i;
     int fromfd;  
     int i;  
   
     tofd = creat(to, 0666);          tofd = creat(to, 0666);
     if (tofd < 0)          if (tofd < 0)
         pfatal("can't create %s", to);                  pfatal("can't create %s", to);
     fromfd = open(from, O_RDONLY);          fromfd = open(from, O_RDONLY);
     if (fromfd < 0)          if (fromfd < 0)
         pfatal("internal error, can't reopen %s", from);                  pfatal("internal error, can't reopen %s", from);
     while ((i=read(fromfd, buf, sizeof buf)) > 0)          while ((i = read(fromfd, buf, sizeof buf)) > 0)
         if (write(tofd, buf, i) != i)                  if (write(tofd, buf, i) != i)
             pfatal("write to %s failed", to);                          pfatal("write to %s failed", to);
     close(fromfd);          close(fromfd);
     close(tofd);          close(tofd);
 }  }
   
 /* Allocate a unique area for a string. */  /*
    * Allocate a unique area for a string.
    */
 char *  char *
 savestr(s)  savestr(char *s)
 char *s;  
 {  {
     char *rv;          char    *rv, *t;
     char *t;  
   
     if (!s)          if (!s)
         s = "Oops";                  s = "Oops";
     t = s;          t = s;
     while (*t++);          while (*t++)
     rv = malloc((MEM) (t - s));                  ;
     if (rv == Nullch) {          rv = malloc((MEM) (t - s));
         if (using_plan_a)          if (rv == Nullch) {
             out_of_mem = TRUE;                  if (using_plan_a)
         else                          out_of_mem = TRUE;
             fatal("out of memory\n");                  else
     }                          fatal("out of memory\n");
     else {          } else {
         t = rv;                  t = rv;
         while ((*t++ = *s++))                  while ((*t++ = *s++))
             ;                          ;
     }          }
     return rv;          return rv;
 }  }
   
 /* Vanilla terminal output (buffered). */  /*
    * Vanilla terminal output (buffered).
    */
 void  void
 say(char *fmt, ...)  say(char *fmt, ...)
 {  {
     va_list ap;          va_list ap;
   
     va_start(ap, fmt);          va_start(ap, fmt);
     vfprintf(stderr, fmt, ap);          vfprintf(stderr, fmt, ap);
     va_end(ap);          va_end(ap);
     fflush(stderr);          fflush(stderr);
 }  }
   
 /* Terminal output, pun intended. */  /*
    * Terminal output, pun intended.
    */
 void  void
 fatal(char *fmt, ...)  fatal(char *fmt, ...)
 {  {
     va_list ap;          va_list ap;
   
     va_start(ap, fmt);          va_start(ap, fmt);
     fprintf(stderr, "patch: **** ");          fprintf(stderr, "patch: **** ");
     vfprintf(stderr, fmt, ap);          vfprintf(stderr, fmt, ap);
     va_end(ap);          va_end(ap);
     my_exit(1);          my_exit(1);
 }  }
   
 /* Say something from patch, something from the system, then silence . . . */  /*
    * Say something from patch, something from the system, then silence . . .
    */
 void  void
 pfatal(char *fmt, ...)  pfatal(char *fmt, ...)
 {  {
     va_list ap;          va_list ap;
     int errnum = errno;          int     errnum = errno;
   
     fprintf(stderr, "patch: **** ");          fprintf(stderr, "patch: **** ");
     va_start(ap, fmt);          va_start(ap, fmt);
     vfprintf(stderr, fmt, ap);          vfprintf(stderr, fmt, ap);
     va_end(ap);          va_end(ap);
     fprintf(stderr, ": %s\n", strerror(errnum));          fprintf(stderr, ": %s\n", strerror(errnum));
     my_exit(1);          my_exit(1);
 }  }
   
 /* Get a response from the user, somehow or other. */  /*
    * Get a response from the user, somehow or other.
    */
 void  void
 ask(char *fmt, ...)  ask(char *fmt, ...)
 {  {
     va_list ap;          va_list ap;
     int ttyfd;          int     ttyfd, r;
     int r;          bool    tty2 = isatty(2);
     bool tty2 = isatty(2);  
   
     va_start(ap, fmt);          va_start(ap, fmt);
     vsnprintf(buf, sizeof buf, fmt, ap);          vsnprintf(buf, sizeof buf, fmt, ap);
     va_end(ap);          va_end(ap);
     fflush(stderr);          fflush(stderr);
     write(2, buf, strlen(buf));          write(2, buf, strlen(buf));
     if (tty2) {                         /* might be redirected to a file */          if (tty2) {
         r = read(2, buf, sizeof buf);                  /* might be redirected to a file */
     } else if (isatty(1)) {             /* this may be new file output */                  r = read(2, buf, sizeof buf);
         fflush(stdout);          } else if (isatty(1)) { /* this may be new file output */
         write(1, buf, strlen(buf));                  fflush(stdout);
         r = read(1, buf, sizeof buf);                  write(1, buf, strlen(buf));
     } else if ((ttyfd = open(_PATH_TTY, O_RDWR)) >= 0 && isatty(ttyfd)) {                  r = read(1, buf, sizeof buf);
         /* might be deleted or unwriteable */          } else if ((ttyfd = open(_PATH_TTY, O_RDWR)) >= 0 && isatty(ttyfd)) {
         write(ttyfd, buf, strlen(buf));                  /* might be deleted or unwriteable */
         r = read(ttyfd, buf, sizeof buf);                  write(ttyfd, buf, strlen(buf));
         close(ttyfd);                  r = read(ttyfd, buf, sizeof buf);
     } else if (isatty(0)) {             /* this is probably patch input */                  close(ttyfd);
         fflush(stdin);          } else if (isatty(0)) { /* this is probably patch input */
         write(0, buf, strlen(buf));                  fflush(stdin);
         r = read(0, buf, sizeof buf);                  write(0, buf, strlen(buf));
     } else {                            /* no terminal at all--default it */                  r = read(0, buf, sizeof buf);
         buf[0] = '\n';          } else {                /* no terminal at all--default it */
         r = 1;                  buf[0] = '\n';
     }                  r = 1;
     if (r <= 0)          }
         buf[0] = 0;          if (r <= 0)
     else                  buf[0] = 0;
         buf[r] = '\0';          else
     if (!tty2)                  buf[r] = '\0';
         say(buf);          if (!tty2)
                   say(buf);
 }  }
   
 /* How to handle certain events when not in a critical region. */  /*
    * How to handle certain events when not in a critical region.
    */
 void  void
 set_signals(reset)  set_signals(int reset)
 int reset;  
 {  {
 #ifndef lint  #ifndef lint
     static sig_t hupval, intval;          static sig_t    hupval, intval;
   
     if (!reset) {          if (!reset) {
         hupval = signal(SIGHUP, SIG_IGN);                  hupval = signal(SIGHUP, SIG_IGN);
         if (hupval != SIG_IGN)                  if (hupval != SIG_IGN)
             hupval = (sig_t)my_exit;                          hupval = (sig_t) my_exit;
         intval = signal(SIGINT, SIG_IGN);                  intval = signal(SIGINT, SIG_IGN);
         if (intval != SIG_IGN)                  if (intval != SIG_IGN)
             intval = (sig_t)my_exit;                          intval = (sig_t) my_exit;
     }          }
     signal(SIGHUP, hupval);          signal(SIGHUP, hupval);
     signal(SIGINT, intval);          signal(SIGINT, intval);
 #endif  #endif
 }  }
   
 /* How to handle certain events when in a critical region. */  /*
    * How to handle certain events when in a critical region.
    */
 void  void
 ignore_signals()  ignore_signals(void)
 {  {
 #ifndef lint  #ifndef lint
     signal(SIGHUP, SIG_IGN);          signal(SIGHUP, SIG_IGN);
     signal(SIGINT, SIG_IGN);          signal(SIGINT, SIG_IGN);
 #endif  #endif
 }  }
   
 /* Make sure we'll have the directories to create a file.  /*
    If `striplast' is TRUE, ignore the last element of `filename'.  */   * Make sure we'll have the directories to create a file. If `striplast' is
    * TRUE, ignore the last element of `filename'.
    */
   
 void  void
 makedirs(filename,striplast)  makedirs(char *filename, bool striplast)
 char *filename;  
 bool striplast;  
 {  {
     char *tmpbuf;          char    *tmpbuf;
   
     if ((tmpbuf = strdup(filename)) == NULL)          if ((tmpbuf = strdup(filename)) == NULL)
         fatal("out of memory\n");                  fatal("out of memory\n");
   
     if (striplast) {          if (striplast) {
         char *s = strrchr(tmpbuf, '/');                  char    *s = strrchr(tmpbuf, '/');
         if (s == NULL)                  if (s == NULL)
           return; /* nothing to be done */                          return; /* nothing to be done */
         *s = '\0';                  *s = '\0';
     }          }
           strlcpy(buf, "/bin/mkdir -p ", sizeof buf);
           if (strlcat(buf, tmpbuf, sizeof(buf)) >= sizeof(buf))
                   fatal("buffer too small to hold %.20s...\n", tmpbuf);
   
     strlcpy(buf, "/bin/mkdir -p ", sizeof buf);          if (system(buf))
     if (strlcat(buf, tmpbuf, sizeof(buf)) >= sizeof(buf))                  pfatal("%.40s failed", buf);
       fatal("buffer too small to hold %.20s...\n", tmpbuf);  
   
     if (system(buf))  
       pfatal("%.40s failed", buf);  
 }  }
   
 /* Make filenames more reasonable. */  /*
    * Make filenames more reasonable.
    */
 char *  char *
 fetchname(at,strip_leading,assume_exists)  fetchname(char *at, int strip_leading, int assume_exists)
 char *at;  
 int strip_leading;  
 int assume_exists;  
 {  {
     char *fullname;          char    *fullname, *name, *t, tmpbuf[200];
     char *name;          int     sleading = strip_leading;
     char *t;  
     char tmpbuf[200];  
     int sleading = strip_leading;  
   
     if (!at || *at == '\0')          if (!at || *at == '\0')
         return Nullch;                  return Nullch;
     while (isspace(*at))          while (isspace(*at))
         at++;                  at++;
 #ifdef DEBUGGING  #ifdef DEBUGGING
     if (debug & 128)          if (debug & 128)
         say("fetchname %s %d %d\n",at,strip_leading,assume_exists);                  say("fetchname %s %d %d\n", at, strip_leading, assume_exists);
 #endif  #endif
     if (strnEQ(at, "/dev/null", 9))     /* so files can be created by diffing */          if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
         return Nullch;                  /*   against /dev/null. */                  return Nullch;  /* against /dev/null. */
     name = fullname = t = savestr(at);          name = fullname = t = savestr(at);
   
     /* Strip off up to `sleading' leading slashes and null terminate.  */          /* Strip off up to `sleading' leading slashes and null terminate.  */
     for (; *t && !isspace(*t); t++)          for (; *t && !isspace(*t); t++)
         if (*t == '/')                  if (*t == '/')
             if (--sleading >= 0)                          if (--sleading >= 0)
                 name = t+1;                                  name = t + 1;
     *t = '\0';          *t = '\0';
   
     /* If no -p option was given (957 is the default value!),          /*
        we were given a relative pathname,           * If no -p option was given (957 is the default value!), we were
        and the leading directories that we just stripped off all exist,           * given a relative pathname, and the leading directories that we
        put them back on.  */           * just stripped off all exist, put them back on.
     if (strip_leading == 957 && name != fullname && *fullname != '/') {           */
         name[-1] = '\0';          if (strip_leading == 957 && name != fullname && *fullname != '/') {
         if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {                  name[-1] = '\0';
             name[-1] = '/';                  if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
             name=fullname;                          name[-1] = '/';
                           name = fullname;
                   }
         }          }
     }          name = savestr(name);
           free(fullname);
   
     name = savestr(name);          if (stat(name, &filestat) && !assume_exists) {
     free(fullname);                  char    *filebase = basename(name);
                   char    *filedir = dirname(name);
   
     if (stat(name, &filestat) && !assume_exists) {  #define try(f, a1, a2, a3) \
         char *filebase = basename(name);          (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
         char *filedir = dirname(name);  
   
 #define try(f, a1, a2, a3) (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)                  if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
         if (   try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX)                      try("%s/RCS/%s%s", filedir, filebase, "") ||
             || try("%s/RCS/%s%s", filedir, filebase,        "")                      try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
             || try(    "%s/%s%s", filedir, filebase, RCSSUFFIX)                      try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
             || try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase)                      try("%s/%s%s", filedir, SCCSPREFIX, filebase))
             || try(     "%s/%s%s", filedir, SCCSPREFIX, filebase))                          return name;
           return name;                  free(name);
         free(name);                  name = Nullch;
         name = Nullch;          }
     }          return name;
   
     return name;  
 }  }
   
 void  void
 version()  version(void)
 {  {
     fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n");          fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n");
     my_exit(0);          my_exit(0);
 }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13