xref: /plan9/sys/src/cmd/con/con.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include <u.h>
2 #include <libc.h>
3 
4 #include "rustream.h"
5 #include "ruttyio.h"
6 #include "rusignal.h"
7 #include "rufilio.h"
8 
9 int debug;		/* true if debugging */
10 int ctl = -1;		/* control fd (for break's) */
11 int raw;		/* true if raw is on */
12 int consctl = -1;	/* control fd for cons */
13 int ttypid;		/* pid's if the 2 processes (used to kill them) */
14 int msgfd = -1;		/* mesgld file descriptor (for signals to be written to) */
15 int outfd = 1;		/* local output file descriptor */
16 int cooked;		/* non-zero forces cooked mode */
17 int returns;		/* non-zero forces carriage returns not to be filtered out */
18 int crtonl;			/* non-zero forces carriage returns to be converted to nls coming from net */
19 int	strip;		/* strip off parity bits */
20 char firsterr[2*ERRMAX];
21 char transerr[2*ERRMAX];
22 int limited;
23 char *remuser;
24 int verbose;
25 int baud;
26 int notkbd;
27 int nltocr;		/* translate kbd nl to cr  and vice versa */
28 
29 typedef struct Msg Msg;
30 #define MAXMSG (2*8192)
31 
32 int	dodial(char*, char*, char*);
33 void	fromkbd(int);
34 void	fromnet(int);
35 long	iread(int, void*, int);
36 long	iwrite(int, void*, int);
37 int	menu(int);
38 void	msgfromkbd(int);
39 void	msgfromnet(int);
40 int	msgwrite(int, void*, int);
41 void	notifyf(void*, char*);
42 void	pass(int, int, int);
43 void	rawoff(void);
44 void	rawon(void);
45 int	readupto(int, char*, int);
46 int	sendctl(int, int);
47 int	sendctl1(int, int, int);
48 void	stdcon(int);
49 char*	system(int, char*);
50 void	dosystem(int, char*);
51 int	wasintr(void);
52 void	punt(char*);
53 char*	syserr(void);
54 void	seterr(char*);
55 
56 /* protocols */
57 void	device(char*, char*);
58 void	rlogin(char*, char*);
59 void	simple(char*, char*);
60 
61 void
62 usage(void)
63 {
64 	punt("usage: con [-drCvsn] [-l [user]] [-c cmd] net!host[!service]");
65 }
66 
67 void
68 main(int argc, char *argv[])
69 {
70 	char *dest;
71 	char *cmd = 0;
72 
73 	returns = 1;
74 	ARGBEGIN{
75 	case 'b':
76 		baud = atoi(ARGF());
77 		break;
78 	case 'd':
79 		debug = 1;
80 		break;
81 	case 'l':
82 		limited = 1;
83 		if(argv[1] != nil && argv[1][0] != '-')
84 			remuser = ARGF();
85 		break;
86 	case 'n':
87 		notkbd = 1;
88 		break;
89 	case 'r':
90 		returns = 0;
91 		break;
92 	case 'R':
93 		nltocr = 1;
94 		break;
95 	case 'T':
96 		crtonl = 1;
97 		break;
98 	case 'C':
99 		cooked = 1;
100 		break;
101 	case 'c':
102 		cmd = ARGF();
103 		break;
104 	case 'v':
105 		verbose = 1;
106 		break;
107 	case 's':
108 		strip = 1;
109 		break;
110 	default:
111 		usage();
112 	}ARGEND
113 
114 	if(argc != 1){
115 		if(remuser == 0)
116 			usage();
117 		dest = remuser;
118 		remuser = 0;
119 	} else
120 		dest = argv[0];
121 	if(*dest == '/' && strchr(dest, '!') == 0)
122 		device(dest, cmd);
123 	else if(limited){
124 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
125 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
126 	} else {
127 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
128 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
129 	}
130 	punt(firsterr);
131 }
132 
133 /*
134  *  just dial and use as a byte stream with remote echo
135  */
136 void
137 simple(char *dest, char *cmd)
138 {
139 	int net;
140 
141 	net = dodial(dest, 0, 0);
142 	if(net < 0)
143 		return;
144 
145 	if(cmd)
146 		dosystem(net, cmd);
147 
148 	if(!cooked)
149 		rawon();
150 	stdcon(net);
151 	exits(0);
152 }
153 
154 /*
155  *  dial, do UCB authentication, use as a byte stream with local echo
156  *
157  *  return if dial failed
158  */
159 void
160 rlogin(char *dest, char *cmd)
161 {
162 	int net;
163 	char buf[128];
164 	char *p;
165 	char *localuser;
166 
167 	/* only useful on TCP */
168 	if(strchr(dest, '!')
169 	&& (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))
170 		return;
171 
172 	net = dodial(dest, "tcp", "login");
173 	if(net < 0)
174 		return;
175 
176 	/*
177 	 *  do UCB rlogin authentication
178 	 */
179 	localuser = getuser();
180 	if(remuser == 0){
181 		if(limited)
182 			remuser = ":";
183 		else
184 			remuser = localuser;
185 	}
186 	p = getenv("TERM");
187 	if(p == 0)
188 		p = "p9";
189 	if(write(net, "", 1)<0
190 	|| write(net, localuser, strlen(localuser)+1)<0
191 	|| write(net, remuser, strlen(remuser)+1)<0
192 	|| write(net, p, strlen(p)+1)<0){
193 		close(net);
194 		punt("BSD authentication failed");
195 	}
196 	if(read(net, buf, 1) != 1)
197 		punt("BSD authentication failed1");
198 	if(buf[0] != 0){
199 		fprint(2, "con: remote error: ");
200 		while(read(net, buf, 1) == 1){
201 			write(2, buf, 1);
202 			if(buf[0] == '\n')
203 				break;
204 		}
205 		exits("read");
206 	}
207 
208 	if(cmd)
209 		dosystem(net, cmd);
210 
211 	if(!cooked)
212 		rawon();
213 	nltocr = 1;
214 	stdcon(net);
215 	exits(0);
216 }
217 
218 /*
219  *  just open a device and use it as a connection
220  */
221 void
222 device(char *dest, char *cmd)
223 {
224 	int net;
225 	char cname[128];
226 
227 	net = open(dest, ORDWR);
228 	if(net < 0) {
229 		fprint(2, "con: cannot open %s: %r\n", dest);
230 		exits("open");
231 	}
232 	snprint(cname, sizeof cname, "%sctl", dest);
233 	ctl = open(cname, ORDWR);
234 	if (baud > 0) {
235 		if(ctl >= 0)
236 			fprint(ctl, "b%d", baud);
237 		else
238 			fprint(2, "con: cannot open %s: %r\n", cname);
239 	}
240 
241 	if(cmd)
242 		dosystem(net, cmd);
243 
244 	if(!cooked)
245 		rawon();
246 	stdcon(net);
247 	exits(0);
248 }
249 
250 /*
251  *  ignore interrupts
252  */
253 void
254 notifyf(void *a, char *msg)
255 {
256 	USED(a);
257 
258 	if(strstr(msg, "yankee"))
259 		noted(NDFLT);
260 	if(strstr(msg, "closed pipe")
261 	|| strcmp(msg, "interrupt") == 0
262 	|| strcmp(msg, "hangup") == 0)
263 		noted(NCONT);
264 	noted(NDFLT);
265 }
266 
267 /*
268  *  turn keyboard raw mode on
269  */
270 void
271 rawon(void)
272 {
273 	if(debug)
274 		fprint(2, "rawon\n");
275 	if(raw)
276 		return;
277 	if(consctl < 0)
278 		consctl = open("/dev/consctl", OWRITE);
279 	if(consctl < 0){
280 //		fprint(2, "can't open consctl\n");
281 		return;
282 	}
283 	write(consctl, "rawon", 5);
284 	raw = 1;
285 }
286 
287 /*
288  *  turn keyboard raw mode off
289  */
290 void
291 rawoff(void)
292 {
293 	if(debug)
294 		fprint(2, "rawoff\n");
295 	if(raw == 0)
296 		return;
297 	if(consctl < 0)
298 		consctl = open("/dev/consctl", OWRITE);
299 	if(consctl < 0){
300 //		fprint(2, "can't open consctl\n");
301 		return;
302 	}
303 	write(consctl, "rawoff", 6);
304 	raw = 0;
305 }
306 
307 /*
308  *  control menu
309  */
310 #define STDHELP	"\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
311 
312 int
313 menu(int net)
314 {
315 	char buf[MAXMSG];
316 	long n;
317 	int done;
318 	int wasraw = raw;
319 
320 	if(wasraw)
321 		rawoff();
322 
323 	fprint(2, ">>> ");
324 	for(done = 0; !done; ){
325 		n = read(0, buf, sizeof(buf)-1);
326 		if(n <= 0)
327 			return -1;
328 		buf[n] = 0;
329 		switch(buf[0]){
330 		case '!':
331 			print(buf);
332 			system(net, buf+1);
333 			print("!\n");
334 			done = 1;
335 			break;
336 		case '.':
337 			done = 1;
338 			break;
339 		case 'q':
340 			return -1;
341 			break;
342 		case 'i':
343 			buf[0] = 0x1c;
344 			if(msgfd <= 0)
345 				write(net, buf, 1);
346 			else
347 				sendctl1(msgfd, M_SIGNAL, SIGQUIT);
348 			done = 1;
349 			break;
350 		case 'b':
351 			if(msgfd >= 0)
352 				sendctl(msgfd, M_BREAK);
353 			else if(ctl >= 0)
354 				write(ctl, "k", 1);
355 			done = 1;
356 			break;
357 		case 'r':
358 			returns = 1-returns;
359 			done = 1;
360 			break;
361 		default:
362 			fprint(2, STDHELP);
363 			break;
364 		}
365 		if(!done)
366 			fprint(2, ">>> ");
367 	}
368 
369 	if(wasraw)
370 		rawon();
371 	else
372 		rawoff();
373 	return 0;
374 }
375 
376 /*
377  *  the real work.  two processes pass bytes back and forth between the
378  *  terminal and the network.
379  */
380 void
381 stdcon(int net)
382 {
383 	int netpid;
384 
385 	ttypid = getpid();
386 	switch(netpid = rfork(RFMEM|RFPROC)){
387 	case -1:
388 		perror("con");
389 		exits("fork");
390 	case 0:
391 		notify(notifyf);
392 		fromnet(net);
393 		postnote(PNPROC, ttypid, "die yankee dog");
394 		exits(0);
395 	default:
396 		notify(notifyf);
397 		fromkbd(net);
398 		if(notkbd)
399 			for(;;)sleep(0);
400 		postnote(PNPROC, netpid, "die yankee dog");
401 		exits(0);
402 	}
403 }
404 
405 /*
406  *  Read the keyboard and write it to the network.  '^\' gets us into
407  *  the menu.
408  */
409 void
410 fromkbd(int net)
411 {
412 	long n;
413 	char buf[MAXMSG];
414 	char *p, *ep;
415 	int eofs;
416 
417 	eofs = 0;
418 	for(;;){
419 		n = read(0, buf, sizeof(buf));
420 		if(n < 0){
421 			if(wasintr()){
422 				if(!raw){
423 					buf[0] = 0x7f;
424 					n = 1;
425 				} else
426 					continue;
427 			} else
428 				return;
429 		}
430 		if(n == 0){
431 			if(++eofs > 32)
432 				return;
433 		} else
434 			eofs = 0;
435 		if(n && memchr(buf, 0x1c, n)){
436 			if(menu(net) < 0)
437 				return;
438 		}else{
439 			if(!raw && n==0){
440 				buf[0] = 0x4;
441 				n = 1;
442 			}
443 			if(nltocr){
444 				ep = buf+n;
445 				for(p = buf; p < ep; p++)
446 					switch(*p){
447 					case '\r':
448 						*p = '\n';
449 						break;
450 					case '\n':
451 						*p = '\r';
452 						break;
453 					}
454 			}
455 			if(iwrite(net, buf, n) != n)
456 				return;
457 		}
458 	}
459 }
460 
461 /*
462  *  Read from the network and write to the screen.
463  *  Filter out spurious carriage returns.
464  */
465 void
466 fromnet(int net)
467 {
468 	long n;
469 	char buf[MAXMSG];
470 	char *cp, *ep;
471 
472 	for(;;){
473 		n = iread(net, buf, sizeof(buf));
474 		if(n < 0)
475 			return;
476 		if(n == 0)
477 			continue;
478 
479 		if (strip)
480 			for (cp=buf; cp<buf+n; cp++)
481 				*cp &= 0177;
482 
483 		if(crtonl) {
484 			/* convert cr's to nl's */
485 			for (cp = buf; cp < buf + n; cp++)
486 				if (*cp == '\r')
487 					*cp = '\n';
488 		}
489 		else if(!returns){
490 			/* convert cr's to null's */
491 			cp = buf;
492 			ep = buf + n;
493 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
494 				memmove(cp, cp+1, ep-cp-1);
495 				ep--;
496 				n--;
497 			}
498 		}
499 
500 		if(n > 0 && iwrite(outfd, buf, n) != n){
501 			if(outfd == 1)
502 				return;
503 			outfd = 1;
504 			if(iwrite(1, buf, n) != n)
505 				return;
506 		}
507 	}
508 }
509 
510 /*
511  *  dial and return a data connection
512  */
513 int
514 dodial(char *dest, char *net, char *service)
515 {
516 	char name[128];
517 	char devdir[128];
518 	int data;
519 
520 	devdir[0] = 0;
521 	strcpy(name, netmkaddr(dest, net, service));
522 	data = dial(name, 0, devdir, &ctl);
523 	if(data < 0){
524 		seterr(name);
525 		return -1;
526 	}
527 	fprint(2, "connected to %s on %s\n", name, devdir);
528 	return data;
529 }
530 
531 void
532 dosystem(int fd, char *cmd)
533 {
534 	char *p;
535 
536 	p = system(fd, cmd);
537 	if(*p){
538 		print("con: %s terminated with %s\n", cmd, p);
539 		exits(p);
540 	}
541 }
542 
543 /*
544  *  run a command with the network connection as standard IO
545  */
546 char *
547 system(int fd, char *cmd)
548 {
549 	int pid;
550 	int p;
551 	static Waitmsg msg;
552 	int pfd[2];
553 	int n;
554 	char buf[4096];
555 
556 	if(pipe(pfd) < 0){
557 		perror("pipe");
558 		return "pipe failed";
559 	}
560 	outfd = pfd[1];
561 
562 	close(consctl);
563 	consctl = -1;
564 	switch(pid = fork()){
565 	case -1:
566 		perror("con");
567 		return "fork failed";
568 	case 0:
569 		close(pfd[1]);
570 		dup(pfd[0], 0);
571 		dup(fd, 1);
572 		close(ctl);
573 		close(fd);
574 		close(pfd[0]);
575 		if(*cmd)
576 			execl("/bin/rc", "rc", "-c", cmd, 0);
577 		else
578 			execl("/bin/rc", "rc", 0);
579 		perror("con");
580 		exits("exec");
581 		break;
582 	default:
583 		close(pfd[0]);
584 		while((n = read(pfd[1], buf, sizeof(buf))) > 0){
585 			if(msgfd >= 0){
586 				if(msgwrite(fd, buf, n) != n)
587 					break;
588 			} else {
589 				if(write(fd, buf, n) != n)
590 					break;
591 			}
592 		}
593 		p = waitpid();
594 		outfd = 1;
595 		close(pfd[1]);
596 		if(p < 0 || p != pid)
597 			return "lost child";
598 		break;
599 	}
600 	return msg.msg;
601 }
602 
603 int
604 wasintr(void)
605 {
606 	return strcmp(syserr(), "interrupted") == 0;
607 }
608 
609 void
610 punt(char *msg)
611 {
612 	if(*msg == 0)
613 		msg = transerr;
614 	fprint(2, "con: %s\n", msg);
615 	exits(msg);
616 }
617 
618 char*
619 syserr(void)
620 {
621 	static char err[ERRMAX];
622 	errstr(err, sizeof err);
623 	return err;
624 }
625 
626 void
627 seterr(char *addr)
628 {
629 	char *se = syserr();
630 
631 	if(verbose)
632 		fprint(2, "'%s' calling %s\n", se, addr);
633 	if(firsterr[0] && (strstr(se, "translate") ||
634 	 strstr(se, "file does not exist") ||
635 	 strstr(se, "unknown address") ||
636 	 strstr(se, "directory entry not found")))
637 		return;
638 	strcpy(firsterr, se);
639 }
640 
641 
642 long
643 iread(int f, void *a, int n)
644 {
645 	long m;
646 
647 	for(;;){
648 		m = read(f, a, n);
649 		if(m >= 0 || !wasintr())
650 			break;
651 	}
652 	return m;
653 }
654 
655 long
656 iwrite(int f, void *a, int n)
657 {
658 	long m;
659 
660 	m = write(f, a, n);
661 	if(m < 0 && wasintr())
662 		return n;
663 	return m;
664 }
665 
666 /*
667  *  The rest is to support the V10 mesgld protocol.
668  */
669 
670 /*
671  *  network orderings
672  */
673 #define get2byte(p) ((p)[0] + ((p)[1]<<8))
674 #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
675 #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
676 #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
677 
678 /*
679  *  tty parameters
680  */
681 int sgflags = ECHO;
682 
683 /*
684  *  a mesgld message
685  */
686 struct Msg {
687 	struct mesg h;
688 	char b[MAXMSG];
689 };
690 
691 
692 /*
693  *  send an empty mesgld message
694  */
695 int
696 sendctl(int net, int type)
697 {
698 	Msg m;
699 
700 	m.h.type = type;
701 	m.h.magic = MSGMAGIC;
702 	put2byte(m.h.size, 0);
703 	if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
704 		return -1;
705 	return 0;
706 }
707 
708 /*
709  *  send a one byte mesgld message
710  */
711 int
712 sendctl1(int net, int type, int parm)
713 {
714 	Msg m;
715 
716 	m.h.type = type;
717 	m.h.magic = MSGMAGIC;
718 	m.b[0] = parm;
719 	put2byte(m.h.size, 1);
720 	if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
721 		return -1;
722 	return 0;
723 }
724 
725 /*
726  *  read n bytes.  return -1 if it fails, 0 otherwise.
727  */
728 int
729 readupto(int from, char *a, int len)
730 {
731 	int n;
732 
733 	while(len > 0){
734 		n = iread(from, a, len);
735 		if(n < 0)
736 			return -1;
737 		a += n;
738 		len -= n;
739 	}
740 	return 0;
741 }
742 
743 /*
744  *  Decode a mesgld message from the network
745  */
746 void
747 msgfromnet(int net)
748 {
749 	ulong com;
750 	struct stioctl *io;
751 	struct sgttyb *sg;
752 	struct ttydevb *td;
753 	struct tchars *tc;
754 	int len;
755 	Msg m;
756 
757 	for(;;){
758 		/* get a complete mesgld message */
759 		if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
760 			break;
761 		if(m.h.magic != MSGMAGIC){
762 			fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
763 			break;
764 		}
765 		len = get2byte(m.h.size);
766 		if(len > sizeof(m.b)){
767 			len = sizeof(m.b);
768 			fprint(2, "con: mesgld message too long\n");
769 		}
770 		if(len && readupto(net, m.b, len) < 0)
771 			break;
772 
773 		/* decode */
774 		switch(m.h.type){
775 		case M_HANGUP:
776 			if(debug)
777 				fprint(2, "M_HANGUP\n");
778 			return;
779 		case M_DATA:
780 			if(debug)
781 				fprint(2, "M_DATA %d bytes\n", len);
782 			if(iwrite(outfd, m.b, len) != len){
783 				if(outfd == 1)
784 					return;
785 				outfd = 1;
786 				if(iwrite(outfd, m.b, len) != len)
787 					return;
788 			}
789 			continue;
790 		case M_IOCTL:
791 			break;
792 		default:
793 			/* ignore */
794 			if(debug)
795 				fprint(2, "con: unknown message\n");
796 			continue;
797 		}
798 
799 		/*
800 		 *  answer an ioctl
801 		 */
802 		io = (struct stioctl *)m.b;
803 		com = get4byte(io->com);
804 		if(debug)
805 			fprint(2, "M_IOCTL %lud\n", com);
806 		switch(com){
807 		case FIOLOOKLD:
808 			put4byte(io->data, tty_ld);
809 			len = 0;
810 			break;
811 		case TIOCGETP:
812 			sg = (struct sgttyb *)io->data;
813 			sg->sg_ispeed = sg->sg_ospeed = B9600;
814 			sg->sg_erase = 0010;	/* back space */
815 			sg->sg_kill = 0025;	/* CNTL U */
816 			put2byte(sg->sg_flags, sgflags);
817 			len = sizeof(struct sgttyb);
818 			break;
819 		case TIOCSETN:
820 		case TIOCSETP:
821 			sg = (struct sgttyb *)io->data;
822 			sgflags = get2byte(sg->sg_flags);
823 			if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
824 				rawon();
825 			else
826 				rawoff();
827 			len = 0;
828 			break;
829 		case TIOCGETC:
830 			tc = (struct tchars *)io->data;
831 			tc->t_intrc = 0177;
832 			tc->t_quitc = 0034;
833 			tc->t_startc = 0;
834 			tc->t_stopc = 0;
835 			tc->t_eofc = 0004;
836 			tc->t_brkc = 0;
837 			len = sizeof(struct tchars);
838 			break;
839 		case TIOCSETC:
840 			len = 0;
841 			break;
842 		case TIOCGDEV:
843 			td = (struct ttydevb *)io->data;
844 			td->ispeed = td->ospeed = B9600;
845 			put2byte(td->flags, 0);
846 			len = sizeof(struct ttydevb);
847 			break;
848 		case TIOCSDEV:
849 			len = 0;
850 			break;
851 		default:
852 			/*
853 			 *  unimplemented
854 			 */
855 			m.b[len] = 0;
856 			if(sendctl(net, M_IOCNAK) < 0)
857 				return;
858 			continue;
859 		}
860 
861 		/*
862 		 *  acknowledge
863 		 */
864 		m.h.type = M_IOCACK;
865 		m.h.magic = MSGMAGIC;
866 		len += 4;
867 		put2byte(m.h.size, len);
868 		len += sizeof(struct mesg);
869 		if(iwrite(net, &m, len) != len)
870 			return;
871 	}
872 }
873 
874 /*
875  *  Read the keyboard, convert to mesgld messages, and write it to the network.
876  *  '^\' gets us into the menu.
877  */
878 void
879 msgfromkbd(int net)
880 {
881 	long n;
882 	char buf[MAXMSG];
883 
884 	for(;;){
885 		n = iread(0, buf, sizeof(buf));
886 		if(n < 0)
887 			return;
888 		if(n && memchr(buf, 0034, n)){
889 			if(menu(net) < 0)
890 				return;
891 		} else {
892 			if(msgwrite(net, buf, n) != n)
893 				return;
894 		}
895 	}
896 }
897 
898 int
899 msgwrite(int fd, void *buf, int len)
900 {
901 	Msg m;
902 	int n;
903 
904 	n = len;
905 	memmove(m.b, buf, n);
906 	put2byte(m.h.size, n);
907 	m.h.magic = MSGMAGIC;
908 	m.h.type = M_DATA;
909 	n += sizeof(struct mesg);
910 	if(iwrite(fd, &m, n) != n)
911 		return -1;
912 
913 	put2byte(m.h.size, 0);
914 	m.h.magic = MSGMAGIC;
915 	m.h.type = M_DELIM;
916 	n = sizeof(struct mesg);
917 	if(iwrite(fd, &m, n) != n)
918 		return -1;
919 
920 	return len;
921 }
922 
923