1 #ifndef lint 2 static char rcsid[] = "$Id: util.c,v 1.2 1993/08/02 17:55:23 mycroft Exp $"; 3 #endif /* not lint */ 4 5 #include "EXTERN.h" 6 #include "common.h" 7 #include "INTERN.h" 8 #include "util.h" 9 #include "backupfile.h" 10 11 void my_exit(); 12 13 static char * 14 private_strerror (errnum) 15 int errnum; 16 { 17 extern char *sys_errlist[]; 18 extern int sys_nerr; 19 20 if (errnum > 0 && errnum <= sys_nerr) 21 return sys_errlist[errnum]; 22 return "Unknown system error"; 23 } 24 #define strerror private_strerror 25 26 /* Rename a file, copying it if necessary. */ 27 28 int 29 move_file(from,to) 30 char *from, *to; 31 { 32 char bakname[512]; 33 Reg1 char *s; 34 Reg2 int i; 35 Reg3 int fromfd; 36 37 /* to stdout? */ 38 39 if (strEQ(to, "-")) { 40 #ifdef DEBUGGING 41 if (debug & 4) 42 say2("Moving %s to stdout.\n", from); 43 #endif 44 fromfd = open(from, 0); 45 if (fromfd < 0) 46 pfatal2("internal error, can't reopen %s", from); 47 while ((i=read(fromfd, buf, sizeof buf)) > 0) 48 if (write(1, buf, i) != 1) 49 pfatal1("write failed"); 50 Close(fromfd); 51 return 0; 52 } 53 54 if (origprae) { 55 Strcpy(bakname, origprae); 56 Strcat(bakname, to); 57 } else { 58 #ifndef NODIR 59 char *backupname = find_backup_file_name(to); 60 if (backupname == (char *) 0) 61 fatal1("out of memory\n"); 62 Strcpy(bakname, backupname); 63 free(backupname); 64 #else /* NODIR */ 65 Strcpy(bakname, to); 66 Strcat(bakname, simple_backup_suffix); 67 #endif /* NODIR */ 68 } 69 70 if (stat(to, &filestat) == 0) { /* output file exists */ 71 dev_t to_device = filestat.st_dev; 72 ino_t to_inode = filestat.st_ino; 73 char *simplename = bakname; 74 75 for (s=bakname; *s; s++) { 76 if (*s == '/') 77 simplename = s+1; 78 } 79 /* Find a backup name that is not the same file. 80 Change the first lowercase char into uppercase; 81 if that isn't sufficient, chop off the first char and try again. */ 82 while (stat(bakname, &filestat) == 0 && 83 to_device == filestat.st_dev && to_inode == filestat.st_ino) { 84 /* Skip initial non-lowercase chars. */ 85 for (s=simplename; *s && !islower(*s); s++) ; 86 if (*s) 87 *s = toupper(*s); 88 else 89 Strcpy(simplename, simplename+1); 90 } 91 while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ 92 #ifdef DEBUGGING 93 if (debug & 4) 94 say3("Moving %s to %s.\n", to, bakname); 95 #endif 96 if (link(to, bakname) < 0) { 97 /* Maybe `to' is a symlink into a different file system. 98 Copying replaces the symlink with a file; using rename 99 would be better. */ 100 Reg4 int tofd; 101 Reg5 int bakfd; 102 103 bakfd = creat(bakname, 0666); 104 if (bakfd < 0) { 105 say4("Can't backup %s, output is in %s: %s\n", to, from, 106 strerror(errno)); 107 return -1; 108 } 109 tofd = open(to, 0); 110 if (tofd < 0) 111 pfatal2("internal error, can't open %s", to); 112 while ((i=read(tofd, buf, sizeof buf)) > 0) 113 if (write(bakfd, buf, i) != i) 114 pfatal1("write failed"); 115 Close(tofd); 116 Close(bakfd); 117 } 118 while (unlink(to) >= 0) ; 119 } 120 #ifdef DEBUGGING 121 if (debug & 4) 122 say3("Moving %s to %s.\n", from, to); 123 #endif 124 if (link(from, to) < 0) { /* different file system? */ 125 Reg4 int tofd; 126 127 tofd = creat(to, 0666); 128 if (tofd < 0) { 129 say4("Can't create %s, output is in %s: %s\n", 130 to, from, strerror(errno)); 131 return -1; 132 } 133 fromfd = open(from, 0); 134 if (fromfd < 0) 135 pfatal2("internal error, can't reopen %s", from); 136 while ((i=read(fromfd, buf, sizeof buf)) > 0) 137 if (write(tofd, buf, i) != i) 138 pfatal1("write failed"); 139 Close(fromfd); 140 Close(tofd); 141 } 142 Unlink(from); 143 return 0; 144 } 145 146 /* Copy a file. */ 147 148 void 149 copy_file(from,to) 150 char *from, *to; 151 { 152 Reg3 int tofd; 153 Reg2 int fromfd; 154 Reg1 int i; 155 156 tofd = creat(to, 0666); 157 if (tofd < 0) 158 pfatal2("can't create %s", to); 159 fromfd = open(from, 0); 160 if (fromfd < 0) 161 pfatal2("internal error, can't reopen %s", from); 162 while ((i=read(fromfd, buf, sizeof buf)) > 0) 163 if (write(tofd, buf, i) != i) 164 pfatal2("write to %s failed", to); 165 Close(fromfd); 166 Close(tofd); 167 } 168 169 /* Allocate a unique area for a string. */ 170 171 char * 172 savestr(s) 173 Reg1 char *s; 174 { 175 Reg3 char *rv; 176 Reg2 char *t; 177 178 if (!s) 179 s = "Oops"; 180 t = s; 181 while (*t++); 182 rv = malloc((MEM) (t - s)); 183 if (rv == Nullch) { 184 if (using_plan_a) 185 out_of_mem = TRUE; 186 else 187 fatal1("out of memory\n"); 188 } 189 else { 190 t = rv; 191 while (*t++ = *s++); 192 } 193 return rv; 194 } 195 196 #if defined(lint) && defined(CANVARARG) 197 198 /*VARARGS ARGSUSED*/ 199 say(pat) char *pat; { ; } 200 /*VARARGS ARGSUSED*/ 201 fatal(pat) char *pat; { ; } 202 /*VARARGS ARGSUSED*/ 203 pfatal(pat) char *pat; { ; } 204 /*VARARGS ARGSUSED*/ 205 ask(pat) char *pat; { ; } 206 207 #else 208 209 /* Vanilla terminal output (buffered). */ 210 211 void 212 say(pat,arg1,arg2,arg3) 213 char *pat; 214 long arg1,arg2,arg3; 215 { 216 fprintf(stderr, pat, arg1, arg2, arg3); 217 Fflush(stderr); 218 } 219 220 /* Terminal output, pun intended. */ 221 222 void /* very void */ 223 fatal(pat,arg1,arg2,arg3) 224 char *pat; 225 long arg1,arg2,arg3; 226 { 227 fprintf(stderr, "patch: **** "); 228 fprintf(stderr, pat, arg1, arg2, arg3); 229 my_exit(1); 230 } 231 232 /* Say something from patch, something from the system, then silence . . . */ 233 234 void /* very void */ 235 pfatal(pat,arg1,arg2,arg3) 236 char *pat; 237 long arg1,arg2,arg3; 238 { 239 int errnum = errno; 240 241 fprintf(stderr, "patch: **** "); 242 fprintf(stderr, pat, arg1, arg2, arg3); 243 fprintf(stderr, ": %s\n", strerror(errnum)); 244 my_exit(1); 245 } 246 247 /* Get a response from the user, somehow or other. */ 248 249 void 250 ask(pat,arg1,arg2,arg3) 251 char *pat; 252 long arg1,arg2,arg3; 253 { 254 int ttyfd; 255 int r; 256 bool tty2 = isatty(2); 257 258 Sprintf(buf, pat, arg1, arg2, arg3); 259 Fflush(stderr); 260 write(2, buf, strlen(buf)); 261 if (tty2) { /* might be redirected to a file */ 262 r = read(2, buf, sizeof buf); 263 } 264 else if (isatty(1)) { /* this may be new file output */ 265 Fflush(stdout); 266 write(1, buf, strlen(buf)); 267 r = read(1, buf, sizeof buf); 268 } 269 else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) { 270 /* might be deleted or unwriteable */ 271 write(ttyfd, buf, strlen(buf)); 272 r = read(ttyfd, buf, sizeof buf); 273 Close(ttyfd); 274 } 275 else if (isatty(0)) { /* this is probably patch input */ 276 Fflush(stdin); 277 write(0, buf, strlen(buf)); 278 r = read(0, buf, sizeof buf); 279 } 280 else { /* no terminal at all--default it */ 281 buf[0] = '\n'; 282 r = 1; 283 } 284 if (r <= 0) 285 buf[0] = 0; 286 else 287 buf[r] = '\0'; 288 if (!tty2) 289 say1(buf); 290 } 291 #endif /* lint */ 292 293 /* How to handle certain events when not in a critical region. */ 294 295 void 296 set_signals(reset) 297 int reset; 298 { 299 #ifndef lint 300 #ifdef VOIDSIG 301 static void (*hupval)(),(*intval)(); 302 #else 303 static int (*hupval)(),(*intval)(); 304 #endif 305 306 if (!reset) { 307 hupval = signal(SIGHUP, SIG_IGN); 308 if (hupval != SIG_IGN) 309 #ifdef VOIDSIG 310 hupval = my_exit; 311 #else 312 hupval = (int(*)())my_exit; 313 #endif 314 intval = signal(SIGINT, SIG_IGN); 315 if (intval != SIG_IGN) 316 #ifdef VOIDSIG 317 intval = my_exit; 318 #else 319 intval = (int(*)())my_exit; 320 #endif 321 } 322 Signal(SIGHUP, hupval); 323 Signal(SIGINT, intval); 324 #endif 325 } 326 327 /* How to handle certain events when in a critical region. */ 328 329 void 330 ignore_signals() 331 { 332 #ifndef lint 333 Signal(SIGHUP, SIG_IGN); 334 Signal(SIGINT, SIG_IGN); 335 #endif 336 } 337 338 /* Make sure we'll have the directories to create a file. 339 If `striplast' is TRUE, ignore the last element of `filename'. */ 340 341 void 342 makedirs(filename,striplast) 343 Reg1 char *filename; 344 bool striplast; 345 { 346 char tmpbuf[256]; 347 Reg2 char *s = tmpbuf; 348 char *dirv[20]; /* Point to the NULs between elements. */ 349 Reg3 int i; 350 Reg4 int dirvp = 0; /* Number of finished entries in dirv. */ 351 352 /* Copy `filename' into `tmpbuf' with a NUL instead of a slash 353 between the directories. */ 354 while (*filename) { 355 if (*filename == '/') { 356 filename++; 357 dirv[dirvp++] = s; 358 *s++ = '\0'; 359 } 360 else { 361 *s++ = *filename++; 362 } 363 } 364 *s = '\0'; 365 dirv[dirvp] = s; 366 if (striplast) 367 dirvp--; 368 if (dirvp < 0) 369 return; 370 371 strcpy(buf, "mkdir"); 372 s = buf; 373 for (i=0; i<=dirvp; i++) { 374 struct stat sbuf; 375 376 if (stat(tmpbuf, &sbuf) && errno == ENOENT) { 377 while (*s) s++; 378 *s++ = ' '; 379 strcpy(s, tmpbuf); 380 } 381 *dirv[i] = '/'; 382 } 383 if (s != buf) 384 system(buf); 385 } 386 387 /* Make filenames more reasonable. */ 388 389 char * 390 fetchname(at,strip_leading,assume_exists) 391 char *at; 392 int strip_leading; 393 int assume_exists; 394 { 395 char *fullname; 396 char *name; 397 Reg1 char *t; 398 char tmpbuf[200]; 399 int sleading = strip_leading; 400 401 if (!at) 402 return Nullch; 403 while (isspace(*at)) 404 at++; 405 #ifdef DEBUGGING 406 if (debug & 128) 407 say4("fetchname %s %d %d\n",at,strip_leading,assume_exists); 408 #endif 409 if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */ 410 return Nullch; /* against /dev/null. */ 411 name = fullname = t = savestr(at); 412 413 /* Strip off up to `sleading' leading slashes and null terminate. */ 414 for (; *t && !isspace(*t); t++) 415 if (*t == '/') 416 if (--sleading >= 0) 417 name = t+1; 418 *t = '\0'; 419 420 /* If no -p option was given (957 is the default value!), 421 we were given a relative pathname, 422 and the leading directories that we just stripped off all exist, 423 put them back on. */ 424 if (strip_leading == 957 && name != fullname && *fullname != '/') { 425 name[-1] = '\0'; 426 if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) { 427 name[-1] = '/'; 428 name=fullname; 429 } 430 } 431 432 name = savestr(name); 433 free(fullname); 434 435 if (stat(name, &filestat) && !assume_exists) { 436 char *filebase = basename(name); 437 int pathlen = filebase - name; 438 439 /* Put any leading path into `tmpbuf'. */ 440 strncpy(tmpbuf, name, pathlen); 441 442 #define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0) 443 if ( try("RCS/%s%s", filebase, RCSSUFFIX) 444 || try("RCS/%s" , filebase, 0) 445 || try( "%s%s", filebase, RCSSUFFIX) 446 || try("SCCS/%s%s", SCCSPREFIX, filebase) 447 || try( "%s%s", SCCSPREFIX, filebase)) 448 return name; 449 free(name); 450 name = Nullch; 451 } 452 453 return name; 454 } 455