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