diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-08 23:12:21 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-08 23:12:21 +0000 |
commit | a04561f5f7b6f1975c1bded6f11001f03190058c (patch) | |
tree | be7dbf6c0cfe0032938c8d2151662b652db87e5f /networking/tftp.c | |
parent | 7e84e539de530b2060f0e570fc8f063ed0aaad2f (diff) | |
download | busybox-w32-a04561f5f7b6f1975c1bded6f11001f03190058c.tar.gz busybox-w32-a04561f5f7b6f1975c1bded6f11001f03190058c.tar.bz2 busybox-w32-a04561f5f7b6f1975c1bded6f11001f03190058c.zip |
tftp: code diet, and I think retransmits were broken.
function old new delta
static.errcode_str - 32 +32
tftp_main 359 345 -14
tftp_bb_error_msg 32 - -32
.rodata 130931 130899 -32
tftp 1720 1558 -162
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 0/3 up/down: 32/-240) Total: -208 bytes
Diffstat (limited to 'networking/tftp.c')
-rw-r--r-- | networking/tftp.c | 368 |
1 files changed, 159 insertions, 209 deletions
diff --git a/networking/tftp.c b/networking/tftp.c index 0621dde69..1f1dfff71 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -36,17 +36,6 @@ | |||
36 | #define TFTP_ERROR 5 | 36 | #define TFTP_ERROR 5 |
37 | #define TFTP_OACK 6 | 37 | #define TFTP_OACK 6 |
38 | 38 | ||
39 | static const char *const tftp_bb_error_msg[] = { | ||
40 | "Undefined error", | ||
41 | "File not found", | ||
42 | "Access violation", | ||
43 | "Disk full or allocation error", | ||
44 | "Illegal TFTP operation", | ||
45 | "Unknown transfer ID", | ||
46 | "File already exists", | ||
47 | "No such user" | ||
48 | }; | ||
49 | |||
50 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT | 39 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT |
51 | #define USE_GETPUT(a) | 40 | #define USE_GETPUT(a) |
52 | #define CMD_GET(cmd) 1 | 41 | #define CMD_GET(cmd) 1 |
@@ -62,7 +51,7 @@ static const char *const tftp_bb_error_msg[] = { | |||
62 | #define CMD_PUT(cmd) ((cmd) & 2) | 51 | #define CMD_PUT(cmd) ((cmd) & 2) |
63 | #endif | 52 | #endif |
64 | /* NB: in the code below | 53 | /* NB: in the code below |
65 | * CMD_GET(cmd) and CMD_GET(cmd) are mutually exclusive | 54 | * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive |
66 | */ | 55 | */ |
67 | 56 | ||
68 | 57 | ||
@@ -86,7 +75,7 @@ static int tftp_blocksize_check(int blocksize, int bufsize) | |||
86 | return blocksize; | 75 | return blocksize; |
87 | } | 76 | } |
88 | 77 | ||
89 | static char *tftp_option_get(char *buf, int len, const char * const option) | 78 | static char *tftp_option_get(char *buf, int len, const char *option) |
90 | { | 79 | { |
91 | int opt_val = 0; | 80 | int opt_val = 0; |
92 | int opt_found = 0; | 81 | int opt_found = 0; |
@@ -94,32 +83,24 @@ static char *tftp_option_get(char *buf, int len, const char * const option) | |||
94 | 83 | ||
95 | while (len > 0) { | 84 | while (len > 0) { |
96 | /* Make sure the options are terminated correctly */ | 85 | /* Make sure the options are terminated correctly */ |
97 | |||
98 | for (k = 0; k < len; k++) { | 86 | for (k = 0; k < len; k++) { |
99 | if (buf[k] == '\0') { | 87 | if (buf[k] == '\0') { |
100 | break; | 88 | goto nul_found; |
101 | } | 89 | } |
102 | } | 90 | } |
103 | 91 | return NULL; | |
104 | if (k >= len) { | 92 | nul_found: |
105 | break; | ||
106 | } | ||
107 | |||
108 | if (opt_val == 0) { | 93 | if (opt_val == 0) { |
109 | if (strcasecmp(buf, option) == 0) { | 94 | if (strcasecmp(buf, option) == 0) { |
110 | opt_found = 1; | 95 | opt_found = 1; |
111 | } | 96 | } |
112 | } else { | 97 | } else if (opt_found) { |
113 | if (opt_found) { | 98 | return buf; |
114 | return buf; | ||
115 | } | ||
116 | } | 99 | } |
117 | 100 | ||
118 | k++; | 101 | k++; |
119 | |||
120 | buf += k; | 102 | buf += k; |
121 | len -= k; | 103 | len -= k; |
122 | |||
123 | opt_val ^= 1; | 104 | opt_val ^= 1; |
124 | } | 105 | } |
125 | 106 | ||
@@ -140,15 +121,15 @@ static int tftp( | |||
140 | fd_set rfds; | 121 | fd_set rfds; |
141 | int socketfd; | 122 | int socketfd; |
142 | int len; | 123 | int len; |
143 | int opcode = 0; | 124 | int send_len; |
144 | int finished = 0; | 125 | USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;) |
145 | int timeout = TFTP_NUM_RETRIES; | 126 | smallint finished = 0; |
127 | uint16_t opcode; | ||
146 | uint16_t block_nr = 1; | 128 | uint16_t block_nr = 1; |
147 | uint16_t tmp; | 129 | uint16_t recv_blk; |
130 | int timeout = TFTP_NUM_RETRIES; | ||
148 | char *cp; | 131 | char *cp; |
149 | 132 | ||
150 | USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) | ||
151 | |||
152 | unsigned org_port; | 133 | unsigned org_port; |
153 | len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len); | 134 | len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len); |
154 | 135 | ||
@@ -168,109 +149,83 @@ static int tftp( | |||
168 | if (CMD_GET(cmd)) { | 149 | if (CMD_GET(cmd)) { |
169 | opcode = TFTP_RRQ; | 150 | opcode = TFTP_RRQ; |
170 | } | 151 | } |
171 | 152 | cp = xbuf + 2; | |
172 | while (1) { | 153 | /* add filename and mode */ |
173 | cp = xbuf; | 154 | /* fill in packet if the filename fits into xbuf */ |
174 | 155 | len = strlen(remotefile) + 1; | |
175 | /* first create the opcode part */ | 156 | if (2 + len + sizeof("octet") >= tftp_bufsize) { |
176 | /* (this 16bit store is aligned) */ | 157 | bb_error_msg("remote filename is too long"); |
177 | *((uint16_t*)cp) = htons(opcode); | 158 | goto ret; |
178 | cp += 2; | 159 | } |
179 | 160 | strcpy(cp, remotefile); | |
180 | /* add filename and mode */ | 161 | cp += len; |
181 | if (CMD_GET(cmd) ? (opcode == TFTP_RRQ) : (opcode == TFTP_WRQ)) { | 162 | /* add "mode" part of the package */ |
182 | int too_long = 0; | 163 | strcpy(cp, "octet"); |
183 | 164 | cp += sizeof("octet"); | |
184 | /* see if the filename fits into xbuf | ||
185 | * and fill in packet. */ | ||
186 | len = strlen(remotefile) + 1; | ||
187 | |||
188 | if ((cp + len) >= &xbuf[tftp_bufsize - 1]) { | ||
189 | too_long = 1; | ||
190 | } else { | ||
191 | safe_strncpy(cp, remotefile, len); | ||
192 | cp += len; | ||
193 | } | ||
194 | |||
195 | if (too_long || (&xbuf[tftp_bufsize - 1] - cp) < sizeof("octet")) { | ||
196 | bb_error_msg("remote filename too long"); | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | /* add "mode" part of the package */ | ||
201 | memcpy(cp, "octet", sizeof("octet")); | ||
202 | cp += sizeof("octet"); | ||
203 | 165 | ||
204 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 166 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
205 | 167 | len = tftp_bufsize - 4; /* data block size */ | |
206 | len = tftp_bufsize - 4; /* data block size */ | 168 | if (len != TFTP_BLOCKSIZE_DEFAULT) { |
207 | 169 | /* rfc2348 says that 65464 is a max allowed value */ | |
208 | if (len != TFTP_BLOCKSIZE_DEFAULT) { | 170 | if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { |
209 | 171 | bb_error_msg("remote filename is too long"); | |
210 | if ((&xbuf[tftp_bufsize - 1] - cp) < 15) { | 172 | goto ret; |
211 | bb_error_msg("remote filename too long"); | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | /* add "blksize" + number of blocks */ | ||
216 | memcpy(cp, "blksize", sizeof("blksize")); | ||
217 | cp += sizeof("blksize"); | ||
218 | cp += snprintf(cp, 6, "%d", len) + 1; | ||
219 | |||
220 | want_option_ack = 1; | ||
221 | } | ||
222 | #endif | ||
223 | } | 173 | } |
174 | /* add "blksize", <nul>, blocksize */ | ||
175 | strcpy(cp, "blksize"); | ||
176 | cp += sizeof("blksize"); | ||
177 | cp += snprintf(cp, 6, "%d", len) + 1; | ||
178 | want_option_ack = 1; | ||
179 | } | ||
180 | #endif | ||
181 | /* First packet is built, so skip packet generation */ | ||
182 | goto send_pkt; | ||
224 | 183 | ||
225 | /* add ack and data */ | 184 | while (1) { |
226 | 185 | /* Build ACK or DATA */ | |
227 | if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) { | 186 | cp = xbuf + 2; |
228 | /* TODO: unaligned access! */ | 187 | *((uint16_t*)cp) = htons(block_nr); |
229 | *((uint16_t*)cp) = htons(block_nr); | 188 | cp += 2; |
230 | cp += 2; | 189 | block_nr++; |
231 | block_nr++; | 190 | opcode = TFTP_ACK; |
232 | 191 | if (CMD_PUT(cmd)) { | |
233 | if (CMD_PUT(cmd) && (opcode == TFTP_DATA)) { | 192 | opcode = TFTP_DATA; |
234 | len = full_read(localfd, cp, tftp_bufsize - 4); | 193 | len = full_read(localfd, cp, tftp_bufsize - 4); |
235 | 194 | if (len < 0) { | |
236 | if (len < 0) { | 195 | bb_perror_msg(bb_msg_read_error); |
237 | bb_perror_msg(bb_msg_read_error); | 196 | goto ret; |
238 | break; | 197 | } |
239 | } | 198 | if (len != (tftp_bufsize - 4)) { |
240 | 199 | finished = 1; | |
241 | if (len != (tftp_bufsize - 4)) { | ||
242 | finished++; | ||
243 | } | ||
244 | |||
245 | cp += len; | ||
246 | } | 200 | } |
201 | cp += len; | ||
247 | } | 202 | } |
248 | 203 | send_pkt: | |
249 | /* send packet */ | 204 | /* Send packet */ |
250 | 205 | *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */ | |
251 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ | 206 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ |
252 | do { | 207 | while (1) { |
253 | len = cp - xbuf; | 208 | send_len = cp - xbuf; |
209 | /* nb: need to preserve send_len value in code below | ||
210 | * for potential resend! */ | ||
211 | send_again: | ||
254 | #if ENABLE_DEBUG_TFTP | 212 | #if ENABLE_DEBUG_TFTP |
255 | fprintf(stderr, "sending %u bytes\n", len); | 213 | fprintf(stderr, "sending %u bytes\n", send_len); |
256 | for (cp = xbuf; cp < &xbuf[len]; cp++) | 214 | for (cp = xbuf; cp < &xbuf[send_len]; cp++) |
257 | fprintf(stderr, "%02x ", (unsigned char) *cp); | 215 | fprintf(stderr, "%02x ", (unsigned char) *cp); |
258 | fprintf(stderr, "\n"); | 216 | fprintf(stderr, "\n"); |
259 | #endif | 217 | #endif |
260 | xsendto(socketfd, xbuf, len, &peer_lsa->sa, peer_lsa->len); | 218 | xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len); |
219 | /* Was it final ACK? then exit */ | ||
220 | if (finished && (opcode == TFTP_ACK)) | ||
221 | goto ret; | ||
261 | 222 | ||
262 | if (finished && (opcode == TFTP_ACK)) { | 223 | /* Receive packet */ |
263 | break; | ||
264 | } | ||
265 | |||
266 | /* receive packet */ | ||
267 | recv_again: | 224 | recv_again: |
268 | tv.tv_sec = TFTP_TIMEOUT; | 225 | tv.tv_sec = TFTP_TIMEOUT; |
269 | tv.tv_usec = 0; | 226 | tv.tv_usec = 0; |
270 | |||
271 | FD_ZERO(&rfds); | 227 | FD_ZERO(&rfds); |
272 | FD_SET(socketfd, &rfds); | 228 | FD_SET(socketfd, &rfds); |
273 | |||
274 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { | 229 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { |
275 | unsigned from_port; | 230 | unsigned from_port; |
276 | case 1: | 231 | case 1: |
@@ -280,7 +235,7 @@ static int tftp( | |||
280 | &from->sa, &from->len); | 235 | &from->sa, &from->len); |
281 | if (len < 0) { | 236 | if (len < 0) { |
282 | bb_perror_msg("recvfrom"); | 237 | bb_perror_msg("recvfrom"); |
283 | break; | 238 | goto ret; |
284 | } | 239 | } |
285 | from_port = get_nport(&from->sa); | 240 | from_port = get_nport(&from->sa); |
286 | if (port == org_port) { | 241 | if (port == org_port) { |
@@ -292,57 +247,57 @@ static int tftp( | |||
292 | } | 247 | } |
293 | if (port != from_port) | 248 | if (port != from_port) |
294 | goto recv_again; | 249 | goto recv_again; |
295 | timeout = 0; | 250 | goto recvd_good; |
296 | break; | ||
297 | case 0: | 251 | case 0: |
298 | bb_error_msg("timeout"); | ||
299 | timeout--; | 252 | timeout--; |
300 | if (timeout == 0) { | 253 | if (timeout == 0) { |
301 | len = -1; | ||
302 | bb_error_msg("last timeout"); | 254 | bb_error_msg("last timeout"); |
255 | goto ret; | ||
303 | } | 256 | } |
304 | break; | 257 | bb_error_msg("last timeout" + 5); |
258 | goto send_again; /* resend last sent pkt */ | ||
305 | default: | 259 | default: |
306 | bb_perror_msg("select"); | 260 | bb_perror_msg("select"); |
307 | len = -1; | 261 | goto ret; |
308 | } | 262 | } |
263 | } /* while we don't see recv packet with correct port# */ | ||
309 | 264 | ||
310 | } while (timeout && (len >= 0)); | 265 | /* Process recv'ed packet */ |
311 | 266 | recvd_good: | |
312 | if (finished || (len < 0)) { | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | /* process received packet */ | ||
317 | /* (both accesses seems to be aligned) */ | ||
318 | |||
319 | opcode = ntohs( ((uint16_t*)rbuf)[0] ); | 267 | opcode = ntohs( ((uint16_t*)rbuf)[0] ); |
320 | tmp = ntohs( ((uint16_t*)rbuf)[1] ); | 268 | recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); |
321 | 269 | ||
322 | #if ENABLE_DEBUG_TFTP | 270 | #if ENABLE_DEBUG_TFTP |
323 | fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp); | 271 | fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); |
324 | #endif | 272 | #endif |
325 | 273 | ||
326 | if (opcode == TFTP_ERROR) { | 274 | if (opcode == TFTP_ERROR) { |
327 | const char *msg = NULL; | 275 | static const char *const errcode_str[] = { |
276 | "", | ||
277 | "file not found", | ||
278 | "access violation", | ||
279 | "disk full", | ||
280 | "illegal TFTP operation", | ||
281 | "unknown transfer id", | ||
282 | "file already exists", | ||
283 | "no such user", | ||
284 | }; | ||
285 | enum { NUM_ERRCODE = sizeof(errcode_str) / sizeof(errcode_str[0]) }; | ||
286 | |||
287 | const char *msg = ""; | ||
328 | 288 | ||
329 | if (rbuf[4] != '\0') { | 289 | if (rbuf[4] != '\0') { |
330 | msg = &rbuf[4]; | 290 | msg = &rbuf[4]; |
331 | rbuf[tftp_bufsize - 1] = '\0'; | 291 | rbuf[tftp_bufsize - 1] = '\0'; |
332 | } else if (tmp < (sizeof(tftp_bb_error_msg) | 292 | } else if (recv_blk < NUM_ERRCODE) { |
333 | / sizeof(char *))) { | 293 | msg = errcode_str[recv_blk]; |
334 | msg = tftp_bb_error_msg[tmp]; | ||
335 | } | ||
336 | |||
337 | if (msg) { | ||
338 | bb_error_msg("server says: %s", msg); | ||
339 | } | 294 | } |
340 | 295 | bb_error_msg("server error: (%u) %s", recv_blk, msg); | |
341 | break; | 296 | goto ret; |
342 | } | 297 | } |
298 | |||
343 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 299 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
344 | if (want_option_ack) { | 300 | if (want_option_ack) { |
345 | |||
346 | want_option_ack = 0; | 301 | want_option_ack = 0; |
347 | 302 | ||
348 | if (opcode == TFTP_OACK) { | 303 | if (opcode == TFTP_OACK) { |
@@ -350,87 +305,81 @@ static int tftp( | |||
350 | char *res; | 305 | char *res; |
351 | 306 | ||
352 | res = tftp_option_get(&rbuf[2], len - 2, "blksize"); | 307 | res = tftp_option_get(&rbuf[2], len - 2, "blksize"); |
353 | |||
354 | if (res) { | 308 | if (res) { |
355 | int blksize = xatoi_u(res); | 309 | int blksize = xatoi_u(res); |
356 | 310 | if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) { | |
357 | if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { | 311 | bb_error_msg("server proposes bad blksize %d, exiting", blksize); |
358 | if (CMD_PUT(cmd)) { | 312 | // FIXME: must also send ERROR 8 to server... |
359 | opcode = TFTP_DATA; | 313 | goto ret; |
360 | } else { | 314 | } |
361 | opcode = TFTP_ACK; | ||
362 | } | ||
363 | #if ENABLE_DEBUG_TFTP | 315 | #if ENABLE_DEBUG_TFTP |
364 | fprintf(stderr, "using blksize %u\n", | 316 | fprintf(stderr, "using blksize %u\n", |
365 | blksize); | 317 | blksize); |
366 | #endif | 318 | #endif |
367 | tftp_bufsize = blksize + 4; | 319 | tftp_bufsize = blksize + 4; |
368 | block_nr = 0; | 320 | block_nr = 0; // TODO: explain why??? |
369 | continue; | 321 | continue; |
370 | } | ||
371 | } | 322 | } |
372 | /* FIXME: | 323 | /* rfc2347: |
373 | * we should send ERROR 8 */ | 324 | * "An option not acknowledged by the server |
374 | bb_error_msg("bad server option"); | 325 | * must be ignored by the client and server |
375 | break; | 326 | * as if it were never requested." */ |
376 | } | 327 | } |
377 | 328 | ||
378 | bb_error_msg("warning: blksize not supported by server" | 329 | bb_error_msg("blksize is not supported by server" |
379 | " - reverting to 512"); | 330 | " - reverting to 512"); |
380 | |||
381 | tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; | 331 | tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; |
382 | } | 332 | } |
383 | #endif | 333 | #endif |
334 | /* block_nr is already advanced to next block# we expect | ||
335 | * to get / block# we are about to send next time */ | ||
384 | 336 | ||
385 | if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { | 337 | if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { |
386 | if (tmp == block_nr) { | 338 | if (recv_blk == block_nr) { |
387 | len = full_write(localfd, &rbuf[4], len - 4); | 339 | len = full_write(localfd, &rbuf[4], len - 4); |
388 | |||
389 | if (len < 0) { | 340 | if (len < 0) { |
390 | bb_perror_msg(bb_msg_write_error); | 341 | bb_perror_msg(bb_msg_write_error); |
391 | break; | 342 | goto ret; |
392 | } | 343 | } |
393 | |||
394 | if (len != (tftp_bufsize - 4)) { | 344 | if (len != (tftp_bufsize - 4)) { |
395 | finished++; | 345 | finished = 1; |
396 | } | 346 | } |
397 | 347 | continue; /* send ACK */ | |
398 | opcode = TFTP_ACK; | ||
399 | continue; | ||
400 | } | 348 | } |
401 | /* in case the last ack disappeared into the ether */ | 349 | if (recv_blk == (block_nr - 1)) { |
402 | if (tmp == (block_nr - 1)) { | ||
403 | --block_nr; | ||
404 | opcode = TFTP_ACK; | ||
405 | continue; | ||
406 | // tmp==(block_nr-1) and (tmp+1)==block_nr is always same, I think. wtf? | ||
407 | } else if (tmp + 1 == block_nr) { | ||
408 | /* Server lost our TFTP_ACK. Resend it */ | 350 | /* Server lost our TFTP_ACK. Resend it */ |
409 | block_nr = tmp; | 351 | block_nr = recv_blk; |
410 | opcode = TFTP_ACK; | ||
411 | continue; | 352 | continue; |
412 | } | 353 | } |
413 | } | 354 | } |
414 | 355 | ||
415 | if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { | 356 | if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { |
416 | if (tmp == (uint16_t) (block_nr - 1)) { | 357 | /* did server ACK our last DATA pkt? */ |
417 | if (finished) { | 358 | if (recv_blk == (uint16_t) (block_nr - 1)) { |
418 | break; | 359 | if (finished) |
419 | } | 360 | goto ret; |
420 | 361 | continue; /* send next block */ | |
421 | opcode = TFTP_DATA; | ||
422 | continue; | ||
423 | } | 362 | } |
424 | } | 363 | } |
364 | /* Awww... recv'd packet is not recognized! */ | ||
365 | goto recv_again; | ||
366 | /* why recv_again? - rfc1123 says: | ||
367 | * "The sender (i.e., the side originating the DATA packets) | ||
368 | * must never resend the current DATA packet on receipt | ||
369 | * of a duplicate ACK". | ||
370 | * DATA pkts are resent ONLY on timeout. | ||
371 | * Thus "goto send_again" will ba a bad mistake above. | ||
372 | * See: | ||
373 | * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome | ||
374 | */ | ||
425 | } | 375 | } |
426 | 376 | ret: | |
427 | if (ENABLE_FEATURE_CLEAN_UP) { | 377 | if (ENABLE_FEATURE_CLEAN_UP) { |
428 | close(socketfd); | 378 | close(socketfd); |
429 | free(xbuf); | 379 | free(xbuf); |
430 | free(rbuf); | 380 | free(rbuf); |
431 | } | 381 | } |
432 | 382 | return finished == 0; /* returns 1 on failure */ | |
433 | return finished ? EXIT_SUCCESS : EXIT_FAILURE; | ||
434 | } | 383 | } |
435 | 384 | ||
436 | int tftp_main(int argc, char **argv); | 385 | int tftp_main(int argc, char **argv); |
@@ -458,6 +407,7 @@ int tftp_main(int argc, char **argv) | |||
458 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), | 407 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), |
459 | &localfile, &remotefile | 408 | &localfile, &remotefile |
460 | USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize)); | 409 | USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize)); |
410 | argv += optind; | ||
461 | 411 | ||
462 | flags = O_RDONLY; | 412 | flags = O_RDONLY; |
463 | if (CMD_GET(cmd)) | 413 | if (CMD_GET(cmd)) |
@@ -472,25 +422,26 @@ int tftp_main(int argc, char **argv) | |||
472 | } | 422 | } |
473 | #endif | 423 | #endif |
474 | 424 | ||
475 | if (localfile == NULL) | 425 | if (!localfile) |
476 | localfile = remotefile; | 426 | localfile = remotefile; |
477 | if (remotefile == NULL) | 427 | if (!remotefile) |
478 | remotefile = localfile; | 428 | remotefile = localfile; |
479 | if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL)) | 429 | /* Error if filename or host is not known */ |
430 | if (!remotefile || !argv[0]) | ||
480 | bb_show_usage(); | 431 | bb_show_usage(); |
481 | 432 | ||
482 | if (localfile == NULL || LONE_DASH(localfile)) { | 433 | if (LONE_DASH(localfile)) { |
483 | fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; | 434 | fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; |
484 | } else { | 435 | } else { |
485 | fd = xopen3(localfile, flags, 0644); | 436 | fd = xopen(localfile, flags); |
486 | } | 437 | } |
487 | 438 | ||
488 | port = bb_lookup_port(argv[optind + 1], "udp", 69); | 439 | port = bb_lookup_port(argv[1], "udp", 69); |
489 | peer_lsa = xhost2sockaddr(argv[optind], port); | 440 | peer_lsa = xhost2sockaddr(argv[0], port); |
490 | 441 | ||
491 | #if ENABLE_DEBUG_TFTP | 442 | #if ENABLE_DEBUG_TFTP |
492 | fprintf(stderr, "using server \"%s\", " | 443 | fprintf(stderr, "using server \"%s\", " |
493 | "remotefile \"%s\", localfile \"%s\".\n", | 444 | "remotefile \"%s\", localfile \"%s\"\n", |
494 | xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len), | 445 | xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len), |
495 | remotefile, localfile); | 446 | remotefile, localfile); |
496 | #endif | 447 | #endif |
@@ -501,11 +452,10 @@ int tftp_main(int argc, char **argv) | |||
501 | #endif | 452 | #endif |
502 | peer_lsa, remotefile, fd, port, blocksize); | 453 | peer_lsa, remotefile, fd, port, blocksize); |
503 | 454 | ||
504 | if (fd > 1) { | 455 | if (ENABLE_FEATURE_CLEAN_UP) |
505 | if (ENABLE_FEATURE_CLEAN_UP) | 456 | close(fd); |
506 | close(fd); | 457 | if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) { |
507 | if (CMD_GET(cmd) && result != EXIT_SUCCESS) | 458 | unlink(localfile); |
508 | unlink(localfile); | ||
509 | } | 459 | } |
510 | return result; | 460 | return result; |
511 | } | 461 | } |