Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/networking/tftp.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/networking/tftp.c
r821 r1770 20 20 * ------------------------------------------------------------------------- */ 21 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <netdb.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 #include <unistd.h> 32 #include <fcntl.h> 33 34 #include "busybox.h" 35 22 #include "libbb.h" 23 24 25 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT 36 26 37 27 #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ 38 28 #define TFTP_TIMEOUT 5 /* seconds */ 39 29 #define TFTP_NUM_RETRIES 5 /* number of retries */ 40 41 static const char * const MODE_OCTET = "octet";42 #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/43 44 static const char * const OPTION_BLOCKSIZE = "blksize";45 #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */46 30 47 31 /* opcodes we support */ … … 53 37 #define TFTP_OACK 6 54 38 55 static const char *const tftp_bb_error_msg[] = { 56 "Undefined error", 57 "File not found", 58 "Access violation", 59 "Disk full or allocation error", 60 "Illegal TFTP operation", 61 "Unknown transfer ID", 62 "File already exists", 63 "No such user" 64 }; 65 66 #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET 67 68 #if ENABLE_FEATURE_TFTP_PUT 69 # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT) 39 #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT 40 #define USE_GETPUT(...) 41 #define CMD_GET(cmd) 1 42 #define CMD_PUT(cmd) 0 43 #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT 44 #define USE_GETPUT(...) 45 #define CMD_GET(cmd) 0 46 #define CMD_PUT(cmd) 1 70 47 #else 71 # define tftp_cmd_put 0 72 #endif 73 74 75 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 48 #define USE_GETPUT(...) __VA_ARGS__ 49 /* masks coming from getpot32 */ 50 #define CMD_GET(cmd) ((cmd) & 1) 51 #define CMD_PUT(cmd) ((cmd) & 2) 52 #endif 53 /* NB: in the code below 54 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive 55 */ 56 57 58 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 76 59 77 60 static int tftp_blocksize_check(int blocksize, int bufsize) … … 83 66 */ 84 67 85 if ((bufsize && (blocksize > bufsize)) || 86 (blocksize < 8) || (blocksize > 65564)) { 68 if ((bufsize && (blocksize > bufsize)) 69 || (blocksize < 8) || (blocksize > 65564) 70 ) { 87 71 bb_error_msg("bad blocksize"); 88 72 return 0; … … 92 76 } 93 77 94 static char *tftp_option_get(char *buf, int len, const char * constoption)78 static char *tftp_option_get(char *buf, int len, const char *option) 95 79 { 96 80 int opt_val = 0; … … 99 83 100 84 while (len > 0) { 101 102 85 /* Make sure the options are terminated correctly */ 103 104 86 for (k = 0; k < len; k++) { 105 87 if (buf[k] == '\0') { 106 break; 107 } 108 } 109 110 if (k >= len) { 111 break; 112 } 113 88 goto nul_found; 89 } 90 } 91 return NULL; 92 nul_found: 114 93 if (opt_val == 0) { 115 94 if (strcasecmp(buf, option) == 0) { 116 95 opt_found = 1; 117 96 } 118 } else { 119 if (opt_found) { 120 return buf; 121 } 97 } else if (opt_found) { 98 return buf; 122 99 } 123 100 124 101 k++; 125 126 102 buf += k; 127 103 len -= k; 128 129 104 opt_val ^= 1; 130 105 } … … 135 110 #endif 136 111 137 static int tftp(const int cmd, const struct hostent *host, 138 const char *remotefile, const int localfd, 139 const unsigned short port, int tftp_bufsize) 112 static int tftp( USE_GETPUT(const int cmd,) 113 len_and_sockaddr *peer_lsa, 114 const char *remotefile, const int localfd, 115 unsigned port, int tftp_bufsize) 140 116 { 141 struct sockaddr_in sa;142 struct sockaddr_in from;143 117 struct timeval tv; 144 socklen_t fromlen;145 118 fd_set rfds; 146 119 int socketfd; 147 120 int len; 148 int opcode = 0; 149 int finished = 0; 121 int send_len; 122 USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;) 123 smallint finished = 0; 124 uint16_t opcode; 125 uint16_t block_nr = 1; 126 uint16_t recv_blk; 150 127 int timeout = TFTP_NUM_RETRIES; 151 unsigned short block_nr = 1;152 unsigned short tmp;153 128 char *cp; 154 129 155 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) 130 unsigned org_port; 131 len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len); 156 132 157 133 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 158 134 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 159 char *buf=xmalloc(tftp_bufsize += 4); 160 161 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 162 /* need to unlink the localfile, so don't use bb_xsocket here. */ 163 bb_perror_msg("socket"); 164 return EXIT_FAILURE; 165 } 166 167 len = sizeof(sa); 168 169 memset(&sa, 0, len); 170 bb_xbind(socketfd, (struct sockaddr *)&sa, len); 171 172 sa.sin_family = host->h_addrtype; 173 sa.sin_port = port; 174 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, 175 sizeof(sa.sin_addr)); 135 /* We must keep the transmit and receive buffers seperate */ 136 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */ 137 char *xbuf = xmalloc(tftp_bufsize += 4); 138 char *rbuf = xmalloc(tftp_bufsize); 139 140 port = org_port = htons(port); 141 142 socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); 176 143 177 144 /* build opcode */ 178 if (cmd & tftp_cmd_get) { 145 opcode = TFTP_WRQ; 146 if (CMD_GET(cmd)) { 179 147 opcode = TFTP_RRQ; 180 148 } 181 if (cmd & tftp_cmd_put) { 182 opcode = TFTP_WRQ; 183 } 149 cp = xbuf + 2; 150 /* add filename and mode */ 151 /* fill in packet if the filename fits into xbuf */ 152 len = strlen(remotefile) + 1; 153 if (2 + len + sizeof("octet") >= tftp_bufsize) { 154 bb_error_msg("remote filename is too long"); 155 goto ret; 156 } 157 strcpy(cp, remotefile); 158 cp += len; 159 /* add "mode" part of the package */ 160 strcpy(cp, "octet"); 161 cp += sizeof("octet"); 162 163 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 164 len = tftp_bufsize - 4; /* data block size */ 165 if (len != TFTP_BLOCKSIZE_DEFAULT) { 166 /* rfc2348 says that 65464 is a max allowed value */ 167 if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { 168 bb_error_msg("remote filename is too long"); 169 goto ret; 170 } 171 /* add "blksize", <nul>, blocksize */ 172 strcpy(cp, "blksize"); 173 cp += sizeof("blksize"); 174 cp += snprintf(cp, 6, "%d", len) + 1; 175 want_option_ack = 1; 176 } 177 #endif 178 /* First packet is built, so skip packet generation */ 179 goto send_pkt; 180 181 /* Using mostly goto's - continue/break will be less clear 182 * in where we actually jump to */ 184 183 185 184 while (1) { 186 187 cp = buf; 188 189 /* first create the opcode part */ 190 *((unsigned short *) cp) = htons(opcode); 185 /* Build ACK or DATA */ 186 cp = xbuf + 2; 187 *((uint16_t*)cp) = htons(block_nr); 191 188 cp += 2; 192 193 /* add filename and mode */ 194 if (((cmd & tftp_cmd_get) && (opcode == TFTP_RRQ)) || 195 ((cmd & tftp_cmd_put) && (opcode == TFTP_WRQ))) 196 { 197 int too_long = 0; 198 199 /* see if the filename fits into buf 200 * and fill in packet. */ 201 len = strlen(remotefile) + 1; 202 203 if ((cp + len) >= &buf[tftp_bufsize - 1]) { 204 too_long = 1; 205 } else { 206 safe_strncpy(cp, remotefile, len); 207 cp += len; 208 } 209 210 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) { 211 bb_error_msg("remote filename too long"); 212 break; 213 } 214 215 /* add "mode" part of the package */ 216 memcpy(cp, MODE_OCTET, MODE_OCTET_LEN); 217 cp += MODE_OCTET_LEN; 218 219 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 220 221 len = tftp_bufsize - 4; /* data block size */ 222 223 if (len != TFTP_BLOCKSIZE_DEFAULT) { 224 225 if ((&buf[tftp_bufsize - 1] - cp) < 15) { 226 bb_error_msg("remote filename too long"); 227 break; 189 block_nr++; 190 opcode = TFTP_ACK; 191 if (CMD_PUT(cmd)) { 192 opcode = TFTP_DATA; 193 len = full_read(localfd, cp, tftp_bufsize - 4); 194 if (len < 0) { 195 bb_perror_msg(bb_msg_read_error); 196 goto ret; 197 } 198 if (len != (tftp_bufsize - 4)) { 199 finished = 1; 200 } 201 cp += len; 202 } 203 send_pkt: 204 /* Send packet */ 205 *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */ 206 send_len = cp - xbuf; 207 /* NB: send_len value is preserved in code below 208 * for potential resend */ 209 send_again: 210 #if ENABLE_DEBUG_TFTP 211 fprintf(stderr, "sending %u bytes\n", send_len); 212 for (cp = xbuf; cp < &xbuf[send_len]; cp++) 213 fprintf(stderr, "%02x ", (unsigned char) *cp); 214 fprintf(stderr, "\n"); 215 #endif 216 xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len); 217 /* Was it final ACK? then exit */ 218 if (finished && (opcode == TFTP_ACK)) 219 goto ret; 220 221 timeout = TFTP_NUM_RETRIES; /* re-initialize */ 222 recv_again: 223 /* Receive packet */ 224 tv.tv_sec = TFTP_TIMEOUT; 225 tv.tv_usec = 0; 226 FD_ZERO(&rfds); 227 FD_SET(socketfd, &rfds); 228 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 229 unsigned from_port; 230 case 1: 231 from->len = peer_lsa->len; 232 memset(&from->sa, 0, peer_lsa->len); 233 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, 234 &from->sa, &from->len); 235 if (len < 0) { 236 bb_perror_msg("recvfrom"); 237 goto ret; 238 } 239 from_port = get_nport(&from->sa); 240 if (port == org_port) { 241 /* Our first query went to port 69 242 * but reply will come from different one. 243 * Remember and use this new port */ 244 port = from_port; 245 set_nport(peer_lsa, from_port); 246 } 247 if (port != from_port) 248 goto recv_again; 249 goto process_pkt; 250 case 0: 251 timeout--; 252 if (timeout == 0) { 253 bb_error_msg("last timeout"); 254 goto ret; 255 } 256 bb_error_msg("last timeout" + 5); 257 goto send_again; /* resend last sent pkt */ 258 default: 259 bb_perror_msg("select"); 260 goto ret; 261 } 262 process_pkt: 263 /* Process recv'ed packet */ 264 opcode = ntohs( ((uint16_t*)rbuf)[0] ); 265 recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); 266 267 #if ENABLE_DEBUG_TFTP 268 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); 269 #endif 270 271 if (opcode == TFTP_ERROR) { 272 static const char *const errcode_str[] = { 273 "", 274 "file not found", 275 "access violation", 276 "disk full", 277 "illegal TFTP operation", 278 "unknown transfer id", 279 "file already exists", 280 "no such user", 281 "bad option" 282 }; 283 284 const char *msg = ""; 285 286 if (rbuf[4] != '\0') { 287 msg = &rbuf[4]; 288 rbuf[tftp_bufsize - 1] = '\0'; 289 } else if (recv_blk < ARRAY_SIZE(errcode_str)) { 290 msg = errcode_str[recv_blk]; 291 } 292 bb_error_msg("server error: (%u) %s", recv_blk, msg); 293 goto ret; 294 } 295 296 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 297 if (want_option_ack) { 298 want_option_ack = 0; 299 300 if (opcode == TFTP_OACK) { 301 /* server seems to support options */ 302 char *res; 303 304 res = tftp_option_get(&rbuf[2], len - 2, "blksize"); 305 if (res) { 306 int blksize = xatoi_u(res); 307 if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) { 308 /* send ERROR 8 to server... */ 309 /* htons can be impossible to use in const initializer: */ 310 /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/ 311 /* thus we open-code big-endian layout */ 312 static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 }; 313 xsendto(socketfd, error_8, 4, &peer_lsa->sa, peer_lsa->len); 314 bb_error_msg("server proposes bad blksize %d, exiting", blksize); 315 goto ret; 316 } 317 #if ENABLE_DEBUG_TFTP 318 fprintf(stderr, "using blksize %u\n", 319 blksize); 320 #endif 321 tftp_bufsize = blksize + 4; 322 /* Send ACK for OACK ("block" no: 0) */ 323 block_nr = 0; 324 continue; 228 325 } 229 230 /* add "blksize" + number of blocks */ 231 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN); 232 cp += OPTION_BLOCKSIZE_LEN; 233 cp += snprintf(cp, 6, "%d", len) + 1; 234 235 want_option_ack = 1; 236 } 237 #endif 238 } 239 240 /* add ack and data */ 241 242 if (((cmd & tftp_cmd_get) && (opcode == TFTP_ACK)) || 243 ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA))) { 244 245 *((unsigned short *) cp) = htons(block_nr); 246 247 cp += 2; 248 249 block_nr++; 250 251 if ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA)) { 252 len = bb_full_read(localfd, cp, tftp_bufsize - 4); 253 254 if (len < 0) { 255 bb_perror_msg(bb_msg_read_error); 256 break; 257 } 258 259 if (len != (tftp_bufsize - 4)) { 260 finished++; 261 } 262 263 cp += len; 264 } 265 } 266 267 268 /* send packet */ 269 270 271 timeout = TFTP_NUM_RETRIES; /* re-initialize */ 272 do { 273 274 len = cp - buf; 275 276 #ifdef CONFIG_DEBUG_TFTP 277 fprintf(stderr, "sending %u bytes\n", len); 278 for (cp = buf; cp < &buf[len]; cp++) 279 fprintf(stderr, "%02x ", (unsigned char) *cp); 280 fprintf(stderr, "\n"); 281 #endif 282 if (sendto(socketfd, buf, len, 0, 283 (struct sockaddr *) &sa, sizeof(sa)) < 0) { 284 bb_perror_msg("send"); 285 len = -1; 286 break; 287 } 288 289 290 if (finished && (opcode == TFTP_ACK)) { 291 break; 292 } 293 294 /* receive packet */ 295 296 memset(&from, 0, sizeof(from)); 297 fromlen = sizeof(from); 298 299 tv.tv_sec = TFTP_TIMEOUT; 300 tv.tv_usec = 0; 301 302 FD_ZERO(&rfds); 303 FD_SET(socketfd, &rfds); 304 305 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 306 case 1: 307 len = recvfrom(socketfd, buf, tftp_bufsize, 0, 308 (struct sockaddr *) &from, &fromlen); 309 310 if (len < 0) { 311 bb_perror_msg("recvfrom"); 312 break; 313 } 314 315 timeout = 0; 316 317 if (sa.sin_port == port) { 318 sa.sin_port = from.sin_port; 319 } 320 if (sa.sin_port == from.sin_port) { 321 break; 322 } 323 324 /* fall-through for bad packets! */ 325 /* discard the packet - treat as timeout */ 326 timeout = TFTP_NUM_RETRIES; 327 case 0: 328 bb_error_msg("timeout"); 329 330 timeout--; 331 if (timeout == 0) { 332 len = -1; 333 bb_error_msg("last timeout"); 334 } 335 break; 336 default: 337 bb_perror_msg("select"); 338 len = -1; 339 } 340 341 } while (timeout && (len >= 0)); 342 343 if ((finished) || (len < 0)) { 344 break; 345 } 346 347 /* process received packet */ 348 349 opcode = ntohs(*((unsigned short *) buf)); 350 tmp = ntohs(*((unsigned short *) &buf[2])); 351 352 #ifdef CONFIG_DEBUG_TFTP 353 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp); 354 #endif 355 356 if (opcode == TFTP_ERROR) { 357 const char *msg = NULL; 358 359 if (buf[4] != '\0') { 360 msg = &buf[4]; 361 buf[tftp_bufsize - 1] = '\0'; 362 } else if (tmp < (sizeof(tftp_bb_error_msg) 363 / sizeof(char *))) { 364 365 msg = tftp_bb_error_msg[tmp]; 366 } 367 368 if (msg) { 369 bb_error_msg("server says: %s", msg); 370 } 371 372 break; 373 } 374 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 375 if (want_option_ack) { 376 377 want_option_ack = 0; 378 379 if (opcode == TFTP_OACK) { 380 381 /* server seems to support options */ 382 383 char *res; 384 385 res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE); 386 387 if (res) { 388 int blksize = atoi(res); 389 390 if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { 391 392 if (cmd & tftp_cmd_put) { 393 opcode = TFTP_DATA; 394 } else { 395 opcode = TFTP_ACK; 396 } 397 #ifdef CONFIG_DEBUG_TFTP 398 fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE, 399 blksize); 400 #endif 401 tftp_bufsize = blksize + 4; 402 block_nr = 0; 403 continue; 404 } 405 } 406 /* FIXME: 407 * we should send ERROR 8 */ 408 bb_error_msg("bad server option"); 409 break; 410 } 411 412 bb_error_msg("warning: blksize not supported by server" 413 " - reverting to 512"); 414 326 /* rfc2347: 327 * "An option not acknowledged by the server 328 * must be ignored by the client and server 329 * as if it were never requested." */ 330 } 331 332 bb_error_msg("blksize is not supported by server" 333 " - reverting to 512"); 415 334 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; 416 335 } 417 336 #endif 418 419 if ((cmd & tftp_cmd_get) && (opcode == TFTP_DATA)) { 420 421 if (tmp == block_nr) { 422 423 len = bb_full_write(localfd, &buf[4], len - 4); 424 337 /* block_nr is already advanced to next block# we expect 338 * to get / block# we are about to send next time */ 339 340 if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { 341 if (recv_blk == block_nr) { 342 len = full_write(localfd, &rbuf[4], len - 4); 425 343 if (len < 0) { 426 344 bb_perror_msg(bb_msg_write_error); 427 break;345 goto ret; 428 346 } 429 430 347 if (len != (tftp_bufsize - 4)) { 431 finished ++;348 finished = 1; 432 349 } 433 434 opcode = TFTP_ACK; 350 continue; /* send ACK */ 351 } 352 if (recv_blk == (block_nr - 1)) { 353 /* Server lost our TFTP_ACK. Resend it */ 354 block_nr = recv_blk; 435 355 continue; 436 356 } 437 /* in case the last ack disappeared into the ether */ 438 if (tmp == (block_nr - 1)) { 439 --block_nr; 440 opcode = TFTP_ACK; 441 continue; 442 } else if (tmp + 1 == block_nr) { 443 /* Server lost our TFTP_ACK. Resend it */ 444 block_nr = tmp; 445 opcode = TFTP_ACK; 446 continue; 447 } 448 } 449 450 if ((cmd & tftp_cmd_put) && (opcode == TFTP_ACK)) { 451 452 if (tmp == (unsigned short) (block_nr - 1)) { 453 if (finished) { 454 break; 455 } 456 457 opcode = TFTP_DATA; 458 continue; 459 } 460 } 461 } 462 463 #ifdef CONFIG_FEATURE_CLEAN_UP 464 close(socketfd); 465 free(buf); 466 #endif 467 468 return finished ? EXIT_SUCCESS : EXIT_FAILURE; 357 } 358 359 if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { 360 /* did server ACK our last DATA pkt? */ 361 if (recv_blk == (uint16_t) (block_nr - 1)) { 362 if (finished) 363 goto ret; 364 continue; /* send next block */ 365 } 366 } 367 /* Awww... recv'd packet is not recognized! */ 368 goto recv_again; 369 /* why recv_again? - rfc1123 says: 370 * "The sender (i.e., the side originating the DATA packets) 371 * must never resend the current DATA packet on receipt 372 * of a duplicate ACK". 373 * DATA pkts are resent ONLY on timeout. 374 * Thus "goto send_again" will ba a bad mistake above. 375 * See: 376 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome 377 */ 378 } 379 ret: 380 if (ENABLE_FEATURE_CLEAN_UP) { 381 close(socketfd); 382 free(xbuf); 383 free(rbuf); 384 } 385 return finished == 0; /* returns 1 on failure */ 469 386 } 470 387 388 int tftp_main(int argc, char **argv); 471 389 int tftp_main(int argc, char **argv) 472 390 { 473 struct hostent *host = NULL;391 len_and_sockaddr *peer_lsa; 474 392 const char *localfile = NULL; 475 393 const char *remotefile = NULL; 394 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 395 const char *sblocksize = NULL; 396 #endif 476 397 int port; 477 int cmd = 0;398 USE_GETPUT(int cmd;) 478 399 int fd = -1; 479 400 int flags = 0; … … 481 402 int blocksize = TFTP_BLOCKSIZE_DEFAULT; 482 403 483 /* figure out what to pass to getopt */ 484 485 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 486 char *sblocksize = NULL; 487 488 #define BS "b:" 489 #define BS_ARG , &sblocksize 490 #else 491 #define BS 492 #define BS_ARG 493 #endif 494 495 #ifdef CONFIG_FEATURE_TFTP_GET 496 #define GET "g" 497 #define GET_COMPL ":g" 498 #else 499 #define GET 500 #define GET_COMPL 501 #endif 502 503 #ifdef CONFIG_FEATURE_TFTP_PUT 504 #define PUT "p" 505 #define PUT_COMPL ":p" 506 #else 507 #define PUT 508 #define PUT_COMPL 509 #endif 510 511 #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT) 512 bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g"; 513 #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) 514 bb_opt_complementally = GET_COMPL PUT_COMPL; 515 #endif 516 517 518 cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS, 519 &localfile, &remotefile BS_ARG); 520 521 cmd &= (tftp_cmd_get | tftp_cmd_put); 522 #ifdef CONFIG_FEATURE_TFTP_GET 523 if (cmd == tftp_cmd_get) 404 /* -p or -g is mandatory, and they are mutually exclusive */ 405 opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") 406 USE_GETPUT("?g--p:p--g"); 407 408 USE_GETPUT(cmd =) getopt32(argv, 409 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") 410 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), 411 &localfile, &remotefile 412 USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize)); 413 argv += optind; 414 415 flags = O_RDONLY; 416 if (CMD_GET(cmd)) 524 417 flags = O_WRONLY | O_CREAT | O_TRUNC; 525 #endif 526 #ifdef CONFIG_FEATURE_TFTP_PUT 527 if (cmd == tftp_cmd_put) 528 flags = O_RDONLY; 529 #endif 530 531 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 418 419 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 532 420 if (sblocksize) { 533 blocksize = atoi(sblocksize);421 blocksize = xatoi_u(sblocksize); 534 422 if (!tftp_blocksize_check(blocksize, 0)) { 535 423 return EXIT_FAILURE; … … 538 426 #endif 539 427 540 if ( localfile == NULL)428 if (!localfile) 541 429 localfile = remotefile; 542 if ( remotefile == NULL)430 if (!remotefile) 543 431 remotefile = localfile; 544 if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL)) 432 /* Error if filename or host is not known */ 433 if (!remotefile || !argv[0]) 545 434 bb_show_usage(); 546 435 547 if (localfile == NULL || strcmp(localfile, "-") == 0) { 548 fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO; 549 } else { 550 fd = open(localfile, flags, 0644); /* fail below */ 551 } 552 if (fd < 0) { 553 bb_perror_msg_and_die("local file"); 554 } 555 556 host = xgethostbyname(argv[optind]); 557 port = bb_lookup_port(argv[optind + 1], "udp", 69); 558 559 #ifdef CONFIG_DEBUG_TFTP 560 fprintf(stderr, "using server \"%s\", remotefile \"%s\", " 561 "localfile \"%s\".\n", 562 inet_ntoa(*((struct in_addr *) host->h_addr)), 436 fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; 437 if (!LONE_DASH(localfile)) { 438 fd = xopen(localfile, flags); 439 } 440 441 port = bb_lookup_port(argv[1], "udp", 69); 442 peer_lsa = xhost2sockaddr(argv[0], port); 443 444 #if ENABLE_DEBUG_TFTP 445 fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n", 446 xmalloc_sockaddr2dotted(&peer_lsa->sa), 563 447 remotefile, localfile); 564 448 #endif 565 449 566 result = tftp(cmd, host, remotefile, fd, port, blocksize); 567 568 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) { 569 if (ENABLE_FEATURE_CLEAN_UP) 570 close(fd); 571 if (cmd == tftp_cmd_get && result != EXIT_SUCCESS) 572 unlink(localfile); 573 } 574 return (result); 450 result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize); 451 452 if (ENABLE_FEATURE_CLEAN_UP) 453 close(fd); 454 if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) { 455 unlink(localfile); 456 } 457 return result; 575 458 } 459 460 #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */
Note:
See TracChangeset
for help on using the changeset viewer.