xref: /original-bsd/usr.bin/ex/ex_temp.c (revision e0399a72)
1 /*-
2  * Copyright (c) 1980 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ex_temp.c	7.8 (Berkeley) 04/17/91";
10 #endif /* not lint */
11 
12 #include "ex.h"
13 #include "ex_temp.h"
14 #include "ex_vis.h"
15 #include "ex_tty.h"
16 #include "pathnames.h"
17 
18 /*
19  * Editor temporary file routines.
20  * Very similar to those of ed, except uses 2 input buffers.
21  */
22 #define	READ	0
23 #define	WRITE	1
24 
25 #ifndef vms
26 #define	EPOSITION	7
27 #else
28 #define	EPOSITION	13
29 #endif
30 
31 char	tfname[40];
32 char	rfname[40];
33 int	havetmp;
34 short	tfile = -1;
35 short	rfile = -1;
36 
37 fileinit()
38 {
39 	register char *p;
40 	register int i, j;
41 	struct stat stbuf;
42 
43 	if (tline == INCRMT * (HBLKS+2))
44 		return;
45 	cleanup(0);
46 	if (tfile >= 0)
47 		close(tfile);
48 	tline = INCRMT * (HBLKS+2);
49 	blocks[0] = HBLKS;
50 	blocks[1] = HBLKS+1;
51 	blocks[2] = -1;
52 	dirtcnt = 0;
53 	iblock = -1;
54 	iblock2 = -1;
55 	oblock = -1;
56 	CP(tfname, svalue(DIRECTORY));
57 #ifndef vms
58 	if (stat(tfname, &stbuf))
59 #else
60 	goto vms_no_check_dir;
61 #endif
62 	{
63 dumbness:
64 		if (setexit() == 0)
65 			filioerr(tfname);
66 		else
67 			putNFL();
68 		cleanup(1);
69 		ex_exit(1);
70 	}
71 #ifndef	vms
72 	if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
73 		errno = ENOTDIR;
74 		goto dumbness;
75 	}
76 #else
77 vms_no_check_dir:
78 #endif
79 	ichanged = 0;
80 	ichang2 = 0;
81 #ifndef	vms
82 	ignore(strcat(tfname, "/ExXXXXX"));
83 #else
84 	ignore(strcat(tfname, "ExXXXXX"));
85 #endif
86 	for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10)
87 		*--p = j % 10 | '0';
88 #ifdef vms
89 	ignore(strcat(tfname, ".txt.1"));
90 	unlink(tfname);
91 #endif
92 	tfile = creat(tfname, 0600);
93 	if (tfile < 0)
94 		goto dumbness;
95 #ifdef VMUNIX
96 	{
97 		extern stilinc;		/* see below */
98 		stilinc = 0;
99 	}
100 #endif
101 	havetmp = 1;
102 	if (tfile >= 0)
103 		close(tfile);
104 	tfile = open(tfname, 2);
105 	if (tfile < 0)
106 		goto dumbness;
107 #ifdef UNIX_SBRK
108 /* 	brk((char *)fendcore); */
109 #endif
110 }
111 
112 cleanup(all)
113 	bool all;
114 {
115 	if (all) {
116 		putpad(TE);
117 		flush();
118 	}
119 	if (havetmp) {
120 		if (tfile >= 0)
121 			close(tfile);
122 		unlink(tfname);
123 	}
124 	havetmp = 0;
125 	if (all && rfile >= 0) {
126 		if (rfile >= 0)
127 			close(rfile);
128 		unlink(rfname);
129 		rfile = -1;
130 	}
131 }
132 
133 getline(tl)
134 	line tl;
135 {
136 	register char *bp, *lp;
137 	register int nl;
138 
139 	lp = linebuf;
140 	bp = getblock(tl, READ);
141 	nl = nleft;
142 	tl &= ~OFFMSK;
143 	while (*lp++ = *bp++)
144 		if (--nl == 0) {
145 			bp = getblock(tl += INCRMT, READ);
146 			nl = nleft;
147 		}
148 }
149 
150 putline()
151 {
152 	register char *bp, *lp;
153 	register int nl;
154 	line tl;
155 
156 	dirtcnt++;
157 	lp = linebuf;
158 	change();
159 	tl = tline;
160 	bp = getblock(tl, WRITE);
161 	nl = nleft;
162 	tl &= ~OFFMSK;
163 	while (*bp = *lp++) {
164 		if (*bp++ == '\n') {
165 			*--bp = 0;
166 			linebp = lp;
167 			break;
168 		}
169 		if (--nl == 0) {
170 			bp = getblock(tl += INCRMT, WRITE);
171 			nl = nleft;
172 		}
173 	}
174 	tl = tline;
175 	tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
176 	return (tl);
177 }
178 
179 int	read();
180 int	write();
181 
182 char *
183 getblock(atl, iof)
184 	line atl;
185 	int iof;
186 {
187 	register int bno, off;
188 #ifdef CRYPT
189         register char *p1, *p2;
190         register int n;
191 #endif
192 
193 	bno = (atl >> OFFBTS) & BLKMSK;
194 	off = (atl << SHFT) & LBTMSK;
195 	if (bno >= NMBLKS)
196 		error(" Tmp file too large");
197 	nleft = BUFSIZ - off;
198 	if (bno == iblock) {
199 		ichanged |= iof;
200 		hitin2 = 0;
201 		return (ibuff + off);
202 	}
203 	if (bno == iblock2) {
204 		ichang2 |= iof;
205 		hitin2 = 1;
206 		return (ibuff2 + off);
207 	}
208 	if (bno == oblock)
209 		return (obuff + off);
210 	if (iof == READ) {
211 		if (hitin2 == 0) {
212 			if (ichang2) {
213 #ifdef CRYPT
214 				if(xtflag)
215 					crblock(tperm, ibuff2, CRSIZE, (long)0);
216 #endif
217 				blkio(iblock2, ibuff2, write);
218 			}
219 			ichang2 = 0;
220 			iblock2 = bno;
221 			blkio(bno, ibuff2, read);
222 #ifdef CRYPT
223 			if(xtflag)
224 				crblock(tperm, ibuff2, CRSIZE, (long)0);
225 #endif
226 			hitin2 = 1;
227 			return (ibuff2 + off);
228 		}
229 		hitin2 = 0;
230 		if (ichanged) {
231 #ifdef CRYPT
232 			if(xtflag)
233 				crblock(tperm, ibuff, CRSIZE, (long)0);
234 #endif
235 			blkio(iblock, ibuff, write);
236 		}
237 		ichanged = 0;
238 		iblock = bno;
239 		blkio(bno, ibuff, read);
240 #ifdef CRYPT
241 		if(xtflag)
242 			crblock(tperm, ibuff, CRSIZE, (long)0);
243 #endif
244 		return (ibuff + off);
245 	}
246 	if (oblock >= 0) {
247 #ifdef CRYPT
248 		if(xtflag) {
249 			/*
250 			 * Encrypt block before writing, so some devious
251 			 * person can't look at temp file while editing.
252 			 */
253 			p1 = obuff;
254 			p2 = crbuf;
255 			n = CRSIZE;
256 			while(n--)
257 				*p2++ = *p1++;
258 			crblock(tperm, crbuf, CRSIZE, (long)0);
259 			blkio(oblock, crbuf, write);
260 		} else
261 #endif
262 			blkio(oblock, obuff, write);
263 	}
264 	oblock = bno;
265 	return (obuff + off);
266 }
267 
268 #ifdef	VMUNIX
269 #ifdef	vms
270 #define	INCORB	32
271 #else
272 #define	INCORB	64
273 #endif
274 char	incorb[INCORB+1][BUFSIZ];
275 #define	pagrnd(a)	((char *)(((int)a)&~(BUFSIZ-1)))
276 int	stilinc;	/* up to here not written yet */
277 #endif
278 
279 blkio(b, buf, iofcn)
280 	short b;
281 	char *buf;
282 	int (*iofcn)();
283 {
284 
285 #ifdef VMUNIX
286 	if (b < INCORB) {
287 		if (iofcn == read) {
288 			bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ);
289 			return;
290 		}
291 		bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ);
292 		if (laste) {
293 			if (b >= stilinc)
294 				stilinc = b + 1;
295 			return;
296 		}
297 	} else if (stilinc)
298 		tflush();
299 #endif
300 	lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
301 	if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
302 		filioerr(tfname);
303 }
304 
305 #ifdef VMUNIX
306 tlaste()
307 {
308 
309 	if (stilinc)
310 		dirtcnt = 0;
311 }
312 
313 tflush()
314 {
315 	int i = stilinc;
316 
317 	stilinc = 0;
318 	lseek(tfile, (long) 0, 0);
319 	if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
320 		filioerr(tfname);
321 }
322 #endif
323 
324 /*
325  * Synchronize the state of the temporary file in case
326  * a crash occurs.
327  */
328 synctmp()
329 {
330 	register int cnt;
331 	register line *a;
332 	register short *bp;
333 
334 #ifdef VMUNIX
335 	if (stilinc)
336 		return;
337 #endif
338 	if (dol == zero)
339 		return;
340 	if (ichanged)
341 		blkio(iblock, ibuff, write);
342 	ichanged = 0;
343 	if (ichang2)
344 		blkio(iblock2, ibuff2, write);
345 	ichang2 = 0;
346 	if (oblock != -1)
347 		blkio(oblock, obuff, write);
348 	time(&H.Time);
349 	uid = getuid();
350 	*zero = (line) H.Time;
351 	for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
352 		if (*bp < 0) {
353 			tline = (tline + OFFMSK) &~ OFFMSK;
354 			*bp = ((tline >> OFFBTS) & BLKMSK);
355 			if (*bp > NMBLKS)
356 				error(" Tmp file too large");
357 			tline += INCRMT;
358 			oblock = *bp + 1;
359 			bp[1] = -1;
360 		}
361 		lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0);
362 		cnt = ((dol - a) + 2) * sizeof (line);
363 		if (cnt > BUFSIZ)
364 			cnt = BUFSIZ;
365 		if (write(tfile, (char *) a, cnt) != cnt) {
366 oops:
367 			*zero = 0;
368 			filioerr(tfname);
369 		}
370 		*zero = 0;
371 	}
372 	flines = lineDOL();
373 	lseek(tfile, 0l, 0);
374 	if (write(tfile, (char *) &H, sizeof H) != sizeof H)
375 		goto oops;
376 #ifdef notdef
377 	/*
378 	 * This will insure that exrecover gets as much
379 	 * back after a crash as is absolutely possible,
380 	 * but can result in pregnant pauses between commands
381 	 * when the TSYNC call is made, so...
382 	 */
383 #ifndef vms
384 	(void) fsync(tfile);
385 #endif
386 #endif
387 }
388 
389 TSYNC()
390 {
391 
392 	if (dirtcnt > MAXDIRT) {	/* mjm: 12 --> MAXDIRT */
393 #ifdef VMUNIX
394 		if (stilinc)
395 			tflush();
396 #endif
397 		dirtcnt = 0;
398 		synctmp();
399 	}
400 }
401 
402 /*
403  * Named buffer routines.
404  * These are implemented differently than the main buffer.
405  * Each named buffer has a chain of blocks in the register file.
406  * Each block contains roughly 508 chars of text,
407  * and a previous and next block number.  We also have information
408  * about which blocks came from deletes of multiple partial lines,
409  * e.g. deleting a sentence or a LISP object.
410  *
411  * We maintain a free map for the temp file.  To free the blocks
412  * in a register we must read the blocks to find how they are chained
413  * together.
414  *
415  * BUG:		The default savind of deleted lines in numbered
416  *		buffers may be rather inefficient; it hasn't been profiled.
417  */
418 struct	strreg {
419 	short	rg_flags;
420 	short	rg_nleft;
421 	short	rg_first;
422 	short	rg_last;
423 } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
424 
425 struct	rbuf {
426 	short	rb_prev;
427 	short	rb_next;
428 	char	rb_text[BUFSIZ - 2 * sizeof (short)];
429 } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
430 #ifdef VMUNIX
431 short	rused[256];
432 #else
433 short	rused[32];
434 #endif
435 short	rnleft;
436 short	rblock;
437 short	rnext;
438 char	*rbufcp;
439 
440 regio(b, iofcn)
441 	short b;
442 	int (*iofcn)();
443 {
444 
445 	if (rfile == -1) {
446 		CP(rfname, tfname);
447 		*(strend(rfname) - EPOSITION) = 'R';
448 		rfile = creat(rfname, 0600);
449 		if (rfile < 0)
450 oops:
451 			filioerr(rfname);
452 		else
453 			close(rfile);
454 		rfile = open(rfname, 2);
455 		if (rfile < 0)
456 			goto oops;
457 	}
458 	lseek(rfile, (long) b * BUFSIZ, 0);
459 	if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
460 		goto oops;
461 	rblock = b;
462 }
463 
464 REGblk()
465 {
466 	register int i, j, m;
467 
468 	for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
469 		m = (rused[i] ^ 0177777) & 0177777;
470 		if (i == 0)
471 			m &= ~1;
472 		if (m != 0) {
473 			j = 0;
474 			while ((m & 1) == 0)
475 				j++, m >>= 1;
476 			rused[i] |= (1 << j);
477 #ifdef RDEBUG
478 			ex_printf("allocating block %d\n", i * 16 + j);
479 #endif
480 			return (i * 16 + j);
481 		}
482 	}
483 	error("Out of register space (ugh)");
484 	/*NOTREACHED*/
485 }
486 
487 struct	strreg *
488 mapreg(c)
489 	register int c;
490 {
491 
492 	if (isupper(c))
493 		c = tolower(c);
494 	return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
495 }
496 
497 int	shread();
498 
499 KILLreg(c)
500 	register int c;
501 {
502 	register struct strreg *sp;
503 
504 	rbuf = &KILLrbuf;
505 	sp = mapreg(c);
506 	rblock = sp->rg_first;
507 	sp->rg_first = sp->rg_last = 0;
508 	sp->rg_flags = sp->rg_nleft = 0;
509 	while (rblock != 0) {
510 #ifdef RDEBUG
511 		ex_printf("freeing block %d\n", rblock);
512 #endif
513 		rused[rblock / 16] &= ~(1 << (rblock % 16));
514 		regio(rblock, shread);
515 		rblock = rbuf->rb_next;
516 	}
517 }
518 
519 /*VARARGS*/
520 shread()
521 {
522 	struct front { short a; short b; };
523 
524 	if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
525 		return (sizeof (struct rbuf));
526 	return (0);
527 }
528 
529 int	getREG();
530 
531 putreg(c)
532 	char c;
533 {
534 	register line *odot = dot;
535 	register line *odol = dol;
536 	register int cnt;
537 
538 	deletenone();
539 	appendnone();
540 	rbuf = &putrbuf;
541 	rnleft = 0;
542 	rblock = 0;
543 	rnext = mapreg(c)->rg_first;
544 	if (rnext == 0) {
545 		if (inopen) {
546 			splitw++;
547 			vclean();
548 			vgoto(WECHO, 0);
549 		}
550 		vreg = -1;
551 		error("Nothing in register %c", c);
552 	}
553 	if (inopen && partreg(c)) {
554 		if (!FIXUNDO) {
555 			splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
556 			error("Can't put partial line inside macro");
557 		}
558 		squish();
559 		addr1 = addr2 = dol;
560 	}
561 	cnt = append(getREG, addr2);
562 	if (inopen && partreg(c)) {
563 		unddol = dol;
564 		dol = odol;
565 		dot = odot;
566 		pragged(0);
567 	}
568 	killcnt(cnt);
569 	notecnt = cnt;
570 }
571 
572 partreg(c)
573 	char c;
574 {
575 
576 	return (mapreg(c)->rg_flags);
577 }
578 
579 notpart(c)
580 	register int c;
581 {
582 
583 	if (c)
584 		mapreg(c)->rg_flags = 0;
585 }
586 
587 getREG()
588 {
589 	register char *lp = linebuf;
590 	register int c;
591 
592 	for (;;) {
593 		if (rnleft == 0) {
594 			if (rnext == 0)
595 				return (EOF);
596 			regio(rnext, read);
597 			rnext = rbuf->rb_next;
598 			rbufcp = rbuf->rb_text;
599 			rnleft = sizeof rbuf->rb_text;
600 		}
601 		c = *rbufcp;
602 		if (c == 0)
603 			return (EOF);
604 		rbufcp++, --rnleft;
605 		if (c == '\n') {
606 			*lp++ = 0;
607 			return (0);
608 		}
609 		*lp++ = c;
610 	}
611 }
612 
613 YANKreg(c)
614 	register int c;
615 {
616 	register line *addr;
617 	register struct strreg *sp;
618 	char savelb[LBSIZE];
619 
620 	if (isdigit(c))
621 		kshift();
622 	if (islower(c))
623 		KILLreg(c);
624 	strp = sp = mapreg(c);
625 	sp->rg_flags = inopen && cursor && wcursor;
626 	rbuf = &YANKrbuf;
627 	if (sp->rg_last) {
628 		regio(sp->rg_last, read);
629 		rnleft = sp->rg_nleft;
630 		rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
631 	} else {
632 		rblock = 0;
633 		rnleft = 0;
634 	}
635 	CP(savelb,linebuf);
636 	for (addr = addr1; addr <= addr2; addr++) {
637 		getline(*addr);
638 		if (sp->rg_flags) {
639 			if (addr == addr2)
640 				*wcursor = 0;
641 			if (addr == addr1)
642 				strcpy(linebuf, cursor);
643 		}
644 		YANKline();
645 	}
646 	rbflush();
647 	killed();
648 	CP(linebuf,savelb);
649 }
650 
651 kshift()
652 {
653 	register int i;
654 
655 	KILLreg('9');
656 	for (i = '8'; i >= '0'; i--)
657 		copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
658 }
659 
660 YANKline()
661 {
662 	register char *lp = linebuf;
663 	register struct rbuf *rp = rbuf;
664 	register int c;
665 
666 	do {
667 		c = *lp++;
668 		if (c == 0)
669 			c = '\n';
670 		if (rnleft == 0) {
671 			rp->rb_next = REGblk();
672 			rbflush();
673 			rblock = rp->rb_next;
674 			rp->rb_next = 0;
675 			rp->rb_prev = rblock;
676 			rnleft = sizeof rp->rb_text;
677 			rbufcp = rp->rb_text;
678 		}
679 		*rbufcp++ = c;
680 		--rnleft;
681 	} while (c != '\n');
682 	if (rnleft)
683 		*rbufcp = 0;
684 }
685 
686 rbflush()
687 {
688 	register struct strreg *sp = strp;
689 
690 	if (rblock == 0)
691 		return;
692 	regio(rblock, write);
693 	if (sp->rg_first == 0)
694 		sp->rg_first = rblock;
695 	sp->rg_last = rblock;
696 	sp->rg_nleft = rnleft;
697 }
698 
699 /* Register c to char buffer buf of size buflen */
700 regbuf(c, buf, buflen)
701 char c;
702 char *buf;
703 int buflen;
704 {
705 	register char *p, *lp;
706 
707 	rbuf = &regrbuf;
708 	rnleft = 0;
709 	rblock = 0;
710 	rnext = mapreg(c)->rg_first;
711 	if (rnext==0) {
712 		*buf = 0;
713 		error("Nothing in register %c",c);
714 	}
715 	p = buf;
716 	while (getREG()==0) {
717 		for (lp=linebuf; *lp;) {
718 			if (p >= &buf[buflen])
719 				error("Register too long@to fit in memory");
720 			*p++ = *lp++;
721 		}
722 		*p++ = '\n';
723 	}
724 	if (partreg(c)) p--;
725 	*p = '\0';
726 	getDOT();
727 }
728 
729 /*
730  * Encryption routines.  These are essentially unmodified from ed.
731  */
732 
733 #ifdef CRYPT
734 /*
735  * crblock: encrypt/decrypt a block of text.
736  * buf is the buffer through which the text is both input and
737  * output. nchar is the size of the buffer. permp is a work
738  * buffer, and startn is the beginning of a sequence.
739  */
740 crblock(permp, buf, nchar, startn)
741 char *permp;
742 char *buf;
743 int nchar;
744 long startn;
745 {
746 	register char *p1;
747 	int n1;
748 	int n2;
749 	register char *t1, *t2, *t3;
750 
751 	t1 = permp;
752 	t2 = &permp[256];
753 	t3 = &permp[512];
754 
755 	n1 = startn&0377;
756 	n2 = (startn>>8)&0377;
757 	p1 = buf;
758 	while(nchar--) {
759 		*p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1;
760 		n1++;
761 		if(n1==256){
762 			n1 = 0;
763 			n2++;
764 			if(n2==256) n2 = 0;
765 		}
766 		p1++;
767 	}
768 }
769 
770 /*
771  * makekey: initialize buffers based on user key a.
772  */
773 makekey(a, b)
774 char *a, *b;
775 {
776        register int i;
777 	long t;
778 	char temp[KSIZE + 1];
779 
780 	for(i = 0; i < KSIZE; i++)
781 		temp[i] = *a++;
782 	time(&t);
783 	t += getpid();
784 	for(i = 0; i < 4; i++)
785 		temp[i] ^= (t>>(8*i))&0377;
786 	crinit(temp, b);
787 }
788 
789 /*
790  * crinit: besides initializing the encryption machine, this routine
791  * returns 0 if the key is null, and 1 if it is non-null.
792  */
793 crinit(keyp, permp)
794 char    *keyp, *permp;
795 {
796        register char *t1, *t2, *t3;
797 	register i;
798 	int ic, k, temp;
799 	unsigned random;
800 	char buf[13];
801 	long seed;
802 
803 	t1 = permp;
804 	t2 = &permp[256];
805 	t3 = &permp[512];
806 	if(*keyp == 0)
807 		return(0);
808 	strncpy(buf, keyp, 8);
809 	while (*keyp)
810 		*keyp++ = '\0';
811 
812 	buf[8] = buf[0];
813 	buf[9] = buf[1];
814 	domakekey(buf);
815 
816 	seed = 123;
817 	for (i=0; i<13; i++)
818 		seed = seed*buf[i] + i;
819 	for(i=0;i<256;i++){
820 		t1[i] = i;
821 		t3[i] = 0;
822 	}
823 	for(i=0; i<256; i++) {
824 		seed = 5*seed + buf[i%13];
825 		random = seed % 65521;
826 		k = 256-1 - i;
827 		ic = (random&0377) % (k+1);
828 		random >>= 8;
829 		temp = t1[k];
830 		t1[k] = t1[ic];
831 		t1[ic] = temp;
832 		if(t3[k]!=0) continue;
833 		ic = (random&0377) % k;
834 		while(t3[ic]!=0) ic = (ic+1) % k;
835 		t3[k] = ic;
836 		t3[ic] = k;
837 	}
838 	for(i=0; i<256; i++)
839 		t2[t1[i]&0377] = i;
840 	return(1);
841 }
842 
843 /*
844  * domakekey: the following is the major nonportable part of the encryption
845  * mechanism. A 10 character key is supplied in buffer.
846  * This string is fed to makekey (an external program) which
847  * responds with a 13 character result. This result is placed
848  * in buffer.
849  */
850 domakekey(buffer)
851 char *buffer;
852 {
853        int pf[2];
854 
855 	if (pipe(pf)<0)
856 		pf[0] = pf[1] = -1;
857 	if (fork()==0) {
858 		close(0);
859 		close(1);
860 		dup(pf[0]);
861 		dup(pf[1]);
862 		execl(_PATH_MAKEKEY, "-", 0);
863 		ex_exit(1);
864 	}
865 	write(pf[1], buffer, 10);
866 	if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13)
867 		error("crypt: cannot generate key");
868 	close(pf[0]);
869 	close(pf[1]);
870 	/* end of nonportable part */
871 }
872 #endif
873