diff options
author | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2006-06-10 14:15:03 +0000 |
---|---|---|
committer | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2006-06-10 14:15:03 +0000 |
commit | b25f98a417233f8c470ad61a6e191ff3aa8bd633 (patch) | |
tree | dd3a1f2b55d2a34638c89e898b62200e548dfb64 /networking/tftp.c | |
parent | 3b1936dcf9d1df4f4a814de3c372258ee63b7cb3 (diff) | |
download | busybox-w32-b25f98a417233f8c470ad61a6e191ff3aa8bd633.tar.gz busybox-w32-b25f98a417233f8c470ad61a6e191ff3aa8bd633.tar.bz2 busybox-w32-b25f98a417233f8c470ad61a6e191ff3aa8bd633.zip |
- fix two segfaults (reported by Horst Kronstorfer)
- remove dangling file if get fails (spotted and fixed by Jason Schoon)
- shrink it (Bernhard Fischer)
Thanks, all!
text data bss dec hex filename
2684 0 0 2684 a7c networking/tftp.o.orig
2748 0 0 2748 abc networking/tftp.o.allfixed
2666 0 0 2666 a6a networking/tftp.o.+shrink
Diffstat (limited to 'networking/tftp.c')
-rw-r--r-- | networking/tftp.c | 286 |
1 files changed, 139 insertions, 147 deletions
diff --git a/networking/tftp.c b/networking/tftp.c index 527e3dc11..e32c5de38 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -33,13 +33,22 @@ | |||
33 | 33 | ||
34 | #include "busybox.h" | 34 | #include "busybox.h" |
35 | 35 | ||
36 | //#define CONFIG_FEATURE_TFTP_DEBUG | ||
37 | 36 | ||
38 | #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ | 37 | #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ |
39 | #define TFTP_TIMEOUT 5 /* seconds */ | 38 | #define TFTP_TIMEOUT 5 /* seconds */ |
39 | #define TFTP_NUM_RETRIES 5 /* number of retries */ | ||
40 | 40 | ||
41 | /* opcodes we support */ | 41 | /* RFC2348 says between 8 and 65464 */ |
42 | #define TFTP_OCTECTS_MIN 8 | ||
43 | #define TFTP_OCTECTS_MAX 65464 | ||
44 | |||
45 | static const char * const MODE_OCTET = "octet"; | ||
46 | #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/ | ||
42 | 47 | ||
48 | static const char * const OPTION_BLOCKSIZE = "blksize"; | ||
49 | #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */ | ||
50 | |||
51 | /* opcodes we support */ | ||
43 | #define TFTP_RRQ 1 | 52 | #define TFTP_RRQ 1 |
44 | #define TFTP_WRQ 2 | 53 | #define TFTP_WRQ 2 |
45 | #define TFTP_DATA 3 | 54 | #define TFTP_DATA 3 |
@@ -47,7 +56,7 @@ | |||
47 | #define TFTP_ERROR 5 | 56 | #define TFTP_ERROR 5 |
48 | #define TFTP_OACK 6 | 57 | #define TFTP_OACK 6 |
49 | 58 | ||
50 | static const char * const tftp_bb_error_msg[] = { | 59 | static const char *const tftp_bb_error_msg[] = { |
51 | "Undefined error", | 60 | "Undefined error", |
52 | "File not found", | 61 | "File not found", |
53 | "Access violation", | 62 | "Access violation", |
@@ -58,13 +67,10 @@ static const char * const tftp_bb_error_msg[] = { | |||
58 | "No such user" | 67 | "No such user" |
59 | }; | 68 | }; |
60 | 69 | ||
61 | #ifdef CONFIG_FEATURE_TFTP_GET | 70 | #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET |
62 | # define tftp_cmd_get 1 | 71 | |
63 | #else | 72 | #if ENABLE_FEATURE_TFTP_PUT |
64 | # define tftp_cmd_get 0 | 73 | # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT) |
65 | #endif | ||
66 | #ifdef CONFIG_FEATURE_TFTP_PUT | ||
67 | # define tftp_cmd_put (tftp_cmd_get+1) | ||
68 | #else | 74 | #else |
69 | # define tftp_cmd_put 0 | 75 | # define tftp_cmd_put 0 |
70 | #endif | 76 | #endif |
@@ -81,15 +87,15 @@ static int tftp_blocksize_check(int blocksize, int bufsize) | |||
81 | */ | 87 | */ |
82 | 88 | ||
83 | if ((bufsize && (blocksize > bufsize)) || | 89 | if ((bufsize && (blocksize > bufsize)) || |
84 | (blocksize < 8) || (blocksize > 65464)) { | 90 | (blocksize < TFTP_OCTECTS_MIN) || (blocksize > TFTP_OCTECTS_MAX)) { |
85 | bb_error_msg("bad blocksize"); | 91 | bb_error_msg("bad blocksize"); |
86 | return 0; | 92 | return 0; |
87 | } | 93 | } |
88 | 94 | ||
89 | return blocksize; | 95 | return blocksize; |
90 | } | 96 | } |
91 | 97 | ||
92 | static char *tftp_option_get(char *buf, int len, char *option) | 98 | static char *tftp_option_get(char *buf, int len, const char const *option) |
93 | { | 99 | { |
94 | int opt_val = 0; | 100 | int opt_val = 0; |
95 | int opt_found = 0; | 101 | int opt_found = 0; |
@@ -97,25 +103,24 @@ static char *tftp_option_get(char *buf, int len, char *option) | |||
97 | 103 | ||
98 | while (len > 0) { | 104 | while (len > 0) { |
99 | 105 | ||
100 | /* Make sure the options are terminated correctly */ | 106 | /* Make sure the options are terminated correctly */ |
101 | 107 | ||
102 | for (k = 0; k < len; k++) { | 108 | for (k = 0; k < len; k++) { |
103 | if (buf[k] == '\0') { | 109 | if (buf[k] == '\0') { |
104 | break; | 110 | break; |
105 | } | 111 | } |
106 | } | 112 | } |
107 | 113 | ||
108 | if (k >= len) { | 114 | if (k >= len) { |
109 | break; | 115 | break; |
110 | } | 116 | } |
111 | 117 | ||
112 | if (opt_val == 0) { | 118 | if (opt_val == 0) { |
113 | if (strcasecmp(buf, option) == 0) { | 119 | if (strcasecmp(buf, option) == 0) { |
114 | opt_found = 1; | 120 | opt_found = 1; |
115 | } | 121 | } |
116 | } | 122 | } else { |
117 | else { | 123 | if (opt_found) { |
118 | if (opt_found) { | ||
119 | return buf; | 124 | return buf; |
120 | } | 125 | } |
121 | } | 126 | } |
@@ -133,38 +138,34 @@ static char *tftp_option_get(char *buf, int len, char *option) | |||
133 | 138 | ||
134 | #endif | 139 | #endif |
135 | 140 | ||
136 | static inline int tftp(const int cmd, const struct hostent *host, | 141 | static int tftp(const int cmd, const struct hostent *host, |
137 | const char *remotefile, int localfd, const unsigned short port, int tftp_bufsize) | 142 | const char *remotefile, const int localfd, |
143 | const unsigned short port, int tftp_bufsize) | ||
138 | { | 144 | { |
139 | const int cmd_get = cmd & tftp_cmd_get; | 145 | #define cmd_get cmd & tftp_cmd_get |
140 | const int cmd_put = cmd & tftp_cmd_put; | 146 | #define cmd_put cmd & tftp_cmd_put |
141 | const int bb_tftp_num_retries = 5; | ||
142 | |||
143 | struct sockaddr_in sa; | 147 | struct sockaddr_in sa; |
144 | struct sockaddr_in from; | 148 | struct sockaddr_in from; |
145 | struct timeval tv; | 149 | struct timeval tv; |
146 | socklen_t fromlen; | 150 | socklen_t fromlen; |
147 | fd_set rfds; | 151 | fd_set rfds; |
148 | char *cp; | ||
149 | unsigned short tmp; | ||
150 | int socketfd; | 152 | int socketfd; |
151 | int len; | 153 | int len, itmp; |
152 | int opcode = 0; | 154 | int opcode = 0; |
153 | int finished = 0; | 155 | int finished = 0; |
154 | int timeout = bb_tftp_num_retries; | 156 | int timeout = TFTP_NUM_RETRIES; |
155 | unsigned short block_nr = 1; | 157 | unsigned short block_nr = 1; |
158 | unsigned short tmp; | ||
159 | char *cp; | ||
156 | 160 | ||
157 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE | 161 | USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) |
158 | int want_option_ack = 0; | ||
159 | #endif | ||
160 | 162 | ||
161 | /* Can't use RESERVE_CONFIG_BUFFER here since the allocation | 163 | /* Can't use RESERVE_CONFIG_BUFFER here since the allocation |
162 | * size varies meaning BUFFERS_GO_ON_STACK would fail */ | 164 | * size varies meaning BUFFERS_GO_ON_STACK would fail */ |
163 | char *buf=xmalloc(tftp_bufsize + 4); | 165 | char *buf=xmalloc(tftp_bufsize += 4); |
164 | |||
165 | tftp_bufsize += 4; | ||
166 | 166 | ||
167 | if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { /* bb_xsocket? */ | 167 | if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { |
168 | /* need to unlink the localfile, so don't use bb_xsocket here. */ | ||
168 | bb_perror_msg("socket"); | 169 | bb_perror_msg("socket"); |
169 | return EXIT_FAILURE; | 170 | return EXIT_FAILURE; |
170 | } | 171 | } |
@@ -180,11 +181,9 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
180 | sizeof(sa.sin_addr)); | 181 | sizeof(sa.sin_addr)); |
181 | 182 | ||
182 | /* build opcode */ | 183 | /* build opcode */ |
183 | |||
184 | if (cmd_get) { | 184 | if (cmd_get) { |
185 | opcode = TFTP_RRQ; | 185 | opcode = TFTP_RRQ; |
186 | } | 186 | } |
187 | |||
188 | if (cmd_put) { | 187 | if (cmd_put) { |
189 | opcode = TFTP_WRQ; | 188 | opcode = TFTP_WRQ; |
190 | } | 189 | } |
@@ -194,56 +193,49 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
194 | cp = buf; | 193 | cp = buf; |
195 | 194 | ||
196 | /* first create the opcode part */ | 195 | /* first create the opcode part */ |
197 | |||
198 | *((unsigned short *) cp) = htons(opcode); | 196 | *((unsigned short *) cp) = htons(opcode); |
199 | |||
200 | cp += 2; | 197 | cp += 2; |
201 | 198 | ||
202 | /* add filename and mode */ | 199 | /* add filename and mode */ |
203 | 200 | if (((cmd_get) && (opcode == TFTP_RRQ)) || | |
204 | if ((cmd_get && (opcode == TFTP_RRQ)) || | 201 | ((cmd_put) && (opcode == TFTP_WRQ))) |
205 | (cmd_put && (opcode == TFTP_WRQ))) { | 202 | { |
206 | int too_long = 0; | 203 | int too_long = 0; |
207 | 204 | ||
208 | /* see if the filename fits into buf */ | 205 | /* see if the filename fits into buf |
209 | /* and fill in packet */ | 206 | * and fill in packet. */ |
210 | |||
211 | len = strlen(remotefile) + 1; | 207 | len = strlen(remotefile) + 1; |
212 | 208 | ||
213 | if ((cp + len) >= &buf[tftp_bufsize - 1]) { | 209 | if ((cp + len) >= &buf[tftp_bufsize - 1]) { |
214 | too_long = 1; | 210 | too_long = 1; |
215 | } | 211 | } else { |
216 | else { | 212 | safe_strncpy(cp, remotefile, len); |
217 | safe_strncpy(cp, remotefile, len); | ||
218 | cp += len; | 213 | cp += len; |
219 | } | 214 | } |
220 | 215 | ||
221 | if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) { | 216 | if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) { |
222 | bb_error_msg("too long remote-filename"); | 217 | bb_error_msg("remote filename too long"); |
223 | break; | 218 | break; |
224 | } | 219 | } |
225 | 220 | ||
226 | /* add "mode" part of the package */ | 221 | /* add "mode" part of the package */ |
227 | 222 | memcpy(cp, MODE_OCTET, MODE_OCTET_LEN); | |
228 | memcpy(cp, "octet", 6); | 223 | cp += MODE_OCTET_LEN; |
229 | cp += 6; | ||
230 | 224 | ||
231 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE | 225 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE |
232 | 226 | ||
233 | len = tftp_bufsize - 4; /* data block size */ | 227 | len = tftp_bufsize - 4; /* data block size */ |
234 | 228 | ||
235 | if (len != TFTP_BLOCKSIZE_DEFAULT) { | 229 | if (len != TFTP_BLOCKSIZE_DEFAULT) { |
236 | 230 | ||
237 | if ((&buf[tftp_bufsize - 1] - cp) < 15) { | 231 | if ((&buf[tftp_bufsize - 1] - cp) < 15) { |
238 | bb_error_msg("too long remote-filename"); | 232 | bb_error_msg("remote filename too long"); |
239 | break; | 233 | break; |
240 | } | 234 | } |
241 | 235 | ||
242 | /* add "blksize" + number of blocks */ | 236 | /* add "blksize" + number of blocks */ |
243 | 237 | memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN); | |
244 | memcpy(cp, "blksize", 8); | 238 | cp += OPTION_BLOCKSIZE_LEN; |
245 | cp += 8; | ||
246 | |||
247 | cp += snprintf(cp, 6, "%d", len) + 1; | 239 | cp += snprintf(cp, 6, "%d", len) + 1; |
248 | 240 | ||
249 | want_option_ack = 1; | 241 | want_option_ack = 1; |
@@ -253,8 +245,8 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
253 | 245 | ||
254 | /* add ack and data */ | 246 | /* add ack and data */ |
255 | 247 | ||
256 | if ((cmd_get && (opcode == TFTP_ACK)) || | 248 | if (((cmd_get) && (opcode == TFTP_ACK)) || |
257 | (cmd_put && (opcode == TFTP_DATA))) { | 249 | ((cmd_put) && (opcode == TFTP_DATA))) { |
258 | 250 | ||
259 | *((unsigned short *) cp) = htons(block_nr); | 251 | *((unsigned short *) cp) = htons(block_nr); |
260 | 252 | ||
@@ -262,7 +254,7 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
262 | 254 | ||
263 | block_nr++; | 255 | block_nr++; |
264 | 256 | ||
265 | if (cmd_put && (opcode == TFTP_DATA)) { | 257 | if ((cmd_put) && (opcode == TFTP_DATA)) { |
266 | len = bb_full_read(localfd, cp, tftp_bufsize - 4); | 258 | len = bb_full_read(localfd, cp, tftp_bufsize - 4); |
267 | 259 | ||
268 | if (len < 0) { | 260 | if (len < 0) { |
@@ -282,7 +274,7 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
282 | /* send packet */ | 274 | /* send packet */ |
283 | 275 | ||
284 | 276 | ||
285 | timeout = bb_tftp_num_retries; /* re-initialize */ | 277 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ |
286 | do { | 278 | do { |
287 | 279 | ||
288 | len = cp - buf; | 280 | len = cp - buf; |
@@ -290,11 +282,11 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
290 | #ifdef CONFIG_FEATURE_TFTP_DEBUG | 282 | #ifdef CONFIG_FEATURE_TFTP_DEBUG |
291 | fprintf(stderr, "sending %u bytes\n", len); | 283 | fprintf(stderr, "sending %u bytes\n", len); |
292 | for (cp = buf; cp < &buf[len]; cp++) | 284 | for (cp = buf; cp < &buf[len]; cp++) |
293 | fprintf(stderr, "%02x ", (unsigned char)*cp); | 285 | fprintf(stderr, "%02x ", (unsigned char) *cp); |
294 | fprintf(stderr, "\n"); | 286 | fprintf(stderr, "\n"); |
295 | #endif | 287 | #endif |
296 | if (sendto(socketfd, buf, len, 0, | 288 | if (sendto(socketfd, buf, len, 0, |
297 | (struct sockaddr *) &sa, sizeof(sa)) < 0) { | 289 | (struct sockaddr *) &sa, sizeof(sa)) < 0) { |
298 | bb_perror_msg("send"); | 290 | bb_perror_msg("send"); |
299 | len = -1; | 291 | len = -1; |
300 | break; | 292 | break; |
@@ -316,10 +308,10 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
316 | FD_ZERO(&rfds); | 308 | FD_ZERO(&rfds); |
317 | FD_SET(socketfd, &rfds); | 309 | FD_SET(socketfd, &rfds); |
318 | 310 | ||
319 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { | 311 | itmp = select(socketfd + 1, &rfds, NULL, NULL, &tv); |
320 | case 1: | 312 | if (itmp == 1) { |
321 | len = recvfrom(socketfd, buf, tftp_bufsize, 0, | 313 | len = recvfrom(socketfd, buf, tftp_bufsize, 0, |
322 | (struct sockaddr *) &from, &fromlen); | 314 | (struct sockaddr *) &from, &fromlen); |
323 | 315 | ||
324 | if (len < 0) { | 316 | if (len < 0) { |
325 | bb_perror_msg("recvfrom"); | 317 | bb_perror_msg("recvfrom"); |
@@ -337,9 +329,9 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
337 | 329 | ||
338 | /* fall-through for bad packets! */ | 330 | /* fall-through for bad packets! */ |
339 | /* discard the packet - treat as timeout */ | 331 | /* discard the packet - treat as timeout */ |
340 | timeout = bb_tftp_num_retries; | 332 | timeout = TFTP_NUM_RETRIES; |
341 | 333 | ||
342 | case 0: | 334 | } else if (itmp == 0) { |
343 | bb_error_msg("timeout"); | 335 | bb_error_msg("timeout"); |
344 | 336 | ||
345 | timeout--; | 337 | timeout--; |
@@ -349,7 +341,7 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
349 | } | 341 | } |
350 | break; | 342 | break; |
351 | 343 | ||
352 | default: | 344 | } else { |
353 | bb_perror_msg("select"); | 345 | bb_perror_msg("select"); |
354 | len = -1; | 346 | len = -1; |
355 | } | 347 | } |
@@ -362,7 +354,6 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
362 | 354 | ||
363 | /* process received packet */ | 355 | /* process received packet */ |
364 | 356 | ||
365 | |||
366 | opcode = ntohs(*((unsigned short *) buf)); | 357 | opcode = ntohs(*((unsigned short *) buf)); |
367 | tmp = ntohs(*((unsigned short *) &buf[2])); | 358 | tmp = ntohs(*((unsigned short *) &buf[2])); |
368 | 359 | ||
@@ -377,7 +368,7 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
377 | msg = &buf[4]; | 368 | msg = &buf[4]; |
378 | buf[tftp_bufsize - 1] = '\0'; | 369 | buf[tftp_bufsize - 1] = '\0'; |
379 | } else if (tmp < (sizeof(tftp_bb_error_msg) | 370 | } else if (tmp < (sizeof(tftp_bb_error_msg) |
380 | / sizeof(char *))) { | 371 | / sizeof(char *))) { |
381 | 372 | ||
382 | msg = tftp_bb_error_msg[tmp]; | 373 | msg = tftp_bb_error_msg[tmp]; |
383 | } | 374 | } |
@@ -388,55 +379,52 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
388 | 379 | ||
389 | break; | 380 | break; |
390 | } | 381 | } |
391 | |||
392 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE | 382 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE |
393 | if (want_option_ack) { | 383 | if (want_option_ack) { |
394 | 384 | ||
395 | want_option_ack = 0; | 385 | want_option_ack = 0; |
396 | 386 | ||
397 | if (opcode == TFTP_OACK) { | 387 | if (opcode == TFTP_OACK) { |
398 | 388 | ||
399 | /* server seems to support options */ | 389 | /* server seems to support options */ |
400 | 390 | ||
401 | char *res; | 391 | char *res; |
402 | 392 | ||
403 | res = tftp_option_get(&buf[2], len-2, | 393 | res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE); |
404 | "blksize"); | ||
405 | 394 | ||
406 | if (res) { | 395 | if (res) { |
407 | int blksize = atoi(res); | 396 | int blksize = atoi(res); |
408 | 397 | ||
409 | if (tftp_blocksize_check(blksize, | 398 | if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { |
410 | tftp_bufsize - 4)) { | ||
411 | 399 | ||
412 | if (cmd_put) { | 400 | if (cmd_put) { |
413 | opcode = TFTP_DATA; | 401 | opcode = TFTP_DATA; |
414 | } | 402 | } else { |
415 | else { | 403 | opcode = TFTP_ACK; |
416 | opcode = TFTP_ACK; | 404 | } |
417 | } | ||
418 | #ifdef CONFIG_FEATURE_TFTP_DEBUG | 405 | #ifdef CONFIG_FEATURE_TFTP_DEBUG |
419 | fprintf(stderr, "using blksize %u\n", blksize); | 406 | fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE, |
407 | blksize); | ||
420 | #endif | 408 | #endif |
421 | tftp_bufsize = blksize + 4; | 409 | tftp_bufsize = blksize + 4; |
422 | block_nr = 0; | 410 | block_nr = 0; |
423 | continue; | 411 | continue; |
424 | } | 412 | } |
425 | } | 413 | } |
426 | /* FIXME: | 414 | /* FIXME: |
427 | * we should send ERROR 8 */ | 415 | * we should send ERROR 8 */ |
428 | bb_error_msg("bad server option"); | 416 | bb_error_msg("bad server option"); |
429 | break; | 417 | break; |
430 | } | 418 | } |
431 | 419 | ||
432 | bb_error_msg("warning: blksize not supported by server" | 420 | bb_error_msg("warning: blksize not supported by server" |
433 | " - reverting to 512"); | 421 | " - reverting to 512"); |
434 | 422 | ||
435 | tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; | 423 | tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; |
436 | } | 424 | } |
437 | #endif | 425 | #endif |
438 | 426 | ||
439 | if (cmd_get && (opcode == TFTP_DATA)) { | 427 | if ((cmd_get) && (opcode == TFTP_DATA)) { |
440 | 428 | ||
441 | if (tmp == block_nr) { | 429 | if (tmp == block_nr) { |
442 | 430 | ||
@@ -455,7 +443,7 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
455 | continue; | 443 | continue; |
456 | } | 444 | } |
457 | /* in case the last ack disappeared into the ether */ | 445 | /* in case the last ack disappeared into the ether */ |
458 | if ( tmp == (block_nr - 1) ) { | 446 | if (tmp == (block_nr - 1)) { |
459 | --block_nr; | 447 | --block_nr; |
460 | opcode = TFTP_ACK; | 448 | opcode = TFTP_ACK; |
461 | continue; | 449 | continue; |
@@ -467,9 +455,9 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
467 | } | 455 | } |
468 | } | 456 | } |
469 | 457 | ||
470 | if (cmd_put && (opcode == TFTP_ACK)) { | 458 | if ((cmd_put) && (opcode == TFTP_ACK)) { |
471 | 459 | ||
472 | if (tmp == (unsigned short)(block_nr - 1)) { | 460 | if (tmp == (unsigned short) (block_nr - 1)) { |
473 | if (finished) { | 461 | if (finished) { |
474 | break; | 462 | break; |
475 | } | 463 | } |
@@ -482,7 +470,6 @@ static inline int tftp(const int cmd, const struct hostent *host, | |||
482 | 470 | ||
483 | #ifdef CONFIG_FEATURE_CLEAN_UP | 471 | #ifdef CONFIG_FEATURE_CLEAN_UP |
484 | close(socketfd); | 472 | close(socketfd); |
485 | |||
486 | free(buf); | 473 | free(buf); |
487 | #endif | 474 | #endif |
488 | 475 | ||
@@ -505,6 +492,7 @@ int tftp_main(int argc, char **argv) | |||
505 | 492 | ||
506 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE | 493 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE |
507 | char *sblocksize = NULL; | 494 | char *sblocksize = NULL; |
495 | |||
508 | #define BS "b:" | 496 | #define BS "b:" |
509 | #define BS_ARG , &sblocksize | 497 | #define BS_ARG , &sblocksize |
510 | #else | 498 | #else |
@@ -533,62 +521,66 @@ int tftp_main(int argc, char **argv) | |||
533 | #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) | 521 | #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) |
534 | bb_opt_complementally = GET_COMPL PUT_COMPL; | 522 | bb_opt_complementally = GET_COMPL PUT_COMPL; |
535 | #else | 523 | #else |
536 | /* XXX: may be should #error ? */ | 524 | #error "Either CONFIG_FEATURE_TFTP_GET or CONFIG_FEATURE_TFTP_PUT must be defined" |
537 | #endif | 525 | #endif |
538 | 526 | ||
539 | 527 | ||
540 | cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS, | 528 | cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS, |
541 | &localfile, &remotefile BS_ARG); | 529 | &localfile, &remotefile BS_ARG); |
542 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE | ||
543 | if(sblocksize) { | ||
544 | blocksize = atoi(sblocksize); | ||
545 | if (!tftp_blocksize_check(blocksize, 0)) { | ||
546 | return EXIT_FAILURE; | ||
547 | } | ||
548 | } | ||
549 | #endif | ||
550 | 530 | ||
551 | cmd &= (tftp_cmd_get | tftp_cmd_put); | 531 | cmd &= (tftp_cmd_get | tftp_cmd_put); |
552 | #ifdef CONFIG_FEATURE_TFTP_GET | 532 | #ifdef CONFIG_FEATURE_TFTP_GET |
553 | if(cmd == tftp_cmd_get) | 533 | if (cmd == tftp_cmd_get) |
554 | flags = O_WRONLY | O_CREAT | O_TRUNC; | 534 | flags = O_WRONLY | O_CREAT | O_TRUNC; |
555 | #endif | 535 | #endif |
556 | #ifdef CONFIG_FEATURE_TFTP_PUT | 536 | #ifdef CONFIG_FEATURE_TFTP_PUT |
557 | if(cmd == tftp_cmd_put) | 537 | if (cmd == tftp_cmd_put) |
558 | flags = O_RDONLY; | 538 | flags = O_RDONLY; |
559 | #endif | 539 | #endif |
560 | 540 | ||
561 | if(localfile == NULL) | 541 | #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE |
562 | localfile = remotefile; | 542 | if (sblocksize) { |
563 | if(remotefile == NULL) | 543 | blocksize = atoi(sblocksize); |
564 | remotefile = localfile; | 544 | if (!tftp_blocksize_check(blocksize, 0)) { |
565 | /* XXX: I corrected this, but may be wrong too. vodz */ | 545 | return EXIT_FAILURE; |
566 | if(localfile==NULL || strcmp(localfile, "-") == 0) { | 546 | } |
567 | fd = fileno((cmd==tftp_cmd_get)? stdout : stdin); | 547 | } |
568 | } else if (fd==-1) { | 548 | #endif |
569 | fd = open(localfile, flags, 0644); | 549 | |
550 | if (localfile == NULL) | ||
551 | localfile = remotefile; | ||
552 | if (remotefile == NULL) | ||
553 | remotefile = localfile; | ||
554 | if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL)) | ||
555 | bb_show_usage(); | ||
556 | |||
557 | if (localfile == NULL || strcmp(localfile, "-") == 0) { | ||
558 | fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO; | ||
559 | } else { | ||
560 | fd = open(localfile, flags, 0644); /* fail below */ | ||
570 | } | 561 | } |
571 | if (fd < 0) { | 562 | if (fd < 0) { |
572 | bb_perror_msg_and_die("local file"); | 563 | bb_perror_msg_and_die("local file"); |
573 | } | 564 | } |
574 | 565 | ||
575 | /* XXX: argv[optind] and/or argv[optind + 1] may be NULL! */ | ||
576 | host = xgethostbyname(argv[optind]); | 566 | host = xgethostbyname(argv[optind]); |
577 | port = bb_lookup_port(argv[optind + 1], "udp", 69); | 567 | port = bb_lookup_port(argv[optind + 1], "udp", 69); |
578 | 568 | ||
579 | #ifdef CONFIG_FEATURE_TFTP_DEBUG | 569 | #ifdef CONFIG_FEATURE_TFTP_DEBUG |
580 | fprintf(stderr, "using server \"%s\", remotefile \"%s\", " | 570 | fprintf(stderr, "using server \"%s\", remotefile \"%s\", " |
581 | "localfile \"%s\".\n", | 571 | "localfile \"%s\".\n", |
582 | inet_ntoa(*((struct in_addr *) host->h_addr)), | 572 | inet_ntoa(*((struct in_addr *) host->h_addr)), |
583 | remotefile, localfile); | 573 | remotefile, localfile); |
584 | #endif | 574 | #endif |
585 | 575 | ||
586 | result = tftp(cmd, host, remotefile, fd, port, blocksize); | 576 | result = tftp(cmd, host, remotefile, fd, port, blocksize); |
587 | 577 | ||
588 | #ifdef CONFIG_FEATURE_CLEAN_UP | 578 | #ifdef CONFIG_FEATURE_CLEAN_UP |
589 | if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) { | 579 | if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) { |
590 | close(fd); | 580 | close(fd); |
591 | } | 581 | } |
592 | #endif | 582 | #endif |
593 | return(result); | 583 | if (cmd == tftp_cmd_get && result != EXIT_SUCCESS) |
584 | unlink(localfile); | ||
585 | return (result); | ||
594 | } | 586 | } |