GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tftp/main.c Lines: 0 345 0.0 %
Date: 2016-12-06 Branches: 0 228 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: main.c,v 1.40 2016/03/16 15:41:11 krw Exp $	*/
2
/*	$NetBSD: main.c,v 1.6 1995/05/21 16:54:10 mycroft Exp $	*/
3
4
/*
5
 * Copyright (c) 1983, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * TFTP User Program -- Command Interface
35
 *
36
 * This version includes many modifications by Jim Guyton <guyton@rand-unix>
37
 */
38
39
#include <sys/socket.h>
40
#include <sys/file.h>
41
42
#include <netinet/in.h>
43
#include <arpa/inet.h>
44
#include <arpa/tftp.h>
45
46
#include <ctype.h>
47
#include <err.h>
48
#include <errno.h>
49
#include <netdb.h>
50
#include <poll.h>
51
#include <signal.h>
52
#include <stdio.h>
53
#include <stdlib.h>
54
#include <string.h>
55
#include <unistd.h>
56
#include <limits.h>
57
58
#include "extern.h"
59
60
#define	LBUFLEN		200		/* size of input buffer */
61
#define	MAXARGV		20
62
#define HELPINDENT	(sizeof("connect"))
63
64
void			 get(int, char **);
65
void			 help(int, char **);
66
void			 modecmd(int, char **);
67
void			 put(int, char **);
68
void			 quit(int, char **);
69
void			 setascii(int, char **);
70
void			 setbinary(int, char **);
71
void			 setpeer(char *, char *);
72
void			 parsearg(int, char **);
73
void			 setrexmt(int, char **);
74
void			 settimeout(int, char **);
75
void			 settrace(int, char **);
76
void			 setverbose(int, char **);
77
void			 settsize(int, char **);
78
void			 settout(int, char **);
79
void			 setblksize(int, char **);
80
void			 status(int, char **);
81
int			 readcmd(char *, int, FILE *);
82
static void		 getusage(char *);
83
static int		 makeargv(void);
84
static void		 putusage(char *);
85
static void		 settftpmode(char *);
86
static __dead void	 command(void);
87
struct cmd	 	*getcmd(char *);
88
char			*tail(char *);
89
90
struct sockaddr_storage	 peeraddr;
91
int			 f;
92
int			 trace;
93
int			 verbose;
94
int			 connected;
95
char			 mode[32];
96
char			 line[LBUFLEN];
97
int			 margc;
98
char			*margv[MAXARGV+1];
99
char			*prompt = "tftp";
100
void			 intr(int);
101
int	 		 rexmtval = TIMEOUT;
102
int	 		 maxtimeout = 5 * TIMEOUT;
103
char	 		 hostname[HOST_NAME_MAX+1];
104
FILE			*file = NULL;
105
volatile sig_atomic_t	 intrflag = 0;
106
char			*ackbuf;
107
int			 has_options = 0;
108
int			 opt_tsize = 0;
109
int			 opt_tout = 0;
110
int			 opt_blksize = 0;
111
112
char	vhelp[] = "toggle verbose mode";
113
char	thelp[] = "toggle packet tracing";
114
char	chelp[] = "connect to remote tftp";
115
char	qhelp[] = "exit tftp";
116
char	hhelp[] = "print help information";
117
char	shelp[] = "send file";
118
char	rhelp[] = "receive file";
119
char	mhelp[] = "set file transfer mode";
120
char	sthelp[] = "show current status";
121
char	xhelp[] = "set per-packet retransmission timeout";
122
char	ihelp[] = "set total retransmission timeout";
123
char	ashelp[] = "set mode to netascii";
124
char	bnhelp[] = "set mode to octet";
125
char	oshelp[] = "toggle tsize option";
126
char	othelp[] = "toggle timeout option";
127
char	obhelp[] = "set alternative blksize option";
128
129
struct cmd {
130
	char	*name;
131
	char	*help;
132
	void	 (*handler)(int, char **);
133
};
134
135
struct cmd cmdtab[] = {
136
	{ "connect",	chelp,	parsearg },
137
	{ "mode",       mhelp,	modecmd },
138
	{ "put",	shelp,	put },
139
	{ "get",	rhelp,	get },
140
	{ "quit",	qhelp,	quit },
141
	{ "verbose",	vhelp,	setverbose },
142
	{ "trace",	thelp,	settrace },
143
	{ "status",	sthelp,	status },
144
	{ "binary",     bnhelp,	setbinary },
145
	{ "ascii",      ashelp,	setascii },
146
	{ "rexmt",	xhelp,	setrexmt },
147
	{ "timeout",	ihelp,	settimeout },
148
	{ "tsize",	oshelp, settsize },
149
	{ "tout",	othelp, settout },
150
	{ "blksize",	obhelp,	setblksize },
151
	{ "help",	hhelp,	help },
152
	{ "?",		hhelp,	help },
153
	{ NULL,		NULL,	NULL }
154
};
155
156
struct	modes {
157
	char	*m_name;
158
	char	*m_mode;
159
} modes[] = {
160
	{ "ascii",	"netascii" },
161
	{ "netascii",	"netascii" },
162
	{ "binary",	"octet" },
163
	{ "image",	"octet" },
164
	{ "octet",	"octet" },
165
/*	{ "mail",	"mail" }, */
166
	{ NULL,		NULL }
167
};
168
169
int
170
main(int argc, char *argv[])
171
{
172
	f = -1;
173
174
	if (pledge("stdio rpath wpath cpath dns inet", NULL) == -1)
175
		err(1, "pledge");
176
177
	/* set default transfer mode */
178
	strlcpy(mode, "netascii", sizeof(mode));
179
180
	/* set peer if given */
181
	if (argc > 1)
182
		parsearg(argc, argv);
183
184
	/* catch SIGINT */
185
	signal(SIGINT, intr);
186
187
	/* allocate memory for packets */
188
	if ((ackbuf = malloc(SEGSIZE_MAX + 4)) == NULL)
189
		err(1, "malloc");
190
191
	/* command prompt */
192
	command();
193
194
	return (0);
195
}
196
197
void
198
setpeer(char *host, char *port)
199
{
200
	struct addrinfo hints, *res0, *res;
201
	int error;
202
	struct sockaddr_storage ss;
203
	char *cause = "unknown";
204
205
	if (connected) {
206
		close(f);
207
		f = -1;
208
	}
209
	connected = 0;
210
211
	memset(&hints, 0, sizeof(hints));
212
	hints.ai_family = PF_UNSPEC;
213
	hints.ai_socktype = SOCK_DGRAM;
214
	hints.ai_protocol = IPPROTO_UDP;
215
	hints.ai_flags = AI_CANONNAME;
216
	if (!port)
217
		port = "tftp";
218
	error = getaddrinfo(host, port, &hints, &res0);
219
	if (error) {
220
		warnx("%s", gai_strerror(error));
221
		return;
222
	}
223
224
	for (res = res0; res; res = res->ai_next) {
225
		if (res->ai_addrlen > sizeof(peeraddr))
226
			continue;
227
		f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
228
		if (f < 0) {
229
			cause = "socket";
230
			continue;
231
		}
232
233
		memset(&ss, 0, sizeof(ss));
234
		ss.ss_family = res->ai_family;
235
		ss.ss_len = res->ai_addrlen;
236
		if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
237
			cause = "bind";
238
			close(f);
239
			f = -1;
240
			continue;
241
		}
242
243
		break;
244
	}
245
246
	if (f < 0)
247
		warn("%s", cause);
248
	else {
249
		/* res->ai_addr <= sizeof(peeraddr) is guaranteed */
250
		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
251
		if (res->ai_canonname) {
252
			(void)strlcpy(hostname, res->ai_canonname,
253
			    sizeof(hostname));
254
		} else
255
			(void)strlcpy(hostname, host, sizeof(hostname));
256
			connected = 1;
257
	}
258
	freeaddrinfo(res0);
259
}
260
261
void
262
parsearg(int argc, char *argv[])
263
{
264
	if (argc < 2) {
265
		strlcpy(line, "Connect ", sizeof(line));
266
		printf("(to) ");
267
		readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
268
		if (makeargv())
269
			return;
270
		argc = margc;
271
		argv = margv;
272
	}
273
	if ((argc < 2) || (argc > 3)) {
274
		printf("usage: %s [host [port]]\n", argv[0]);
275
		return;
276
	}
277
	if (argc == 2)
278
		setpeer(argv[1], NULL);
279
	else
280
		setpeer(argv[1], argv[2]);
281
}
282
283
void
284
modecmd(int argc, char *argv[])
285
{
286
	struct modes	*p;
287
	char		*sep;
288
289
	if (argc < 2) {
290
		printf("Using %s mode to transfer files.\n", mode);
291
		return;
292
	}
293
	if (argc == 2) {
294
		for (p = modes; p->m_name != NULL; p++)
295
			if (strcmp(argv[1], p->m_name) == 0)
296
				break;
297
		if (p->m_name) {
298
			settftpmode(p->m_mode);
299
			return;
300
		}
301
		printf("%s: unknown mode\n", argv[1]);
302
		/* drop through and print usage message */
303
	}
304
305
	printf("usage: %s [", argv[0]);
306
	sep = " ";
307
	for (p = modes; p->m_name != NULL; p++) {
308
		printf("%s%s", sep, p->m_name);
309
		if (*sep == ' ')
310
			sep = " | ";
311
	}
312
	printf(" ]\n");
313
314
	return;
315
}
316
317
/* ARGSUSED */
318
void
319
setbinary(int argc, char *argv[])
320
{
321
	settftpmode("octet");
322
}
323
324
/* ARGSUSED */
325
void
326
setascii(int argc, char *argv[])
327
{
328
	settftpmode("netascii");
329
}
330
331
static void
332
settftpmode(char *newmode)
333
{
334
	strlcpy(mode, newmode, sizeof(mode));
335
	if (verbose)
336
		printf("mode set to %s\n", mode);
337
}
338
339
/*
340
 * Send file(s).
341
 */
342
void
343
put(int argc, char *argv[])
344
{
345
	int	 fd;
346
	int	 n;
347
	char	*cp, *targ;
348
349
	if (argc < 2) {
350
		strlcpy(line, "put ", sizeof(line));
351
		printf("(file) ");
352
		readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
353
		if (makeargv())
354
			return;
355
		argc = margc;
356
		argv = margv;
357
	}
358
	if (argc < 2) {
359
		putusage(argv[0]);
360
		return;
361
	}
362
	targ = argv[argc - 1];
363
	if (strrchr(argv[argc - 1], ':')) {
364
365
		for (n = 1; n < argc - 1; n++)
366
			if (strchr(argv[n], ':')) {
367
				putusage(argv[0]);
368
				return;
369
			}
370
		cp = argv[argc - 1];
371
		targ = strrchr(cp, ':');
372
		*targ++ = 0;
373
		if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
374
			cp[strlen(cp) - 1] = '\0';
375
			cp++;
376
		}
377
		setpeer(cp, NULL);
378
	}
379
	if (!connected) {
380
		printf("No target machine specified.\n");
381
		return;
382
	}
383
	if (argc < 4) {
384
		cp = argc == 2 ? tail(targ) : argv[1];
385
		fd = open(cp, O_RDONLY);
386
		if (fd < 0) {
387
			warn("open: %s", cp);
388
			return;
389
		}
390
		if (verbose)
391
			printf("putting %s to %s:%s [%s]\n",
392
			    cp, hostname, targ, mode);
393
		sendfile(fd, targ, mode);
394
		return;
395
	}
396
397
	/*
398
	 * this assumes the target is a directory on
399
	 * on a remote unix system.  hmmmm.
400
	 */
401
	for (n = 1; n < argc - 1; n++) {
402
		if (asprintf(&cp, "%s/%s", targ, tail(argv[n])) == -1)
403
			err(1, "asprintf");
404
		fd = open(argv[n], O_RDONLY);
405
		if (fd < 0) {
406
			warn("open: %s", argv[n]);
407
			free(cp);
408
			continue;
409
		}
410
		if (verbose)
411
			printf("putting %s to %s:%s [%s]\n",
412
			    argv[n], hostname, cp, mode);
413
		sendfile(fd, cp, mode);
414
		free(cp);
415
	}
416
}
417
418
static void
419
putusage(char *s)
420
{
421
	printf("usage: %s file [[host:]remotename]\n", s);
422
	printf("       %s file1 file2 ... fileN [[host:]remote-directory]\n",
423
	    s);
424
}
425
426
/*
427
 * Receive file(s).
428
 */
429
void
430
get(int argc, char *argv[])
431
{
432
	int	 fd;
433
	int	 n;
434
	char	*cp;
435
	char	*src;
436
437
	if (argc < 2) {
438
		strlcpy(line, "get ", sizeof(line));
439
		printf("(files) ");
440
		readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
441
		if (makeargv())
442
			return;
443
		argc = margc;
444
		argv = margv;
445
	}
446
	if (argc < 2) {
447
		getusage(argv[0]);
448
		return;
449
	}
450
	if (!connected) {
451
		for (n = 1; n < argc; n++)
452
			if (strrchr(argv[n], ':') == 0) {
453
				getusage(argv[0]);
454
				return;
455
			}
456
	}
457
	for (n = 1; n < argc; n++) {
458
		src = strrchr(argv[n], ':');
459
		if (src == NULL)
460
			src = argv[n];
461
		else {
462
			char *cp;
463
464
			*src++ = 0;
465
			cp = argv[n];
466
			if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
467
				cp[strlen(cp) - 1] = '\0';
468
				cp++;
469
			}
470
			setpeer(cp, NULL);
471
			if (!connected)
472
				continue;
473
		}
474
		if (argc < 4) {
475
			cp = argc == 3 ? argv[2] : tail(src);
476
			fd = open(cp, O_CREAT | O_TRUNC | O_WRONLY, 0644);
477
			if (fd < 0) {
478
				warn("create: %s", cp);
479
				return;
480
			}
481
			if (verbose)
482
				printf("getting from %s:%s to %s [%s]\n",
483
				    hostname, src, cp, mode);
484
			recvfile(fd, src, mode);
485
			break;
486
		}
487
		cp = tail(src);	/* new .. jdg */
488
		fd = open(cp, O_CREAT | O_TRUNC | O_WRONLY, 0644);
489
		if (fd < 0) {
490
			warn("create: %s", cp);
491
			continue;
492
		}
493
		if (verbose)
494
			printf("getting from %s:%s to %s [%s]\n",
495
			    hostname, src, cp, mode);
496
		recvfile(fd, src, mode);
497
	}
498
}
499
500
static void
501
getusage(char *s)
502
{
503
	printf("usage: %s [host:]file [localname]\n", s);
504
	printf("       %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
505
}
506
507
void
508
setrexmt(int argc, char *argv[])
509
{
510
	int		 t;
511
	const char	*errstr;
512
513
	if (argc < 2) {
514
		strlcpy(line, "Rexmt-timeout ", sizeof(line));
515
		printf("(value) ");
516
		readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
517
		if (makeargv())
518
			return;
519
		argc = margc;
520
		argv = margv;
521
	}
522
	if (argc != 2) {
523
		printf("usage: %s value\n", argv[0]);
524
		return;
525
	}
526
	t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
527
	if (errstr)
528
		printf("%s: value is %s\n", argv[1], errstr);
529
	else
530
		rexmtval = t;
531
}
532
533
void
534
settimeout(int argc, char *argv[])
535
{
536
	int		 t;
537
	const char	*errstr;
538
539
	if (argc < 2) {
540
		strlcpy(line, "Maximum-timeout ", sizeof(line));
541
		printf("(value) ");
542
		readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
543
		if (makeargv())
544
			return;
545
		argc = margc;
546
		argv = margv;
547
	}
548
	if (argc != 2) {
549
		printf("usage: %s value\n", argv[0]);
550
		return;
551
	}
552
	t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
553
	if (errstr)
554
		printf("%s: value is %s\n", argv[1], errstr);
555
	else
556
		maxtimeout = t;
557
}
558
559
/* ARGSUSED */
560
void
561
status(int argc, char *argv[])
562
{
563
	if (connected)
564
		printf("Connected to %s.\n", hostname);
565
	else
566
		printf("Not connected.\n");
567
	printf("Mode: %s Verbose: %s Tracing: %s\n",
568
	    mode, verbose ? "on" : "off", trace ? "on" : "off");
569
	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
570
	    rexmtval, maxtimeout);
571
}
572
573
/* ARGSUSED */
574
void
575
intr(int signo)
576
{
577
	intrflag = 1;
578
}
579
580
char *
581
tail(char *filename)
582
{
583
	char	*s;
584
585
	while (*filename) {
586
		s = strrchr(filename, '/');
587
		if (s == NULL)
588
			break;
589
		if (s[1])
590
			return (s + 1);
591
		*s = '\0';
592
	}
593
594
	return (filename);
595
}
596
597
/*
598
 * Command parser.
599
 */
600
static __dead void
601
command(void)
602
{
603
	struct cmd	*c;
604
605
	for (;;) {
606
		printf("%s> ", prompt);
607
		if (readcmd(line, LBUFLEN, stdin) < 1)
608
			continue;
609
		if ((line[0] == 0) || (line[0] == '\n'))
610
			continue;
611
		if (makeargv())
612
			continue;
613
		if (margc == 0)
614
			continue;
615
		c = getcmd(margv[0]);
616
		if (c == (struct cmd *) - 1) {
617
			printf("?Ambiguous command\n");
618
			continue;
619
		}
620
		if (c == 0) {
621
			printf("?Invalid command\n");
622
			continue;
623
		}
624
		(*c->handler)(margc, margv);
625
	}
626
}
627
628
struct cmd *
629
getcmd(char *name)
630
{
631
	char		*p, *q;
632
	struct cmd	*c, *found;
633
	int		 nmatches, longest;
634
635
	longest = 0;
636
	nmatches = 0;
637
	found = 0;
638
	intrflag = 0;
639
	for (c = cmdtab; (p = c->name) != NULL; c++) {
640
		for (q = name; *q == *p++; q++)
641
			if (*q == 0)		/* exact match? */
642
				return (c);
643
		if (!*q) {			/* the name was a prefix */
644
			if (q - name > longest) {
645
				longest = q - name;
646
				nmatches = 1;
647
				found = c;
648
			} else if (q - name == longest)
649
				nmatches++;
650
		}
651
	}
652
	if (nmatches > 1)
653
		return ((struct cmd *) - 1);
654
655
	return (found);
656
}
657
658
/*
659
 * Slice a string up into argc/argv.
660
 */
661
static int
662
makeargv(void)
663
{
664
	char	 *cp;
665
	char	**argp = margv;
666
	int	  ret = 0;
667
668
	margc = 0;
669
	for (cp = line; *cp;) {
670
		if (margc >= MAXARGV) {
671
			printf("too many arguments\n");
672
			ret = 1;
673
			break;
674
		}
675
		while (isspace((unsigned char)*cp))
676
			cp++;
677
		if (*cp == '\0')
678
			break;
679
		*argp++ = cp;
680
		margc += 1;
681
		while (*cp != '\0' && !isspace((unsigned char)*cp))
682
			cp++;
683
		if (*cp == '\0')
684
			break;
685
		*cp++ = '\0';
686
	}
687
	*argp++ = 0;
688
689
	return (ret);
690
}
691
692
/* ARGSUSED */
693
void
694
quit(int argc, char *argv[])
695
{
696
	exit(0);
697
}
698
699
/*
700
 * Help command.
701
 */
702
void
703
help(int argc, char *argv[])
704
{
705
	struct cmd	*c;
706
707
	if (argc == 1) {
708
		printf("Commands may be abbreviated.  Commands are:\n\n");
709
		for (c = cmdtab; c->name != NULL; c++)
710
			printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
711
		return;
712
	}
713
	while (--argc > 0) {
714
		char *arg;
715
		arg = *++argv;
716
		c = getcmd(arg);
717
		if (c == (struct cmd *) - 1)
718
			printf("?Ambiguous help command %s\n", arg);
719
		else if (c == NULL)
720
			printf("?Invalid help command %s\n", arg);
721
		else
722
			printf("%s\n", c->help);
723
	}
724
}
725
726
/* ARGSUSED */
727
void
728
settrace(int argc, char *argv[])
729
{
730
	trace = !trace;
731
	printf("Packet tracing %s.\n", trace ? "on" : "off");
732
}
733
734
/* ARGSUSED */
735
void
736
setverbose(int argc, char *argv[])
737
{
738
	verbose = !verbose;
739
	printf("Verbose mode %s.\n", verbose ? "on" : "off");
740
}
741
742
/* ARGSUSED */
743
void
744
settsize(int argc, char *argv[])
745
{
746
	opt_tsize = !opt_tsize;
747
	printf("Tsize option %s.\n", opt_tsize ? "on" : "off");
748
	if (opt_tsize)
749
		has_options++;
750
	else
751
		has_options--;
752
}
753
754
/* ARGSUSED */
755
void
756
settout(int argc, char *argv[])
757
{
758
	opt_tout = !opt_tout;
759
	printf("Timeout option %s.\n", opt_tout ? "on" : "off");
760
	if (opt_tout)
761
		has_options++;
762
	else
763
		has_options--;
764
}
765
766
void
767
setblksize(int argc, char *argv[])
768
{
769
	int		 t;
770
	const char	*errstr;
771
772
	if (argc < 2) {
773
		strlcpy(line, "Blocksize ", sizeof(line));
774
		printf("(value) ");
775
		readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
776
		if (makeargv())
777
			return;
778
		argc = margc;
779
		argv = margv;
780
	}
781
	if (argc != 2) {
782
		printf("usage: %s value\n", argv[0]);
783
		return;
784
	}
785
	t = strtonum(argv[1], SEGSIZE_MIN, SEGSIZE_MAX, &errstr);
786
	if (errstr)
787
		printf("%s: value is %s\n", argv[1], errstr);
788
	else {
789
		if (opt_blksize == 0)
790
			has_options++;
791
		opt_blksize = t;
792
	}
793
}
794
795
int
796
readcmd(char *input, int len, FILE *stream)
797
{
798
	int		nfds;
799
	struct pollfd	pfd[1];
800
801
	fflush(stdout);
802
803
	pfd[0].fd = 0;
804
	pfd[0].events = POLLIN;
805
	nfds = poll(pfd, 1, INFTIM);
806
	if (nfds == -1) {
807
		if (intrflag) {
808
			intrflag = 0;
809
			putchar('\n');
810
			return (0);
811
		}
812
		exit(1);
813
	}
814
815
	if (fgets(input, len, stream) == NULL) {
816
		if (feof(stdin))
817
			exit(0);
818
		else
819
			return (-1);
820
	}
821
822
	return (1);
823
}