diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-11 16:50:23 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-11 16:50:23 +0000 |
commit | 8e9ccba371480fb1fb3da9235fabdbb7861523c3 (patch) | |
tree | 369636a4a765a571e1c6a6ecf2a52ca0131cc90e /networking/tftp.c | |
parent | 085231fbbad159d2275cbd5ecdcf4732512bb80f (diff) | |
download | busybox-w32-8e9ccba371480fb1fb3da9235fabdbb7861523c3.tar.gz busybox-w32-8e9ccba371480fb1fb3da9235fabdbb7861523c3.tar.bz2 busybox-w32-8e9ccba371480fb1fb3da9235fabdbb7861523c3.zip |
ipv6-ization efforts continue. Few bugs are found,
unknown number likely introduced...
Diffstat (limited to 'networking/tftp.c')
-rw-r--r-- | networking/tftp.c | 251 |
1 files changed, 103 insertions, 148 deletions
diff --git a/networking/tftp.c b/networking/tftp.c index 2d28973dc..eaeb80857 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -26,12 +26,6 @@ | |||
26 | #define TFTP_TIMEOUT 5 /* seconds */ | 26 | #define TFTP_TIMEOUT 5 /* seconds */ |
27 | #define TFTP_NUM_RETRIES 5 /* number of retries */ | 27 | #define TFTP_NUM_RETRIES 5 /* number of retries */ |
28 | 28 | ||
29 | static const char * const MODE_OCTET = "octet"; | ||
30 | #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/ | ||
31 | |||
32 | static const char * const OPTION_BLOCKSIZE = "blksize"; | ||
33 | #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */ | ||
34 | |||
35 | /* opcodes we support */ | 29 | /* opcodes we support */ |
36 | #define TFTP_RRQ 1 | 30 | #define TFTP_RRQ 1 |
37 | #define TFTP_WRQ 2 | 31 | #define TFTP_WRQ 2 |
@@ -51,13 +45,23 @@ static const char *const tftp_bb_error_msg[] = { | |||
51 | "No such user" | 45 | "No such user" |
52 | }; | 46 | }; |
53 | 47 | ||
54 | #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET | 48 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT |
55 | 49 | #define USE_GETPUT(a) | |
56 | #if ENABLE_FEATURE_TFTP_PUT | 50 | #define CMD_GET(cmd) 1 |
57 | # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT) | 51 | #define CMD_PUT(cmd) 0 |
52 | #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT | ||
53 | #define USE_GETPUT(a) | ||
54 | #define CMD_GET(cmd) 0 | ||
55 | #define CMD_PUT(cmd) 1 | ||
58 | #else | 56 | #else |
59 | # define tftp_cmd_put 0 | 57 | #define USE_GETPUT(a) a |
58 | /* masks coming from getpot32 */ | ||
59 | #define CMD_GET(cmd) (cmd & 1) | ||
60 | #define CMD_PUT(cmd) (cmd & 2) | ||
60 | #endif | 61 | #endif |
62 | /* NB: in the code below | ||
63 | * CMD_GET(cmd) and CMD_GET(cmd) are mutually exclusive | ||
64 | */ | ||
61 | 65 | ||
62 | 66 | ||
63 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 67 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
@@ -70,8 +74,9 @@ static int tftp_blocksize_check(int blocksize, int bufsize) | |||
70 | * to use blocksizes smaller than 22 octets. | 74 | * to use blocksizes smaller than 22 octets. |
71 | */ | 75 | */ |
72 | 76 | ||
73 | if ((bufsize && (blocksize > bufsize)) || | 77 | if ((bufsize && (blocksize > bufsize)) |
74 | (blocksize < 8) || (blocksize > 65564)) { | 78 | || (blocksize < 8) || (blocksize > 65564) |
79 | ) { | ||
75 | bb_error_msg("bad blocksize"); | 80 | bb_error_msg("bad blocksize"); |
76 | return 0; | 81 | return 0; |
77 | } | 82 | } |
@@ -86,7 +91,6 @@ static char *tftp_option_get(char *buf, int len, const char * const option) | |||
86 | int k; | 91 | int k; |
87 | 92 | ||
88 | while (len > 0) { | 93 | while (len > 0) { |
89 | |||
90 | /* Make sure the options are terminated correctly */ | 94 | /* Make sure the options are terminated correctly */ |
91 | 95 | ||
92 | for (k = 0; k < len; k++) { | 96 | for (k = 0; k < len; k++) { |
@@ -122,22 +126,23 @@ static char *tftp_option_get(char *buf, int len, const char * const option) | |||
122 | 126 | ||
123 | #endif | 127 | #endif |
124 | 128 | ||
125 | static int tftp(const int cmd, const struct hostent *host, | 129 | static int tftp( |
126 | const char *remotefile, const int localfd, | 130 | #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT |
127 | const unsigned short port, int tftp_bufsize) | 131 | const int cmd, |
132 | #endif | ||
133 | const len_and_sockaddr *peer_lsa, | ||
134 | const char *remotefile, const int localfd, | ||
135 | const unsigned port, int tftp_bufsize) | ||
128 | { | 136 | { |
129 | struct sockaddr_in sa; | ||
130 | struct sockaddr_in from; | ||
131 | struct timeval tv; | 137 | struct timeval tv; |
132 | socklen_t fromlen; | ||
133 | fd_set rfds; | 138 | fd_set rfds; |
134 | int socketfd; | 139 | int socketfd; |
135 | int len; | 140 | int len; |
136 | int opcode = 0; | 141 | int opcode = 0; |
137 | int finished = 0; | 142 | int finished = 0; |
138 | int timeout = TFTP_NUM_RETRIES; | 143 | int timeout = TFTP_NUM_RETRIES; |
139 | unsigned short block_nr = 1; | 144 | uint16_t block_nr = 1; |
140 | unsigned short tmp; | 145 | uint16_t tmp; |
141 | char *cp; | 146 | char *cp; |
142 | 147 | ||
143 | USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) | 148 | USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) |
@@ -149,42 +154,24 @@ static int tftp(const int cmd, const struct hostent *host, | |||
149 | char *xbuf = xmalloc(tftp_bufsize += 4); | 154 | char *xbuf = xmalloc(tftp_bufsize += 4); |
150 | char *rbuf = xmalloc(tftp_bufsize); | 155 | char *rbuf = xmalloc(tftp_bufsize); |
151 | 156 | ||
152 | if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { | 157 | socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); |
153 | /* need to unlink the localfile, so don't use xsocket here. */ | ||
154 | bb_perror_msg("socket"); | ||
155 | return EXIT_FAILURE; | ||
156 | } | ||
157 | |||
158 | len = sizeof(sa); | ||
159 | |||
160 | memset(&sa, 0, len); | ||
161 | xbind(socketfd, (struct sockaddr *)&sa, len); | ||
162 | |||
163 | sa.sin_family = host->h_addrtype; | ||
164 | sa.sin_port = port; | ||
165 | memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, | ||
166 | sizeof(sa.sin_addr)); | ||
167 | 158 | ||
168 | /* build opcode */ | 159 | /* build opcode */ |
169 | if (cmd & tftp_cmd_get) { | 160 | opcode = TFTP_WRQ; |
161 | if (CMD_GET(cmd)) { | ||
170 | opcode = TFTP_RRQ; | 162 | opcode = TFTP_RRQ; |
171 | } | 163 | } |
172 | if (cmd & tftp_cmd_put) { | ||
173 | opcode = TFTP_WRQ; | ||
174 | } | ||
175 | 164 | ||
176 | while (1) { | 165 | while (1) { |
177 | 166 | ||
178 | cp = xbuf; | 167 | cp = xbuf; |
179 | 168 | ||
180 | /* first create the opcode part */ | 169 | /* first create the opcode part */ |
181 | *((unsigned short *) cp) = htons(opcode); | 170 | *((uint16_t*)cp) = htons(opcode); |
182 | cp += 2; | 171 | cp += 2; |
183 | 172 | ||
184 | /* add filename and mode */ | 173 | /* add filename and mode */ |
185 | if (((cmd & tftp_cmd_get) && (opcode == TFTP_RRQ)) || | 174 | if (CMD_GET(cmd) ? (opcode == TFTP_RRQ) : (opcode == TFTP_WRQ)) { |
186 | ((cmd & tftp_cmd_put) && (opcode == TFTP_WRQ))) | ||
187 | { | ||
188 | int too_long = 0; | 175 | int too_long = 0; |
189 | 176 | ||
190 | /* see if the filename fits into xbuf | 177 | /* see if the filename fits into xbuf |
@@ -198,14 +185,14 @@ static int tftp(const int cmd, const struct hostent *host, | |||
198 | cp += len; | 185 | cp += len; |
199 | } | 186 | } |
200 | 187 | ||
201 | if (too_long || ((&xbuf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) { | 188 | if (too_long || (&xbuf[tftp_bufsize - 1] - cp) < sizeof("octet")) { |
202 | bb_error_msg("remote filename too long"); | 189 | bb_error_msg("remote filename too long"); |
203 | break; | 190 | break; |
204 | } | 191 | } |
205 | 192 | ||
206 | /* add "mode" part of the package */ | 193 | /* add "mode" part of the package */ |
207 | memcpy(cp, MODE_OCTET, MODE_OCTET_LEN); | 194 | memcpy(cp, "octet", sizeof("octet")); |
208 | cp += MODE_OCTET_LEN; | 195 | cp += sizeof("octet"); |
209 | 196 | ||
210 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 197 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
211 | 198 | ||
@@ -219,8 +206,8 @@ static int tftp(const int cmd, const struct hostent *host, | |||
219 | } | 206 | } |
220 | 207 | ||
221 | /* add "blksize" + number of blocks */ | 208 | /* add "blksize" + number of blocks */ |
222 | memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN); | 209 | memcpy(cp, "blksize", sizeof("blksize")); |
223 | cp += OPTION_BLOCKSIZE_LEN; | 210 | cp += sizeof("blksize"); |
224 | cp += snprintf(cp, 6, "%d", len) + 1; | 211 | cp += snprintf(cp, 6, "%d", len) + 1; |
225 | 212 | ||
226 | want_option_ack = 1; | 213 | want_option_ack = 1; |
@@ -230,16 +217,12 @@ static int tftp(const int cmd, const struct hostent *host, | |||
230 | 217 | ||
231 | /* add ack and data */ | 218 | /* add ack and data */ |
232 | 219 | ||
233 | if (((cmd & tftp_cmd_get) && (opcode == TFTP_ACK)) || | 220 | if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) { |
234 | ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA))) { | 221 | *((uint16_t*)cp) = htons(block_nr); |
235 | |||
236 | *((unsigned short *) cp) = htons(block_nr); | ||
237 | |||
238 | cp += 2; | 222 | cp += 2; |
239 | |||
240 | block_nr++; | 223 | block_nr++; |
241 | 224 | ||
242 | if ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA)) { | 225 | if (CMD_PUT(cmd) && (opcode == TFTP_DATA)) { |
243 | len = full_read(localfd, cp, tftp_bufsize - 4); | 226 | len = full_read(localfd, cp, tftp_bufsize - 4); |
244 | 227 | ||
245 | if (len < 0) { | 228 | if (len < 0) { |
@@ -261,9 +244,7 @@ static int tftp(const int cmd, const struct hostent *host, | |||
261 | 244 | ||
262 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ | 245 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ |
263 | do { | 246 | do { |
264 | |||
265 | len = cp - xbuf; | 247 | len = cp - xbuf; |
266 | |||
267 | #if ENABLE_DEBUG_TFTP | 248 | #if ENABLE_DEBUG_TFTP |
268 | fprintf(stderr, "sending %u bytes\n", len); | 249 | fprintf(stderr, "sending %u bytes\n", len); |
269 | for (cp = xbuf; cp < &xbuf[len]; cp++) | 250 | for (cp = xbuf; cp < &xbuf[len]; cp++) |
@@ -271,7 +252,7 @@ static int tftp(const int cmd, const struct hostent *host, | |||
271 | fprintf(stderr, "\n"); | 252 | fprintf(stderr, "\n"); |
272 | #endif | 253 | #endif |
273 | if (sendto(socketfd, xbuf, len, 0, | 254 | if (sendto(socketfd, xbuf, len, 0, |
274 | (struct sockaddr *) &sa, sizeof(sa)) < 0) { | 255 | &peer_lsa->sa, peer_lsa->len) < 0) { |
275 | bb_perror_msg("send"); | 256 | bb_perror_msg("send"); |
276 | len = -1; | 257 | len = -1; |
277 | break; | 258 | break; |
@@ -284,9 +265,6 @@ static int tftp(const int cmd, const struct hostent *host, | |||
284 | 265 | ||
285 | /* receive packet */ | 266 | /* receive packet */ |
286 | 267 | ||
287 | memset(&from, 0, sizeof(from)); | ||
288 | fromlen = sizeof(from); | ||
289 | |||
290 | tv.tv_sec = TFTP_TIMEOUT; | 268 | tv.tv_sec = TFTP_TIMEOUT; |
291 | tv.tv_usec = 0; | 269 | tv.tv_usec = 0; |
292 | 270 | ||
@@ -294,30 +272,41 @@ static int tftp(const int cmd, const struct hostent *host, | |||
294 | FD_SET(socketfd, &rfds); | 272 | FD_SET(socketfd, &rfds); |
295 | 273 | ||
296 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { | 274 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { |
275 | struct sockaddr *from; | ||
276 | socklen_t fromlen; | ||
277 | |||
297 | case 1: | 278 | case 1: |
298 | len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, | 279 | fromlen = peer_lsa->len; |
299 | (struct sockaddr *) &from, &fromlen); | 280 | from = alloca(fromlen); |
281 | memset(from, 0, fromlen); | ||
300 | 282 | ||
283 | len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, | ||
284 | from, &fromlen); | ||
301 | if (len < 0) { | 285 | if (len < 0) { |
302 | bb_perror_msg("recvfrom"); | 286 | bb_perror_msg("recvfrom"); |
303 | break; | 287 | break; |
304 | } | 288 | } |
305 | |||
306 | timeout = 0; | 289 | timeout = 0; |
307 | 290 | if (from->sa_family == peer_lsa->sa.sa_family) { | |
308 | if (sa.sin_port == port) { | 291 | #if ENABLE_FEATURE_IPV6 |
309 | sa.sin_port = from.sin_port; | 292 | if (from->sa_family == AF_INET6 |
310 | } | 293 | && ((struct sockaddr_in6*)from)->sin6_port == port |
311 | if (sa.sin_port == from.sin_port) { | 294 | ) |
312 | break; | 295 | break; |
296 | #endif | ||
297 | /* Non-internet sockets are ok */ | ||
298 | if (from->sa_family != AF_INET) | ||
299 | break; | ||
300 | if (((struct sockaddr_in*)from)->sin_port == port) | ||
301 | break; | ||
313 | } | 302 | } |
314 | 303 | /* family doesn't match, or | |
315 | /* fall-through for bad packets! */ | 304 | * it is INET[v6] and port doesn't match - |
316 | /* discard the packet - treat as timeout */ | 305 | * fall-through for bad packets! |
306 | * (discard the packet - treat as timeout) */ | ||
317 | timeout = TFTP_NUM_RETRIES; | 307 | timeout = TFTP_NUM_RETRIES; |
318 | case 0: | 308 | case 0: |
319 | bb_error_msg("timeout"); | 309 | bb_error_msg("timeout"); |
320 | |||
321 | timeout--; | 310 | timeout--; |
322 | if (timeout == 0) { | 311 | if (timeout == 0) { |
323 | len = -1; | 312 | len = -1; |
@@ -331,14 +320,14 @@ static int tftp(const int cmd, const struct hostent *host, | |||
331 | 320 | ||
332 | } while (timeout && (len >= 0)); | 321 | } while (timeout && (len >= 0)); |
333 | 322 | ||
334 | if ((finished) || (len < 0)) { | 323 | if (finished || (len < 0)) { |
335 | break; | 324 | break; |
336 | } | 325 | } |
337 | 326 | ||
338 | /* process received packet */ | 327 | /* process received packet */ |
339 | 328 | ||
340 | opcode = ntohs(*((unsigned short *) rbuf)); | 329 | opcode = ntohs( ((uint16_t*)rbuf)[0] ); |
341 | tmp = ntohs(*((unsigned short *) &rbuf[2])); | 330 | tmp = ntohs( ((uint16_t*)rbuf)[1] ); |
342 | 331 | ||
343 | #if ENABLE_DEBUG_TFTP | 332 | #if ENABLE_DEBUG_TFTP |
344 | fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp); | 333 | fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp); |
@@ -352,7 +341,6 @@ static int tftp(const int cmd, const struct hostent *host, | |||
352 | rbuf[tftp_bufsize - 1] = '\0'; | 341 | rbuf[tftp_bufsize - 1] = '\0'; |
353 | } else if (tmp < (sizeof(tftp_bb_error_msg) | 342 | } else if (tmp < (sizeof(tftp_bb_error_msg) |
354 | / sizeof(char *))) { | 343 | / sizeof(char *))) { |
355 | |||
356 | msg = tftp_bb_error_msg[tmp]; | 344 | msg = tftp_bb_error_msg[tmp]; |
357 | } | 345 | } |
358 | 346 | ||
@@ -368,25 +356,22 @@ static int tftp(const int cmd, const struct hostent *host, | |||
368 | want_option_ack = 0; | 356 | want_option_ack = 0; |
369 | 357 | ||
370 | if (opcode == TFTP_OACK) { | 358 | if (opcode == TFTP_OACK) { |
371 | |||
372 | /* server seems to support options */ | 359 | /* server seems to support options */ |
373 | |||
374 | char *res; | 360 | char *res; |
375 | 361 | ||
376 | res = tftp_option_get(&rbuf[2], len - 2, OPTION_BLOCKSIZE); | 362 | res = tftp_option_get(&rbuf[2], len - 2, "blksize"); |
377 | 363 | ||
378 | if (res) { | 364 | if (res) { |
379 | int blksize = xatoi_u(res); | 365 | int blksize = xatoi_u(res); |
380 | 366 | ||
381 | if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { | 367 | if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { |
382 | 368 | if (CMD_PUT(cmd)) { | |
383 | if (cmd & tftp_cmd_put) { | ||
384 | opcode = TFTP_DATA; | 369 | opcode = TFTP_DATA; |
385 | } else { | 370 | } else { |
386 | opcode = TFTP_ACK; | 371 | opcode = TFTP_ACK; |
387 | } | 372 | } |
388 | #if ENABLE_DEBUG_TFTP | 373 | #if ENABLE_DEBUG_TFTP |
389 | fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE, | 374 | fprintf(stderr, "using blksize %u\n", |
390 | blksize); | 375 | blksize); |
391 | #endif | 376 | #endif |
392 | tftp_bufsize = blksize + 4; | 377 | tftp_bufsize = blksize + 4; |
@@ -407,10 +392,8 @@ static int tftp(const int cmd, const struct hostent *host, | |||
407 | } | 392 | } |
408 | #endif | 393 | #endif |
409 | 394 | ||
410 | if ((cmd & tftp_cmd_get) && (opcode == TFTP_DATA)) { | 395 | if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { |
411 | |||
412 | if (tmp == block_nr) { | 396 | if (tmp == block_nr) { |
413 | |||
414 | len = full_write(localfd, &rbuf[4], len - 4); | 397 | len = full_write(localfd, &rbuf[4], len - 4); |
415 | 398 | ||
416 | if (len < 0) { | 399 | if (len < 0) { |
@@ -430,6 +413,7 @@ static int tftp(const int cmd, const struct hostent *host, | |||
430 | --block_nr; | 413 | --block_nr; |
431 | opcode = TFTP_ACK; | 414 | opcode = TFTP_ACK; |
432 | continue; | 415 | continue; |
416 | // tmp==(block_nr-1) and (tmp+1)==block_nr is always same, I think. wtf? | ||
433 | } else if (tmp + 1 == block_nr) { | 417 | } else if (tmp + 1 == block_nr) { |
434 | /* Server lost our TFTP_ACK. Resend it */ | 418 | /* Server lost our TFTP_ACK. Resend it */ |
435 | block_nr = tmp; | 419 | block_nr = tmp; |
@@ -438,9 +422,8 @@ static int tftp(const int cmd, const struct hostent *host, | |||
438 | } | 422 | } |
439 | } | 423 | } |
440 | 424 | ||
441 | if ((cmd & tftp_cmd_put) && (opcode == TFTP_ACK)) { | 425 | if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { |
442 | 426 | if (tmp == (uint16_t) (block_nr - 1)) { | |
443 | if (tmp == (unsigned short) (block_nr - 1)) { | ||
444 | if (finished) { | 427 | if (finished) { |
445 | break; | 428 | break; |
446 | } | 429 | } |
@@ -462,61 +445,32 @@ static int tftp(const int cmd, const struct hostent *host, | |||
462 | 445 | ||
463 | int tftp_main(int argc, char **argv) | 446 | int tftp_main(int argc, char **argv) |
464 | { | 447 | { |
465 | struct hostent *host = NULL; | 448 | len_and_sockaddr *peer_lsa; |
466 | const char *localfile = NULL; | 449 | const char *localfile = NULL; |
467 | const char *remotefile = NULL; | 450 | const char *remotefile = NULL; |
451 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | ||
452 | const char *sblocksize = NULL; | ||
453 | #endif | ||
468 | int port; | 454 | int port; |
469 | int cmd = 0; | 455 | USE_GETPUT(int cmd;) |
470 | int fd = -1; | 456 | int fd = -1; |
471 | int flags = 0; | 457 | int flags = 0; |
472 | int result; | 458 | int result; |
473 | int blocksize = TFTP_BLOCKSIZE_DEFAULT; | 459 | int blocksize = TFTP_BLOCKSIZE_DEFAULT; |
474 | 460 | ||
475 | /* figure out what to pass to getopt */ | 461 | /* -p or -g is mandatory, and they are mutually exclusive */ |
476 | 462 | opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") | |
477 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 463 | USE_GETPUT("?g--p:p--g"); |
478 | char *sblocksize = NULL; | ||
479 | |||
480 | #define BS "b:" | ||
481 | #define BS_ARG , &sblocksize | ||
482 | #else | ||
483 | #define BS | ||
484 | #define BS_ARG | ||
485 | #endif | ||
486 | |||
487 | #if ENABLE_FEATURE_TFTP_GET | ||
488 | #define GET "g" | ||
489 | #define GET_COMPL ":g" | ||
490 | #else | ||
491 | #define GET | ||
492 | #define GET_COMPL | ||
493 | #endif | ||
494 | 464 | ||
495 | #if ENABLE_FEATURE_TFTP_PUT | 465 | USE_GETPUT(cmd =) getopt32(argc, argv, |
496 | #define PUT "p" | 466 | USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") |
497 | #define PUT_COMPL ":p" | 467 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), |
498 | #else | 468 | &localfile, &remotefile |
499 | #define PUT | 469 | USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize)); |
500 | #define PUT_COMPL | ||
501 | #endif | ||
502 | 470 | ||
503 | #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT) | 471 | flags = O_RDONLY; |
504 | opt_complementary = GET_COMPL PUT_COMPL ":?g--p:p--g"; | 472 | if (CMD_GET(cmd)) |
505 | #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) | ||
506 | opt_complementary = GET_COMPL PUT_COMPL; | ||
507 | #endif | ||
508 | |||
509 | cmd = getopt32(argc, argv, GET PUT "l:r:" BS, &localfile, &remotefile BS_ARG); | ||
510 | |||
511 | cmd &= (tftp_cmd_get | tftp_cmd_put); | ||
512 | #if ENABLE_FEATURE_TFTP_GET | ||
513 | if (cmd == tftp_cmd_get) | ||
514 | flags = O_WRONLY | O_CREAT | O_TRUNC; | 473 | flags = O_WRONLY | O_CREAT | O_TRUNC; |
515 | #endif | ||
516 | #if ENABLE_FEATURE_TFTP_PUT | ||
517 | if (cmd == tftp_cmd_put) | ||
518 | flags = O_RDONLY; | ||
519 | #endif | ||
520 | 474 | ||
521 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 475 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
522 | if (sblocksize) { | 476 | if (sblocksize) { |
@@ -535,30 +489,31 @@ int tftp_main(int argc, char **argv) | |||
535 | bb_show_usage(); | 489 | bb_show_usage(); |
536 | 490 | ||
537 | if (localfile == NULL || LONE_DASH(localfile)) { | 491 | if (localfile == NULL || LONE_DASH(localfile)) { |
538 | fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO; | 492 | fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; |
539 | } else { | 493 | } else { |
540 | fd = open(localfile, flags, 0644); /* fail below */ | 494 | fd = xopen3(localfile, flags, 0644); |
541 | } | ||
542 | if (fd < 0) { | ||
543 | bb_perror_msg_and_die("local file"); | ||
544 | } | 495 | } |
545 | 496 | ||
546 | host = xgethostbyname(argv[optind]); | ||
547 | port = bb_lookup_port(argv[optind + 1], "udp", 69); | 497 | port = bb_lookup_port(argv[optind + 1], "udp", 69); |
498 | peer_lsa = host2sockaddr(argv[optind], port); | ||
548 | 499 | ||
549 | #if ENABLE_DEBUG_TFTP | 500 | #if ENABLE_DEBUG_TFTP |
550 | fprintf(stderr, "using server \"%s\", remotefile \"%s\", " | 501 | fprintf(stderr, "using server \"%s\", " |
551 | "localfile \"%s\".\n", | 502 | "remotefile \"%s\", localfile \"%s\".\n", |
552 | inet_ntoa(*((struct in_addr *) host->h_addr)), | 503 | xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len), |
553 | remotefile, localfile); | 504 | remotefile, localfile); |
554 | #endif | 505 | #endif |
555 | 506 | ||
556 | result = tftp(cmd, host, remotefile, fd, port, blocksize); | 507 | result = tftp( |
508 | #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT | ||
509 | cmd, | ||
510 | #endif | ||
511 | peer_lsa, remotefile, fd, port, blocksize); | ||
557 | 512 | ||
558 | if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) { | 513 | if (fd > 1) { |
559 | if (ENABLE_FEATURE_CLEAN_UP) | 514 | if (ENABLE_FEATURE_CLEAN_UP) |
560 | close(fd); | 515 | close(fd); |
561 | if (cmd == tftp_cmd_get && result != EXIT_SUCCESS) | 516 | if (CMD_GET(cmd) && result != EXIT_SUCCESS) |
562 | unlink(localfile); | 517 | unlink(localfile); |
563 | } | 518 | } |
564 | return result; | 519 | return result; |