1 /* $OpenBSD: exf.c,v 1.26 2011/07/10 13:20:25 millert Exp $ */ 2 3 /*- 4 * Copyright (c) 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1992, 1993, 1994, 1995, 1996 7 * Keith Bostic. All rights reserved. 8 * 9 * See the LICENSE file for redistribution information. 10 */ 11 12 #include "config.h" 13 14 #include <sys/param.h> 15 #include <sys/types.h> /* XXX: param.h may not have included types.h */ 16 #include <sys/queue.h> 17 #include <sys/stat.h> 18 19 /* 20 * We include <sys/file.h>, because the flock(2) and open(2) #defines 21 * were found there on historical systems. We also include <fcntl.h> 22 * because the open(2) #defines are found there on newer systems. 23 */ 24 #include <sys/file.h> 25 26 #include <bitstring.h> 27 #include <dirent.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <limits.h> 31 #include <signal.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include "common.h" 38 39 static int file_backup(SCR *, char *, char *); 40 static void file_cinit(SCR *); 41 static void file_comment(SCR *); 42 static int file_spath(SCR *, FREF *, struct stat *, int *); 43 44 /* 45 * file_add -- 46 * Insert a file name into the FREF list, if it doesn't already 47 * appear in it. 48 * 49 * !!! 50 * The "if it doesn't already appear" changes vi's semantics slightly. If 51 * you do a "vi foo bar", and then execute "next bar baz", the edit of bar 52 * will reflect the line/column of the previous edit session. Historic nvi 53 * did not do this. The change is a logical extension of the change where 54 * vi now remembers the last location in any file that it has ever edited, 55 * not just the previously edited file. 56 * 57 * PUBLIC: FREF *file_add(SCR *, CHAR_T *); 58 */ 59 FREF * 60 file_add(sp, name) 61 SCR *sp; 62 CHAR_T *name; 63 { 64 GS *gp; 65 FREF *frp, *tfrp; 66 67 /* 68 * Return it if it already exists. Note that we test against the 69 * user's name, whatever that happens to be, including if it's a 70 * temporary file. 71 * 72 * If the user added a file but was unable to initialize it, there 73 * can be file list entries where the name field is NULL. Discard 74 * them the next time we see them. 75 */ 76 gp = sp->gp; 77 if (name != NULL) 78 CIRCLEQ_FOREACH(frp, &gp->frefq, q) { 79 if (frp->name == NULL) { 80 tfrp = CIRCLEQ_NEXT(frp, q); 81 CIRCLEQ_REMOVE(&gp->frefq, frp, q); 82 if (frp->name != NULL) 83 free(frp->name); 84 free(frp); 85 frp = tfrp; 86 continue; 87 } 88 if (!strcmp(frp->name, name)) 89 return (frp); 90 } 91 92 /* Allocate and initialize the FREF structure. */ 93 CALLOC(sp, frp, FREF *, 1, sizeof(FREF)); 94 if (frp == NULL) 95 return (NULL); 96 97 /* 98 * If no file name specified, or if the file name is a request 99 * for something temporary, file_init() will allocate the file 100 * name. Temporary files are always ignored. 101 */ 102 if (name != NULL && strcmp(name, TEMPORARY_FILE_STRING) && 103 (frp->name = strdup(name)) == NULL) { 104 free(frp); 105 msgq(sp, M_SYSERR, NULL); 106 return (NULL); 107 } 108 109 /* Append into the chain of file names. */ 110 CIRCLEQ_INSERT_TAIL(&gp->frefq, frp, q); 111 112 return (frp); 113 } 114 115 /* 116 * file_init -- 117 * Start editing a file, based on the FREF structure. If successsful, 118 * let go of any previous file. Don't release the previous file until 119 * absolutely sure we have the new one. 120 * 121 * PUBLIC: int file_init(SCR *, FREF *, char *, int); 122 */ 123 int 124 file_init(sp, frp, rcv_name, flags) 125 SCR *sp; 126 FREF *frp; 127 char *rcv_name; 128 int flags; 129 { 130 EXF *ep; 131 RECNOINFO oinfo; 132 struct stat sb; 133 size_t psize; 134 int fd, exists, open_err, readonly; 135 char *oname, tname[MAXPATHLEN]; 136 137 open_err = readonly = 0; 138 139 /* 140 * If the file is a recovery file, let the recovery code handle it. 141 * Clear the FR_RECOVER flag first -- the recovery code does set up, 142 * and then calls us! If the recovery call fails, it's probably 143 * because the named file doesn't exist. So, move boldly forward, 144 * presuming that there's an error message the user will get to see. 145 */ 146 if (F_ISSET(frp, FR_RECOVER)) { 147 F_CLR(frp, FR_RECOVER); 148 if (rcv_read(sp, frp) == 0) 149 return (0); /* successful recovery */ 150 } 151 152 /* 153 * Required FRP initialization; the only flag we keep is the 154 * cursor information. 155 */ 156 F_CLR(frp, ~FR_CURSORSET); 157 158 /* 159 * Required EXF initialization: 160 * Flush the line caches. 161 * Default recover mail file fd to -1. 162 * Set initial EXF flag bits. 163 */ 164 CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF)); 165 ep->c_lno = ep->c_nlines = OOBLNO; 166 ep->rcv_fd = ep->fcntl_fd = -1; 167 F_SET(ep, F_FIRSTMODIFY); 168 169 /* 170 * Scan the user's path to find the file that we're going to 171 * try and open. 172 */ 173 if (file_spath(sp, frp, &sb, &exists)) { 174 free(ep); 175 return (1); 176 } 177 178 /* 179 * If no name or backing file, for whatever reason, create a backing 180 * temporary file, saving the temp file name so we can later unlink 181 * it. If the user never named this file, copy the temporary file name 182 * to the real name (we display that until the user renames it). 183 */ 184 oname = frp->name; 185 if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) { 186 /* 187 * Don't try to create a temporary support file twice. 188 */ 189 if (frp->tname != NULL) 190 goto err; 191 if (opts_empty(sp, O_TMP_DIRECTORY, 0)) 192 goto err; 193 (void)snprintf(tname, sizeof(tname), 194 "%s/vi.XXXXXXXXXX", O_STR(sp, O_TMP_DIRECTORY)); 195 fd = mkstemp(tname); 196 if (fd == -1 || fchmod(fd, S_IRUSR | S_IWUSR) == -1) { 197 msgq(sp, M_SYSERR, 198 "237|Unable to create temporary file"); 199 if (fd != -1) { 200 close(fd); 201 (void)unlink(tname); 202 } 203 goto err; 204 } 205 (void)close(fd); 206 207 if (frp->name == NULL) 208 F_SET(frp, FR_TMPFILE); 209 if ((frp->tname = strdup(tname)) == NULL || 210 (frp->name == NULL && (frp->name = strdup(tname)) == NULL)) { 211 if (frp->tname != NULL) 212 free(frp->tname); 213 msgq(sp, M_SYSERR, NULL); 214 (void)unlink(tname); 215 goto err; 216 } 217 oname = frp->tname; 218 psize = 1024; 219 if (!LF_ISSET(FS_OPENERR)) 220 F_SET(frp, FR_NEWFILE); 221 222 time(&ep->mtime); 223 } else { 224 /* 225 * XXX 226 * A seat of the pants calculation: try to keep the file in 227 * 15 pages or less. Don't use a page size larger than 10K 228 * (vi should have good locality) or smaller than 1K. 229 */ 230 psize = ((sb.st_size / 15) + 1023) / 1024; 231 if (psize > 10) 232 psize = 10; 233 if (psize == 0) 234 psize = 1; 235 psize *= 1024; 236 237 F_SET(ep, F_DEVSET); 238 ep->mdev = sb.st_dev; 239 ep->minode = sb.st_ino; 240 241 ep->mtime = sb.st_mtime; 242 243 if (!S_ISREG(sb.st_mode)) 244 msgq_str(sp, M_ERR, oname, 245 "238|Warning: %s is not a regular file"); 246 } 247 248 /* Set up recovery. */ 249 memset(&oinfo, 0, sizeof(RECNOINFO)); 250 oinfo.bval = '\n'; /* Always set. */ 251 oinfo.psize = psize; 252 oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0; 253 if (rcv_name == NULL) { 254 if (!rcv_tmp(sp, ep, frp->name)) 255 oinfo.bfname = ep->rcv_path; 256 } else { 257 if ((ep->rcv_path = strdup(rcv_name)) == NULL) { 258 msgq(sp, M_SYSERR, NULL); 259 goto err; 260 } 261 oinfo.bfname = ep->rcv_path; 262 F_SET(ep, F_MODIFIED); 263 } 264 265 /* Open a db structure. */ 266 if ((ep->db = dbopen(rcv_name == NULL ? oname : NULL, 267 O_NONBLOCK | O_RDONLY, 268 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, 269 DB_RECNO, &oinfo)) == NULL) { 270 msgq_str(sp, 271 M_SYSERR, rcv_name == NULL ? oname : rcv_name, "%s"); 272 /* 273 * !!! 274 * Historically, vi permitted users to edit files that couldn't 275 * be read. This isn't useful for single files from a command 276 * line, but it's quite useful for "vi *.c", since you can skip 277 * past files that you can't read. 278 */ 279 open_err = 1; 280 goto oerr; 281 } 282 283 /* 284 * Do the remaining things that can cause failure of the new file, 285 * mark and logging initialization. 286 */ 287 if (mark_init(sp, ep) || log_init(sp, ep)) 288 goto err; 289 290 /* 291 * Set the alternate file name to be the file we're discarding. 292 * 293 * !!! 294 * Temporary files can't become alternate files, so there's no file 295 * name. This matches historical practice, although it could only 296 * happen in historical vi as the result of the initial command, i.e. 297 * if vi was executed without a file name. 298 */ 299 if (LF_ISSET(FS_SETALT)) 300 set_alt_name(sp, sp->frp == NULL || 301 F_ISSET(sp->frp, FR_TMPFILE) ? NULL : sp->frp->name); 302 303 /* 304 * Close the previous file; if that fails, close the new one and run 305 * for the border. 306 * 307 * !!! 308 * There's a nasty special case. If the user edits a temporary file, 309 * and then does an ":e! %", we need to re-initialize the backing 310 * file, but we can't change the name. (It's worse -- we're dealing 311 * with *names* here, we can't even detect that it happened.) Set a 312 * flag so that the file_end routine ignores the backing information 313 * of the old file if it happens to be the same as the new one. 314 * 315 * !!! 316 * Side-effect: after the call to file_end(), sp->frp may be NULL. 317 */ 318 if (sp->ep != NULL) { 319 F_SET(frp, FR_DONTDELETE); 320 if (file_end(sp, NULL, LF_ISSET(FS_FORCE))) { 321 (void)file_end(sp, ep, 1); 322 goto err; 323 } 324 F_CLR(frp, FR_DONTDELETE); 325 } 326 327 /* 328 * Lock the file; if it's a recovery file, it should already be 329 * locked. Note, we acquire the lock after the previous file 330 * has been ended, so that we don't get an "already locked" error 331 * for ":edit!". 332 * 333 * XXX 334 * While the user can't interrupt us between the open and here, 335 * there's a race between the dbopen() and the lock. Not much 336 * we can do about it. 337 * 338 * XXX 339 * We don't make a big deal of not being able to lock the file. As 340 * locking rarely works over NFS, and often fails if the file was 341 * mmap(2)'d, it's far too common to do anything like print an error 342 * message, let alone make the file readonly. At some future time, 343 * when locking is a little more reliable, this should change to be 344 * an error. 345 */ 346 if (rcv_name == NULL) 347 switch (file_lock(sp, oname, 348 &ep->fcntl_fd, ep->db->fd(ep->db), 0)) { 349 case LOCK_FAILED: 350 F_SET(frp, FR_UNLOCKED); 351 break; 352 case LOCK_UNAVAIL: 353 readonly = 1; 354 if (!O_ISSET(sp, O_READONLY)) { 355 msgq_str(sp, M_INFO, oname, 356 "239|%s already locked, session is read-only"); 357 } 358 break; 359 case LOCK_SUCCESS: 360 break; 361 } 362 363 /* 364 * Historically, the readonly edit option was set per edit buffer in 365 * vi, unless the -R command-line option was specified or the program 366 * was executed as "view". (Well, to be truthful, if the letter 'w' 367 * occurred anywhere in the program name, but let's not get into that.) 368 * So, the persistent readonly state has to be stored in the screen 369 * structure, and the edit option value toggles with the contents of 370 * the edit buffer. If the persistent readonly flag is set, set the 371 * readonly edit option. 372 * 373 * Otherwise, try and figure out if a file is readonly. This is a 374 * dangerous thing to do. The kernel is the only arbiter of whether 375 * or not a file is writeable, and the best that a user program can 376 * do is guess. Obvious loopholes are files that are on a file system 377 * mounted readonly (access catches this one on a few systems), or 378 * alternate protection mechanisms, ACL's for example, that we can't 379 * portably check. Lots of fun, and only here because users whined. 380 * 381 * !!! 382 * Historic vi displayed the readonly message if none of the file 383 * write bits were set, or if an an access(2) call on the path 384 * failed. This seems reasonable. If the file is mode 444, root 385 * users may want to know that the owner of the file did not expect 386 * it to be written. 387 * 388 * Historic vi set the readonly bit if no write bits were set for 389 * a file, even if the access call would have succeeded. This makes 390 * the superuser force the write even when vi expects that it will 391 * succeed. I'm less supportive of this semantic, but it's historic 392 * practice and the conservative approach to vi'ing files as root. 393 * 394 * It would be nice if there was some way to update this when the user 395 * does a "^Z; chmod ...". The problem is that we'd first have to 396 * distinguish between readonly bits set because of file permissions 397 * and those set for other reasons. That's not too hard, but deciding 398 * when to reevaluate the permissions is trickier. An alternative 399 * might be to turn off the readonly bit if the user forces a write 400 * and it succeeds. 401 * 402 * XXX 403 * Access(2) doesn't consider the effective uid/gid values. This 404 * probably isn't a problem for vi when it's running standalone. 405 */ 406 if (readonly || F_ISSET(sp, SC_READONLY) || 407 (!F_ISSET(frp, FR_NEWFILE) && 408 (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) || 409 access(frp->name, W_OK)))) 410 O_SET(sp, O_READONLY); 411 else 412 O_CLR(sp, O_READONLY); 413 414 /* Switch... */ 415 ++ep->refcnt; 416 sp->ep = ep; 417 sp->frp = frp; 418 419 /* Set the initial cursor position, queue initial command. */ 420 file_cinit(sp); 421 422 /* Redraw the screen from scratch, schedule a welcome message. */ 423 F_SET(sp, SC_SCR_REFORMAT | SC_STATUS); 424 425 return (0); 426 427 err: if (frp->name != NULL) { 428 free(frp->name); 429 frp->name = NULL; 430 } 431 if (frp->tname != NULL) { 432 (void)unlink(frp->tname); 433 free(frp->tname); 434 frp->tname = NULL; 435 } 436 437 oerr: if (F_ISSET(ep, F_RCV_ON)) 438 (void)unlink(ep->rcv_path); 439 if (ep->rcv_path != NULL) { 440 free(ep->rcv_path); 441 ep->rcv_path = NULL; 442 } 443 if (ep->db != NULL) 444 (void)ep->db->close(ep->db); 445 free(ep); 446 447 return (open_err ? 448 file_init(sp, frp, rcv_name, flags | FS_OPENERR) : 1); 449 } 450 451 /* 452 * file_spath -- 453 * Scan the user's path to find the file that we're going to 454 * try and open. 455 */ 456 static int 457 file_spath(sp, frp, sbp, existsp) 458 SCR *sp; 459 FREF *frp; 460 struct stat *sbp; 461 int *existsp; 462 { 463 CHAR_T savech; 464 size_t len; 465 int found; 466 char *name, *p, *t, path[MAXPATHLEN]; 467 468 /* 469 * If the name is NULL or an explicit reference (i.e., the first 470 * component is . or ..) ignore the O_PATH option. 471 */ 472 name = frp->name; 473 if (name == NULL) { 474 *existsp = 0; 475 return (0); 476 } 477 if (name[0] == '/' || (name[0] == '.' && 478 (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) { 479 *existsp = !stat(name, sbp); 480 return (0); 481 } 482 483 /* Try . */ 484 if (!stat(name, sbp)) { 485 *existsp = 1; 486 return (0); 487 } 488 489 /* Try the O_PATH option values. */ 490 for (found = 0, p = t = O_STR(sp, O_PATH);; ++p) 491 if (*p == ':' || *p == '\0') { 492 if (t < p - 1) { 493 savech = *p; 494 *p = '\0'; 495 len = snprintf(path, 496 sizeof(path), "%s/%s", t, name); 497 if (len >= sizeof(path)) 498 len = sizeof(path) - 1; 499 *p = savech; 500 if (!stat(path, sbp)) { 501 found = 1; 502 break; 503 } 504 } 505 t = p + 1; 506 if (*p == '\0') 507 break; 508 } 509 510 /* If we found it, build a new pathname and discard the old one. */ 511 if (found) { 512 MALLOC_RET(sp, p, char *, len + 1); 513 memcpy(p, path, len + 1); 514 free(frp->name); 515 frp->name = p; 516 } 517 *existsp = found; 518 return (0); 519 } 520 521 /* 522 * file_cinit -- 523 * Set up the initial cursor position. 524 */ 525 static void 526 file_cinit(sp) 527 SCR *sp; 528 { 529 GS *gp; 530 MARK m; 531 size_t len; 532 int nb; 533 534 /* Set some basic defaults. */ 535 sp->lno = 1; 536 sp->cno = 0; 537 538 /* 539 * Historically, initial commands (the -c option) weren't executed 540 * until a file was loaded, e.g. "vi +10 nofile", followed by an 541 * :edit or :tag command, would execute the +10 on the file loaded 542 * by the subsequent command, (assuming that it existed). This 543 * applied as well to files loaded using the tag commands, and we 544 * follow that historic practice. Also, all initial commands were 545 * ex commands and were always executed on the last line of the file. 546 * 547 * Otherwise, if no initial command for this file: 548 * If in ex mode, move to the last line, first nonblank character. 549 * If the file has previously been edited, move to the last known 550 * position, and check it for validity. 551 * Otherwise, move to the first line, first nonblank. 552 * 553 * This gets called by the file init code, because we may be in a 554 * file of ex commands and we want to execute them from the right 555 * location in the file. 556 */ 557 nb = 0; 558 gp = sp->gp; 559 if (gp->c_option != NULL && !F_ISSET(sp->frp, FR_NEWFILE)) { 560 if (db_last(sp, &sp->lno)) 561 return; 562 if (sp->lno == 0) { 563 sp->lno = 1; 564 sp->cno = 0; 565 } 566 if (ex_run_str(sp, 567 "-c option", gp->c_option, strlen(gp->c_option), 1, 1)) 568 return; 569 gp->c_option = NULL; 570 } else if (F_ISSET(sp, SC_EX)) { 571 if (db_last(sp, &sp->lno)) 572 return; 573 if (sp->lno == 0) { 574 sp->lno = 1; 575 sp->cno = 0; 576 return; 577 } 578 nb = 1; 579 } else { 580 if (F_ISSET(sp->frp, FR_CURSORSET)) { 581 sp->lno = sp->frp->lno; 582 sp->cno = sp->frp->cno; 583 584 /* If returning to a file in vi, center the line. */ 585 F_SET(sp, SC_SCR_CENTER); 586 } else { 587 if (O_ISSET(sp, O_COMMENT)) 588 file_comment(sp); 589 else 590 sp->lno = 1; 591 nb = 1; 592 } 593 if (db_get(sp, sp->lno, 0, NULL, &len)) { 594 sp->lno = 1; 595 sp->cno = 0; 596 return; 597 } 598 if (!nb && sp->cno > len) 599 nb = 1; 600 } 601 if (nb) { 602 sp->cno = 0; 603 (void)nonblank(sp, sp->lno, &sp->cno); 604 } 605 606 /* 607 * !!! 608 * The initial column is also the most attractive column. 609 */ 610 sp->rcm = sp->cno; 611 612 /* 613 * !!! 614 * Historically, vi initialized the absolute mark, but ex did not. 615 * Which meant, that if the first command in ex mode was "visual", 616 * or if an ex command was executed first (e.g. vi +10 file) vi was 617 * entered without the mark being initialized. For consistency, if 618 * the file isn't empty, we initialize it for everyone, believing 619 * that it can't hurt, and is generally useful. Not initializing it 620 * if the file is empty is historic practice, although it has always 621 * been possible to set (and use) marks in empty vi files. 622 */ 623 m.lno = sp->lno; 624 m.cno = sp->cno; 625 (void)mark_set(sp, ABSMARK1, &m, 0); 626 } 627 628 /* 629 * file_end -- 630 * Stop editing a file. 631 * 632 * PUBLIC: int file_end(SCR *, EXF *, int); 633 */ 634 int 635 file_end(sp, ep, force) 636 SCR *sp; 637 EXF *ep; 638 int force; 639 { 640 FREF *frp; 641 642 /* 643 * !!! 644 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. 645 * (If argument ep is NULL, use sp->ep.) 646 * 647 * If multiply referenced, just decrement the count and return. 648 */ 649 if (ep == NULL) 650 ep = sp->ep; 651 if (--ep->refcnt != 0) 652 return (0); 653 654 /* 655 * 656 * Clean up the FREF structure. 657 * 658 * Save the cursor location. 659 * 660 * XXX 661 * It would be cleaner to do this somewhere else, but by the time 662 * ex or vi knows that we're changing files it's already happened. 663 */ 664 frp = sp->frp; 665 frp->lno = sp->lno; 666 frp->cno = sp->cno; 667 F_SET(frp, FR_CURSORSET); 668 669 /* 670 * We may no longer need the temporary backing file, so clean it 671 * up. We don't need the FREF structure either, if the file was 672 * never named, so lose it. 673 * 674 * !!! 675 * Re: FR_DONTDELETE, see the comment above in file_init(). 676 */ 677 if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) { 678 if (unlink(frp->tname)) 679 msgq_str(sp, M_SYSERR, frp->tname, "240|%s: remove"); 680 free(frp->tname); 681 frp->tname = NULL; 682 if (F_ISSET(frp, FR_TMPFILE)) { 683 CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q); 684 if (frp->name != NULL) 685 free(frp->name); 686 free(frp); 687 } 688 sp->frp = NULL; 689 } 690 691 /* 692 * Clean up the EXF structure. 693 * 694 * Close the db structure. 695 */ 696 if (ep->db->close != NULL && ep->db->close(ep->db) && !force) { 697 msgq_str(sp, M_SYSERR, frp->name, "241|%s: close"); 698 ++ep->refcnt; 699 return (1); 700 } 701 702 /* COMMITTED TO THE CLOSE. THERE'S NO GOING BACK... */ 703 704 /* Stop logging. */ 705 (void)log_end(sp, ep); 706 707 /* Free up any marks. */ 708 (void)mark_end(sp, ep); 709 710 /* 711 * Delete recovery files, close the open descriptor, free recovery 712 * memory. See recover.c for a description of the protocol. 713 * 714 * XXX 715 * Unlink backup file first, we can detect that the recovery file 716 * doesn't reference anything when the user tries to recover it. 717 * There's a race, here, obviously, but it's fairly small. 718 */ 719 if (!F_ISSET(ep, F_RCV_NORM)) { 720 if (ep->rcv_path != NULL && unlink(ep->rcv_path)) 721 msgq_str(sp, M_SYSERR, ep->rcv_path, "242|%s: remove"); 722 if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath)) 723 msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove"); 724 } 725 if (ep->fcntl_fd != -1) 726 (void)close(ep->fcntl_fd); 727 if (ep->rcv_fd != -1) 728 (void)close(ep->rcv_fd); 729 if (ep->rcv_path != NULL) 730 free(ep->rcv_path); 731 if (ep->rcv_mpath != NULL) 732 free(ep->rcv_mpath); 733 734 free(ep); 735 return (0); 736 } 737 738 /* 739 * file_write -- 740 * Write the file to disk. Historic vi had fairly convoluted 741 * semantics for whether or not writes would happen. That's 742 * why all the flags. 743 * 744 * PUBLIC: int file_write(SCR *, MARK *, MARK *, char *, int); 745 */ 746 int 747 file_write(sp, fm, tm, name, flags) 748 SCR *sp; 749 MARK *fm, *tm; 750 char *name; 751 int flags; 752 { 753 enum { NEWFILE, OLDFILE } mtype; 754 struct stat sb; 755 EXF *ep; 756 FILE *fp; 757 FREF *frp; 758 MARK from, to; 759 size_t len; 760 u_long nlno, nch; 761 int fd, nf, noname, oflags, rval; 762 char *p, *s, *t, buf[MAXPATHLEN + 64]; 763 const char *msgstr; 764 765 ep = sp->ep; 766 frp = sp->frp; 767 768 /* 769 * Writing '%', or naming the current file explicitly, has the 770 * same semantics as writing without a name. 771 */ 772 if (name == NULL || !strcmp(name, frp->name)) { 773 noname = 1; 774 name = frp->name; 775 } else 776 noname = 0; 777 778 /* Can't write files marked read-only, unless forced. */ 779 if (!LF_ISSET(FS_FORCE) && noname && O_ISSET(sp, O_READONLY)) { 780 msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ? 781 "244|Read-only file, not written; use ! to override" : 782 "245|Read-only file, not written"); 783 return (1); 784 } 785 786 /* If not forced, not appending, and "writeany" not set ... */ 787 if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) { 788 /* Don't overwrite anything but the original file. */ 789 if ((!noname || F_ISSET(frp, FR_NAMECHANGE)) && 790 !stat(name, &sb)) { 791 msgq_str(sp, M_ERR, name, 792 LF_ISSET(FS_POSSIBLE) ? 793 "246|%s exists, not written; use ! to override" : 794 "247|%s exists, not written"); 795 return (1); 796 } 797 798 /* 799 * Don't write part of any existing file. Only test for the 800 * original file, the previous test catches anything else. 801 */ 802 if (!LF_ISSET(FS_ALL) && noname && !stat(name, &sb)) { 803 msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ? 804 "248|Partial file, not written; use ! to override" : 805 "249|Partial file, not written"); 806 return (1); 807 } 808 } 809 810 /* 811 * Figure out if the file already exists -- if it doesn't, we display 812 * the "new file" message. The stat might not be necessary, but we 813 * just repeat it because it's easier than hacking the previous tests. 814 * The information is only used for the user message and modification 815 * time test, so we can ignore the obvious race condition. 816 * 817 * One final test. If we're not forcing or appending the current file, 818 * and we have a saved modification time, object if the file changed 819 * since we last edited or wrote it, and make them force it. 820 */ 821 if (stat(name, &sb)) 822 mtype = NEWFILE; 823 else { 824 if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) && 825 ((F_ISSET(ep, F_DEVSET) && 826 (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) || 827 sb.st_mtime != ep->mtime)) { 828 msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ? 829 "250|%s: file modified more recently than this copy; use ! to override" : 830 "251|%s: file modified more recently than this copy"); 831 return (1); 832 } 833 834 mtype = OLDFILE; 835 } 836 837 /* Set flags to create, write, and either append or truncate. */ 838 oflags = O_CREAT | O_WRONLY | 839 (LF_ISSET(FS_APPEND) ? O_APPEND : O_TRUNC); 840 841 /* Backup the file if requested. */ 842 if (!opts_empty(sp, O_BACKUP, 1) && 843 file_backup(sp, name, O_STR(sp, O_BACKUP)) && !LF_ISSET(FS_FORCE)) 844 return (1); 845 846 /* Open the file. */ 847 SIGBLOCK; 848 if ((fd = open(name, oflags, 849 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) { 850 msgq_str(sp, M_SYSERR, name, "%s"); 851 SIGUNBLOCK; 852 return (1); 853 } 854 SIGUNBLOCK; 855 856 /* Try and get a lock. */ 857 if (!noname && file_lock(sp, NULL, NULL, fd, 0) == LOCK_UNAVAIL) 858 msgq_str(sp, M_ERR, name, 859 "252|%s: write lock was unavailable"); 860 861 #if __linux__ 862 /* 863 * XXX 864 * In libc 4.5.x, fdopen(fd, "w") clears the O_APPEND flag (if set). 865 * This bug is fixed in libc 4.6.x. 866 * 867 * This code works around this problem for libc 4.5.x users. 868 * Note that this code is harmless if you're using libc 4.6.x. 869 */ 870 if (LF_ISSET(FS_APPEND) && lseek(fd, (off_t)0, SEEK_END) < 0) { 871 msgq(sp, M_SYSERR, "%s", name); 872 return (1); 873 } 874 #endif 875 876 /* 877 * Use stdio for buffering. 878 * 879 * XXX 880 * SVR4.2 requires the fdopen mode exactly match the original open 881 * mode, i.e. you have to open with "a" if appending. 882 */ 883 if ((fp = fdopen(fd, LF_ISSET(FS_APPEND) ? "a" : "w")) == NULL) { 884 msgq_str(sp, M_SYSERR, name, "%s"); 885 (void)close(fd); 886 return (1); 887 } 888 889 /* Build fake addresses, if necessary. */ 890 if (fm == NULL) { 891 from.lno = 1; 892 from.cno = 0; 893 fm = &from; 894 if (db_last(sp, &to.lno)) 895 return (1); 896 to.cno = 0; 897 tm = &to; 898 } 899 900 rval = ex_writefp(sp, name, fp, fm, tm, &nlno, &nch, 0); 901 902 /* 903 * Save the new last modification time -- even if the write fails 904 * we re-init the time. That way the user can clean up the disk 905 * and rewrite without having to force it. 906 */ 907 if (noname) { 908 if (stat(name, &sb)) 909 time(&ep->mtime); 910 else { 911 F_SET(ep, F_DEVSET); 912 ep->mdev = sb.st_dev; 913 ep->minode = sb.st_ino; 914 915 ep->mtime = sb.st_mtime; 916 } 917 } 918 919 /* 920 * If the write failed, complain loudly. ex_writefp() has already 921 * complained about the actual error, reinforce it if data was lost. 922 */ 923 if (rval) { 924 if (!LF_ISSET(FS_APPEND)) 925 msgq_str(sp, M_ERR, name, 926 "254|%s: WARNING: FILE TRUNCATED"); 927 return (1); 928 } 929 930 /* 931 * Once we've actually written the file, it doesn't matter that the 932 * file name was changed -- if it was, we've already whacked it. 933 */ 934 F_CLR(frp, FR_NAMECHANGE); 935 936 /* 937 * If wrote the entire file, and it wasn't by appending it to a file, 938 * clear the modified bit. If the file was written to the original 939 * file name and the file is a temporary, set the "no exit" bit. This 940 * permits the user to write the file and use it in the context of the 941 * filesystem, but still keeps them from discarding their changes by 942 * exiting. 943 */ 944 if (LF_ISSET(FS_ALL) && !LF_ISSET(FS_APPEND)) { 945 F_CLR(ep, F_MODIFIED); 946 if (F_ISSET(frp, FR_TMPFILE)) { 947 if (noname) 948 F_SET(frp, FR_TMPEXIT); 949 else 950 F_CLR(frp, FR_TMPEXIT); 951 } 952 } 953 954 p = msg_print(sp, name, &nf); 955 switch (mtype) { 956 case NEWFILE: 957 msgstr = msg_cat(sp, 958 "256|%s: new file: %lu lines, %lu characters", NULL); 959 len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch); 960 if (len >= sizeof(buf)) 961 len = sizeof(buf) - 1; 962 break; 963 case OLDFILE: 964 msgstr = msg_cat(sp, LF_ISSET(FS_APPEND) ? 965 "315|%s: appended: %lu lines, %lu characters" : 966 "257|%s: %lu lines, %lu characters", NULL); 967 len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch); 968 if (len >= sizeof(buf)) 969 len = sizeof(buf) - 1; 970 break; 971 default: 972 abort(); 973 } 974 975 /* 976 * There's a nasty problem with long path names. Cscope and tags files 977 * can result in long paths and vi will request a continuation key from 978 * the user. Unfortunately, the user has typed ahead, and chaos will 979 * result. If we assume that the characters in the filenames only take 980 * a single screen column each, we can trim the filename. 981 */ 982 s = buf; 983 if (len >= sp->cols) { 984 for (s = buf, t = buf + strlen(p); s < t && 985 (*s != '/' || len >= sp->cols - 3); ++s, --len); 986 if (s == t) 987 s = buf; 988 else { 989 *--s = '.'; /* Leading ellipses. */ 990 *--s = '.'; 991 *--s = '.'; 992 } 993 } 994 msgq(sp, M_INFO, "%s", s); 995 if (nf) 996 FREE_SPACE(sp, p, 0); 997 return (0); 998 } 999 1000 /* 1001 * file_backup -- 1002 * Backup the about-to-be-written file. 1003 * 1004 * XXX 1005 * We do the backup by copying the entire file. It would be nice to do 1006 * a rename instead, but: (1) both files may not fit and we want to fail 1007 * before doing the rename; (2) the backup file may not be on the same 1008 * disk partition as the file being written; (3) there may be optional 1009 * file information (MACs, DACs, whatever) that we won't get right if we 1010 * recreate the file. So, let's not risk it. 1011 */ 1012 static int 1013 file_backup(sp, name, bname) 1014 SCR *sp; 1015 char *name, *bname; 1016 { 1017 struct dirent *dp; 1018 struct stat sb; 1019 DIR *dirp; 1020 EXCMD cmd; 1021 off_t off; 1022 size_t blen; 1023 int flags, maxnum, nr, num, nw, rfd, wfd, version; 1024 char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192]; 1025 1026 rfd = wfd = -1; 1027 bp = estr = wfname = NULL; 1028 1029 /* 1030 * Open the current file for reading. Do this first, so that 1031 * we don't exec a shell before the most likely failure point. 1032 * If it doesn't exist, it's okay, there's just nothing to back 1033 * up. 1034 */ 1035 errno = 0; 1036 if ((rfd = open(name, O_RDONLY, 0)) < 0) { 1037 if (errno == ENOENT) 1038 return (0); 1039 estr = name; 1040 goto err; 1041 } 1042 1043 /* 1044 * If the name starts with an 'N' character, add a version number 1045 * to the name. Strip the leading N from the string passed to the 1046 * expansion routines, for no particular reason. It would be nice 1047 * to permit users to put the version number anywhere in the backup 1048 * name, but there isn't a special character that we can use in the 1049 * name, and giving a new character a special meaning leads to ugly 1050 * hacks both here and in the supporting ex routines. 1051 * 1052 * Shell and file name expand the option's value. 1053 */ 1054 argv_init(sp, &cmd); 1055 ex_cinit(&cmd, 0, 0, 0, 0, 0, NULL); 1056 if (bname[0] == 'N') { 1057 version = 1; 1058 ++bname; 1059 } else 1060 version = 0; 1061 if (argv_exp2(sp, &cmd, bname, strlen(bname))) 1062 return (1); 1063 1064 /* 1065 * 0 args: impossible. 1066 * 1 args: use it. 1067 * >1 args: object, too many args. 1068 */ 1069 if (cmd.argc != 1) { 1070 msgq_str(sp, M_ERR, bname, 1071 "258|%s expanded into too many file names"); 1072 (void)close(rfd); 1073 return (1); 1074 } 1075 1076 /* 1077 * If appending a version number, read through the directory, looking 1078 * for file names that match the name followed by a number. Make all 1079 * of the other % characters in name literal, so the user doesn't get 1080 * surprised and sscanf doesn't drop core indirecting through pointers 1081 * that don't exist. If any such files are found, increment its number 1082 * by one. 1083 */ 1084 if (version) { 1085 GET_SPACE_GOTO(sp, bp, blen, cmd.argv[0]->len * 2 + 50); 1086 for (t = bp, slash = NULL, 1087 p = cmd.argv[0]->bp; p[0] != '\0'; *t++ = *p++) 1088 if (p[0] == '%') { 1089 if (p[1] != '%') 1090 *t++ = '%'; 1091 } else if (p[0] == '/') 1092 slash = t; 1093 pct = t; 1094 *t++ = '%'; 1095 *t++ = 'd'; 1096 *t = '\0'; 1097 1098 if (slash == NULL) { 1099 dirp = opendir("."); 1100 p = bp; 1101 } else { 1102 *slash = '\0'; 1103 dirp = opendir(bp); 1104 *slash = '/'; 1105 p = slash + 1; 1106 } 1107 if (dirp == NULL) { 1108 estr = cmd.argv[0]->bp; 1109 goto err; 1110 } 1111 1112 for (maxnum = 0; (dp = readdir(dirp)) != NULL;) 1113 if (sscanf(dp->d_name, p, &num) == 1 && num > maxnum) 1114 maxnum = num; 1115 (void)closedir(dirp); 1116 1117 /* Format the backup file name. */ 1118 (void)snprintf(pct, blen - (pct - bp), "%d", maxnum + 1); 1119 wfname = bp; 1120 } else { 1121 bp = NULL; 1122 wfname = cmd.argv[0]->bp; 1123 } 1124 1125 /* Open the backup file, avoiding lurkers. */ 1126 if (stat(wfname, &sb) == 0) { 1127 if (!S_ISREG(sb.st_mode)) { 1128 msgq_str(sp, M_ERR, bname, 1129 "259|%s: not a regular file"); 1130 goto err; 1131 } 1132 if (sb.st_uid != getuid()) { 1133 msgq_str(sp, M_ERR, bname, "260|%s: not owned by you"); 1134 goto err; 1135 } 1136 if (sb.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) { 1137 msgq_str(sp, M_ERR, bname, 1138 "261|%s: accessible by a user other than the owner"); 1139 goto err; 1140 } 1141 flags = O_TRUNC; 1142 } else 1143 flags = O_CREAT | O_EXCL; 1144 if ((wfd = open(wfname, flags | O_WRONLY, S_IRUSR | S_IWUSR)) < 0 || 1145 fchmod(wfd, S_IRUSR | S_IWUSR) < 0) { 1146 if (wfd != -1) { 1147 close(wfd); 1148 (void)unlink(wfname); 1149 } 1150 estr = bname; 1151 goto err; 1152 } 1153 1154 /* Copy the file's current contents to its backup value. */ 1155 while ((nr = read(rfd, buf, sizeof(buf))) > 0) 1156 for (off = 0; nr != 0; nr -= nw, off += nw) 1157 if ((nw = write(wfd, buf + off, nr)) < 0) { 1158 estr = wfname; 1159 goto err; 1160 } 1161 if (nr < 0) { 1162 estr = name; 1163 goto err; 1164 } 1165 1166 if (close(rfd)) { 1167 estr = name; 1168 goto err; 1169 } 1170 if (close(wfd)) { 1171 estr = wfname; 1172 goto err; 1173 } 1174 if (bp != NULL) 1175 FREE_SPACE(sp, bp, blen); 1176 return (0); 1177 1178 alloc_err: 1179 err: if (rfd != -1) 1180 (void)close(rfd); 1181 if (wfd != -1) { 1182 (void)unlink(wfname); 1183 (void)close(wfd); 1184 } 1185 if (estr) 1186 msgq_str(sp, M_SYSERR, estr, "%s"); 1187 if (bp != NULL) 1188 FREE_SPACE(sp, bp, blen); 1189 return (1); 1190 } 1191 1192 /* 1193 * file_comment -- 1194 * Skip the first comment. 1195 */ 1196 static void 1197 file_comment(sp) 1198 SCR *sp; 1199 { 1200 recno_t lno; 1201 size_t len; 1202 char *p; 1203 1204 for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno); 1205 if (p == NULL) 1206 return; 1207 if (p[0] == '#') { 1208 F_SET(sp, SC_SCR_TOP); 1209 while (!db_get(sp, ++lno, 0, &p, &len)) 1210 if (len < 1 || p[0] != '#') { 1211 sp->lno = lno; 1212 return; 1213 } 1214 } else if (len > 1 && p[0] == '/' && p[1] == '*') { 1215 F_SET(sp, SC_SCR_TOP); 1216 do { 1217 for (; len > 1; --len, ++p) 1218 if (p[0] == '*' && p[1] == '/') { 1219 sp->lno = lno; 1220 return; 1221 } 1222 } while (!db_get(sp, ++lno, 0, &p, &len)); 1223 } else if (len > 1 && p[0] == '/' && p[1] == '/') { 1224 F_SET(sp, SC_SCR_TOP); 1225 p += 2; 1226 len -= 2; 1227 do { 1228 for (; len > 1; --len, ++p) 1229 if (p[0] == '/' && p[1] == '/') { 1230 sp->lno = lno; 1231 return; 1232 } 1233 } while (!db_get(sp, ++lno, 0, &p, &len)); 1234 } 1235 } 1236 1237 /* 1238 * file_m1 -- 1239 * First modification check routine. The :next, :prev, :rewind, :tag, 1240 * :tagpush, :tagpop, ^^ modifications check. 1241 * 1242 * PUBLIC: int file_m1(SCR *, int, int); 1243 */ 1244 int 1245 file_m1(sp, force, flags) 1246 SCR *sp; 1247 int force, flags; 1248 { 1249 EXF *ep; 1250 1251 ep = sp->ep; 1252 1253 /* If no file loaded, return no modifications. */ 1254 if (ep == NULL) 1255 return (0); 1256 1257 /* 1258 * If the file has been modified, we'll want to write it back or 1259 * fail. If autowrite is set, we'll write it back automatically, 1260 * unless force is also set. Otherwise, we fail unless forced or 1261 * there's another open screen on this file. 1262 */ 1263 if (F_ISSET(ep, F_MODIFIED)) { 1264 if (O_ISSET(sp, O_AUTOWRITE)) { 1265 if (!force && file_aw(sp, flags)) 1266 return (1); 1267 } else if (ep->refcnt <= 1 && !force) { 1268 msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ? 1269 "262|File modified since last complete write; write or use ! to override" : 1270 "263|File modified since last complete write; write or use :edit! to override"); 1271 return (1); 1272 } 1273 } 1274 1275 return (file_m3(sp, force)); 1276 } 1277 1278 /* 1279 * file_m2 -- 1280 * Second modification check routine. The :edit, :quit, :recover 1281 * modifications check. 1282 * 1283 * PUBLIC: int file_m2(SCR *, int); 1284 */ 1285 int 1286 file_m2(sp, force) 1287 SCR *sp; 1288 int force; 1289 { 1290 EXF *ep; 1291 1292 ep = sp->ep; 1293 1294 /* If no file loaded, return no modifications. */ 1295 if (ep == NULL) 1296 return (0); 1297 1298 /* 1299 * If the file has been modified, we'll want to fail, unless forced 1300 * or there's another open screen on this file. 1301 */ 1302 if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) { 1303 msgq(sp, M_ERR, 1304 "264|File modified since last complete write; write or use ! to override"); 1305 return (1); 1306 } 1307 1308 return (file_m3(sp, force)); 1309 } 1310 1311 /* 1312 * file_m3 -- 1313 * Third modification check routine. 1314 * 1315 * PUBLIC: int file_m3(SCR *, int); 1316 */ 1317 int 1318 file_m3(sp, force) 1319 SCR *sp; 1320 int force; 1321 { 1322 EXF *ep; 1323 1324 ep = sp->ep; 1325 1326 /* If no file loaded, return no modifications. */ 1327 if (ep == NULL) 1328 return (0); 1329 1330 /* 1331 * Don't exit while in a temporary files if the file was ever modified. 1332 * The problem is that if the user does a ":wq", we write and quit, 1333 * unlinking the temporary file. Not what the user had in mind at all. 1334 * We permit writing to temporary files, so that user maps using file 1335 * system names work with temporary files. 1336 */ 1337 if (F_ISSET(sp->frp, FR_TMPEXIT) && ep->refcnt <= 1 && !force) { 1338 msgq(sp, M_ERR, 1339 "265|File is a temporary; exit will discard modifications"); 1340 return (1); 1341 } 1342 return (0); 1343 } 1344 1345 /* 1346 * file_aw -- 1347 * Autowrite routine. If modified, autowrite is set and the readonly bit 1348 * is not set, write the file. A routine so there's a place to put the 1349 * comment. 1350 * 1351 * PUBLIC: int file_aw(SCR *, int); 1352 */ 1353 int 1354 file_aw(sp, flags) 1355 SCR *sp; 1356 int flags; 1357 { 1358 if (!F_ISSET(sp->ep, F_MODIFIED)) 1359 return (0); 1360 if (!O_ISSET(sp, O_AUTOWRITE)) 1361 return (0); 1362 1363 /* 1364 * !!! 1365 * Historic 4BSD vi attempted to write the file if autowrite was set, 1366 * regardless of the writeability of the file (as defined by the file 1367 * readonly flag). System V changed this as some point, not attempting 1368 * autowrite if the file was readonly. This feels like a bug fix to 1369 * me (e.g. the principle of least surprise is violated if readonly is 1370 * set and vi writes the file), so I'm compatible with System V. 1371 */ 1372 if (O_ISSET(sp, O_READONLY)) { 1373 msgq(sp, M_INFO, 1374 "266|File readonly, modifications not auto-written"); 1375 return (1); 1376 } 1377 return (file_write(sp, NULL, NULL, NULL, flags)); 1378 } 1379 1380 /* 1381 * set_alt_name -- 1382 * Set the alternate pathname. 1383 * 1384 * Set the alternate pathname. It's a routine because I wanted some place 1385 * to hang this comment. The alternate pathname (normally referenced using 1386 * the special character '#' during file expansion and in the vi ^^ command) 1387 * is set by almost all ex commands that take file names as arguments. The 1388 * rules go something like this: 1389 * 1390 * 1: If any ex command takes a file name as an argument (except for the 1391 * :next command), the alternate pathname is set to that file name. 1392 * This excludes the command ":e" and ":w !command" as no file name 1393 * was specified. Note, historically, the :source command did not set 1394 * the alternate pathname. It does in nvi, for consistency. 1395 * 1396 * 2: However, if any ex command sets the current pathname, e.g. the 1397 * ":e file" or ":rew" commands succeed, then the alternate pathname 1398 * is set to the previous file's current pathname, if it had one. 1399 * This includes the ":file" command and excludes the ":e" command. 1400 * So, by rule #1 and rule #2, if ":edit foo" fails, the alternate 1401 * pathname will be "foo", if it succeeds, the alternate pathname will 1402 * be the previous current pathname. The ":e" command will not set 1403 * the alternate or current pathnames regardless. 1404 * 1405 * 3: However, if it's a read or write command with a file argument and 1406 * the current pathname has not yet been set, the file name becomes 1407 * the current pathname, and the alternate pathname is unchanged. 1408 * 1409 * If the user edits a temporary file, there may be times when there is no 1410 * alternative file name. A name argument of NULL turns it off. 1411 * 1412 * PUBLIC: void set_alt_name(SCR *, char *); 1413 */ 1414 void 1415 set_alt_name(sp, name) 1416 SCR *sp; 1417 char *name; 1418 { 1419 if (sp->alt_name != NULL) 1420 free(sp->alt_name); 1421 if (name == NULL) 1422 sp->alt_name = NULL; 1423 else if ((sp->alt_name = strdup(name)) == NULL) 1424 msgq(sp, M_SYSERR, NULL); 1425 } 1426 1427 /* 1428 * file_lock -- 1429 * Get an exclusive lock on a file. 1430 * 1431 * XXX 1432 * The default locking is flock(2) style, not fcntl(2). The latter is 1433 * known to fail badly on some systems, and its only advantage is that 1434 * it occasionally works over NFS. 1435 * 1436 * Furthermore, the semantics of fcntl(2) are wrong. The problems are 1437 * two-fold: you can't close any file descriptor associated with the file 1438 * without losing all of the locks, and you can't get an exclusive lock 1439 * unless you have the file open for writing. Someone ought to be shot, 1440 * but it's probably too late, they may already have reproduced. To get 1441 * around these problems, nvi opens the files for writing when it can and 1442 * acquires a second file descriptor when it can't. The recovery files 1443 * are examples of the former, they're always opened for writing. The DB 1444 * files can't be opened for writing because the semantics of DB are that 1445 * files opened for writing are flushed back to disk when the DB session 1446 * is ended. So, in that case we have to acquire an extra file descriptor. 1447 * 1448 * PUBLIC: lockr_t file_lock(SCR *, char *, int *, int, int); 1449 */ 1450 lockr_t 1451 file_lock(sp, name, fdp, fd, iswrite) 1452 SCR *sp; 1453 char *name; 1454 int *fdp, fd, iswrite; 1455 { 1456 if (!O_ISSET(sp, O_LOCKFILES)) 1457 return (LOCK_SUCCESS); 1458 1459 /* Set close-on-exec flag so locks are not inherited by shell cmd. */ 1460 if (fcntl(fd, F_SETFD, 1) == -1) 1461 msgq_str(sp, M_SYSERR, name, "%s"); 1462 1463 #ifdef HAVE_LOCK_FLOCK /* Hurrah! We've got flock(2). */ 1464 /* 1465 * !!! 1466 * We need to distinguish a lock not being available for the file 1467 * from the file system not supporting locking. Flock is documented 1468 * as returning EWOULDBLOCK; add EAGAIN for good measure, and assume 1469 * they are the former. There's no portable way to do this. 1470 */ 1471 errno = 0; 1472 return (flock(fd, LOCK_EX | LOCK_NB) ? errno == EAGAIN 1473 #ifdef EWOULDBLOCK 1474 || errno == EWOULDBLOCK 1475 #endif 1476 ? LOCK_UNAVAIL : LOCK_FAILED : LOCK_SUCCESS); 1477 #endif 1478 #ifdef HAVE_LOCK_FCNTL /* Gag me. We've got fcntl(2). */ 1479 { 1480 struct flock arg; 1481 int didopen, sverrno; 1482 1483 arg.l_type = F_WRLCK; 1484 arg.l_whence = 0; /* SEEK_SET */ 1485 arg.l_start = arg.l_len = 0; 1486 arg.l_pid = 0; 1487 1488 /* 1489 * If the file descriptor isn't opened for writing, it must fail. 1490 * If we fail because we can't get a read/write file descriptor, 1491 * we return LOCK_SUCCESS, believing that the file is readonly 1492 * and that will be sufficient to warn the user. 1493 */ 1494 if (!iswrite) { 1495 if (name == NULL || fdp == NULL) 1496 return (LOCK_FAILED); 1497 if ((fd = open(name, O_RDWR, 0)) == -1) 1498 return (LOCK_SUCCESS); 1499 *fdp = fd; 1500 didopen = 1; 1501 } 1502 1503 errno = 0; 1504 if (!fcntl(fd, F_SETLK, &arg)) 1505 return (LOCK_SUCCESS); 1506 if (didopen) { 1507 sverrno = errno; 1508 (void)close(fd); 1509 errno = sverrno; 1510 } 1511 1512 /* 1513 * !!! 1514 * We need to distinguish a lock not being available for the file 1515 * from the file system not supporting locking. Fcntl is documented 1516 * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure, 1517 * and assume they are the former. There's no portable way to do this. 1518 */ 1519 return (errno == EACCES || errno == EAGAIN 1520 #ifdef EWOULDBLOCK 1521 || errno == EWOULDBLOCK 1522 #endif 1523 ? LOCK_UNAVAIL : LOCK_FAILED); 1524 } 1525 #endif 1526 #if !defined(HAVE_LOCK_FLOCK) && !defined(HAVE_LOCK_FCNTL) 1527 return (LOCK_SUCCESS); 1528 #endif 1529 } 1530