diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-10-16 01:10:28 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-10-16 01:10:28 +0000 |
commit | d0e70af9d1065400a3ed478393dcd3873d1cb7d8 (patch) | |
tree | 82e9c52a15ed4c24dec593834188cefcc82a8382 /networking/nc.c | |
parent | bf39216cc4e095a7ce9a4b33b778c903b916e18b (diff) | |
download | busybox-w32-d0e70af9d1065400a3ed478393dcd3873d1cb7d8.tar.gz busybox-w32-d0e70af9d1065400a3ed478393dcd3873d1cb7d8.tar.bz2 busybox-w32-d0e70af9d1065400a3ed478393dcd3873d1cb7d8.zip |
nc: fix 2 my own buglets, and few someone else's too.
Diffstat (limited to 'networking/nc.c')
-rw-r--r-- | networking/nc.c | 95 |
1 files changed, 61 insertions, 34 deletions
diff --git a/networking/nc.c b/networking/nc.c index bde5e6600..a940d8a5d 100644 --- a/networking/nc.c +++ b/networking/nc.c | |||
@@ -16,51 +16,78 @@ static void timeout(int signum) | |||
16 | 16 | ||
17 | int nc_main(int argc, char **argv) | 17 | int nc_main(int argc, char **argv) |
18 | { | 18 | { |
19 | int sfd = 0, cfd; | 19 | int sfd = 0; |
20 | unsigned opt; | 20 | int cfd = 0; |
21 | unsigned lport = 0, wsecs = 0, delay = 0; | 21 | SKIP_NC_SERVER(const) unsigned do_listen = 0; |
22 | unsigned do_listen = 0, execflag = 0; | 22 | SKIP_NC_SERVER(const) unsigned lport = 0; |
23 | SKIP_NC_EXTRA (const) unsigned wsecs = 0; | ||
24 | SKIP_NC_EXTRA (const) unsigned delay = 0; | ||
25 | SKIP_NC_EXTRA (const int execparam = 0;) | ||
26 | USE_NC_EXTRA (char **execparam = NULL;) | ||
23 | struct sockaddr_in address; | 27 | struct sockaddr_in address; |
24 | struct hostent *hostinfo; | 28 | struct hostent *hostinfo; |
25 | fd_set readfds, testfds; | 29 | fd_set readfds, testfds; |
26 | char *infile = NULL; | 30 | int opt; /* must be signed (getopt returns -1) */ |
27 | 31 | ||
28 | memset(&address, 0, sizeof(address)); | 32 | memset(&address, 0, sizeof(address)); |
29 | 33 | ||
30 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { | 34 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { |
31 | while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) { | 35 | /* getopt32 is _almost_ usable: |
32 | if (ENABLE_NC_SERVER && opt=='l') do_listen++; | 36 | ** it cannot handle "... -e prog -prog-opt" */ |
33 | else if (ENABLE_NC_SERVER && opt=='p') | 37 | while ((opt = getopt(argc, argv, |
34 | lport = bb_lookup_port(optarg, "tcp", 0); | 38 | "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0 |
35 | else if (ENABLE_NC_EXTRA && opt=='w') wsecs = xatou(optarg); | 39 | ) { |
36 | else if (ENABLE_NC_EXTRA && opt=='i') delay = xatou(optarg); | 40 | if (ENABLE_NC_SERVER && opt=='l') USE_NC_SERVER(do_listen++); |
37 | else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg; | 41 | else if (ENABLE_NC_SERVER && opt=='p') USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); |
38 | else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) { | 42 | else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg)); |
39 | execflag++; | 43 | else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg)); |
40 | break; | 44 | else if (ENABLE_NC_EXTRA && opt=='f') USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); |
45 | else if (ENABLE_NC_EXTRA && opt=='e' && optind<=argc) { | ||
46 | /* We cannot just 'break'. We should let getopt finish. | ||
47 | ** Or else we won't be able to find where | ||
48 | ** 'host' and 'port' params are | ||
49 | ** (think "nc -w 60 host port -e prog"). */ | ||
50 | USE_NC_EXTRA( | ||
51 | char **p; | ||
52 | // +2: one for progname (optarg) and one for NULL | ||
53 | execparam = xzalloc(sizeof(char*) * (argc - optind + 2)); | ||
54 | p = execparam; | ||
55 | *p++ = optarg; | ||
56 | while (optind < argc) { | ||
57 | *p++ = argv[optind++]; | ||
58 | } | ||
59 | ) | ||
60 | /* optind points to argv[arvc] (NULL) now. | ||
61 | ** FIXME: we assume that getopt will not count options | ||
62 | ** possibly present on "-e prog args" and will not | ||
63 | ** include them into final value of optind | ||
64 | ** which is to be used ... */ | ||
41 | } else bb_show_usage(); | 65 | } else bb_show_usage(); |
42 | } | 66 | } |
43 | } | 67 | argv += optind; /* ... here! */ |
44 | 68 | argc -= optind; | |
45 | // For listen or file we need zero arguments, dialout is 2. | 69 | // -l and -f don't mix |
46 | // For exec we need at least one more argument at the end, more ok | 70 | if (do_listen && cfd) bb_show_usage(); |
47 | 71 | // Listen or file modes need zero arguments, client mode needs 2 | |
48 | opt = (do_listen || infile) ? 0 : 2 + execflag; | 72 | opt = ((do_listen || cfd) ? 0 : 2); |
49 | if (execflag ? argc-optind < opt : argc-optind!=opt || | 73 | if (argc != opt) |
50 | (infile && do_listen)) | ||
51 | bb_show_usage(); | 74 | bb_show_usage(); |
75 | } else { | ||
76 | if (argc != 3) bb_show_usage(); | ||
77 | argc--; | ||
78 | argv++; | ||
79 | } | ||
52 | 80 | ||
53 | if (wsecs) { | 81 | if (wsecs) { |
54 | signal(SIGALRM, timeout); | 82 | signal(SIGALRM, timeout); |
55 | alarm(wsecs); | 83 | alarm(wsecs); |
56 | } | 84 | } |
57 | 85 | ||
58 | if (infile) cfd = xopen(infile, O_RDWR); | 86 | if (!cfd) { |
59 | else { | ||
60 | opt = 1; | ||
61 | sfd = xsocket(AF_INET, SOCK_STREAM, 0); | 87 | sfd = xsocket(AF_INET, SOCK_STREAM, 0); |
62 | fcntl(sfd, F_SETFD, FD_CLOEXEC); | 88 | fcntl(sfd, F_SETFD, FD_CLOEXEC); |
63 | setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); | 89 | opt = 1; |
90 | setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | ||
64 | address.sin_family = AF_INET; | 91 | address.sin_family = AF_INET; |
65 | 92 | ||
66 | // Set local port. | 93 | // Set local port. |
@@ -82,17 +109,17 @@ int nc_main(int argc, char **argv) | |||
82 | getsockname(sfd, &address, &len); | 109 | getsockname(sfd, &address, &len); |
83 | fdprintf(2, "%d\n", SWAP_BE16(address.sin_port)); | 110 | fdprintf(2, "%d\n", SWAP_BE16(address.sin_port)); |
84 | } | 111 | } |
85 | repeatyness: | 112 | repeatyness: |
86 | cfd = accept(sfd, (struct sockaddr *) &address, &addrlen); | 113 | cfd = accept(sfd, (struct sockaddr *) &address, &addrlen); |
87 | if (cfd < 0) | 114 | if (cfd < 0) |
88 | bb_perror_msg_and_die("accept"); | 115 | bb_perror_msg_and_die("accept"); |
89 | 116 | ||
90 | if (!execflag) close(sfd); | 117 | if (!execparam) close(sfd); |
91 | } else { | 118 | } else { |
92 | hostinfo = xgethostbyname(argv[optind]); | 119 | hostinfo = xgethostbyname(argv[0]); |
93 | 120 | ||
94 | address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; | 121 | address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; |
95 | address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); | 122 | address.sin_port = bb_lookup_port(argv[1], "tcp", 0); |
96 | 123 | ||
97 | if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) | 124 | if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) |
98 | bb_perror_msg_and_die("connect"); | 125 | bb_perror_msg_and_die("connect"); |
@@ -106,8 +133,8 @@ repeatyness: | |||
106 | } | 133 | } |
107 | 134 | ||
108 | /* -e given? */ | 135 | /* -e given? */ |
109 | if (execflag) { | 136 | if (execparam) { |
110 | if(cfd) { | 137 | if (cfd) { |
111 | signal(SIGCHLD, SIG_IGN); | 138 | signal(SIGCHLD, SIG_IGN); |
112 | dup2(cfd, 0); | 139 | dup2(cfd, 0); |
113 | close(cfd); | 140 | close(cfd); |
@@ -128,7 +155,7 @@ repeatyness: | |||
128 | 155 | ||
129 | goto repeatyness; | 156 | goto repeatyness; |
130 | } | 157 | } |
131 | execvp(argv[optind], argv+optind); | 158 | USE_NC_EXTRA(execvp(execparam[0], execparam);) |
132 | /* Don't print stuff or it will go over the wire.... */ | 159 | /* Don't print stuff or it will go over the wire.... */ |
133 | _exit(127); | 160 | _exit(127); |
134 | } | 161 | } |