GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../common/exf.c Lines: 0 499 0.0 %
Date: 2017-11-13 Branches: 0 497 0.0 %

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