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