00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "vfer_rcp.h"
00022
00023
00024
00025
00026 typedef struct rcp_info {
00027 char local_path [MAX_PATH];
00028 char remote_path[MAX_PATH];
00029 char user [MAX_USER];
00030 char host [MAX_HOST];
00031 uint32_t frame_size;
00032 int port;
00033 char from_remote;
00034 } rcp_info;
00035
00036 extern char *optarg;
00037 extern int optind;
00038 extern int optopt;
00039 extern int opterr;
00040
00041 void print_help (char* prog, int verbose);
00042 int parse_opts (int argc, char** argv, FILE** testing_out);
00043 int rcp_connect ();
00044
00045
00046 vfer_fd connect_skt;
00047 rcp_info info;
00048 int fd;
00049 int sig_mark = 0;
00050
00051
00052
00053
00054
00055
00056
00057 void print_help(char* prog, int verbose) {
00058 printf("usage: %s [-h] [-v[v]] [-P port] [[user1@]host1:]file1 [[user2@]host2:]file2\n", prog);
00059 if (verbose == 0) return;
00060 printf("\t-h brings up this help page [optional]\n");
00061 printf("\t-v verbose message printing [optional]\n");
00062 printf("\t-vv more verbose message printing [optional]\n");
00063 printf("\t-P specifies port to connect to [optional]\n");
00064 printf("\tuser[1,2] username to use when connecting to host [optional]\n");
00065 printf("\thost[1,2] hostname of remote system\n");
00066 printf("\tfile[1,2] local, remote file path\n");
00067 printf("notes:\n");
00068 printf("\t- to do a remote->local copy specify the remote host and path first\n");
00069 printf("\t- to do a local->remote copy specify the local host and path first\n");
00070 printf("\t- one remote host is required (signaled with ':')\n");
00071 printf("\t- port is defaulted to 2046\n");
00072 printf("\t- username is defauled to user invoking the program but may be specified with '@'\n");
00073 printf("\t- username must match the user who started the remote host daemon\n");
00074 printf("\t- there is no other authentication with the remote daemon\n");
00075 printf("\t- remote->remote copying is not implemented\n");
00076 printf("\t- encryption is not implemented\n");
00077 printf("examples:\n");
00078 printf("\t%s /tmp/file.txt fred@work-computer.univ.edu:\n", prog);
00079 printf("\t\tcopy local file [/tmp/file.txt] to remote computer [work-computer.univ.edu] at remote path [~/] \n\n");
00080 printf("\t%s fred@work-computer.univ.edu:/tmp/file.txt ./\n", prog);
00081 printf("\t\tcopy remote file [/tmp/file.txt] at remote computer [work-computer.univ.edu] to local path [./] \n");
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 int parse_opts(int argc, char** argv, FILE** testing_out) {
00099 int c;
00100 char* r;
00101 char* l;
00102 char *cp, *cp2;
00103 struct passwd *pwentry;
00104 int uid;
00105
00106 opterr=0;
00107 bzero(info.local_path,MAX_PATH);
00108 bzero(info.remote_path,MAX_PATH);
00109 bzero(info.user,MAX_USER);
00110 bzero(info.host,MAX_HOST);
00111 info.frame_size = (uint32_t)(MAX_FRAME_SIZE);
00112 info.port = DEFAULT_PORT;
00113 *testing_out = NULL;
00114 while (1) {
00115 c = getopt (argc, argv, ":hvP:");
00116 if (c == -1) break;
00117 switch (c) {
00118 case 'h':
00119 return -2;
00120 break;
00121 case 'P':
00122 info.port = atoi(optarg);
00123 break;
00124 case 'v':
00125 if (*testing_out == NULL) {
00126
00127 *testing_out = stdout;
00128 vfer_debug(stdout, stdout, "a");
00129 } else {
00130 vfer_debug(stdout, stdout, "aCcP");
00131 }
00132 break;
00133 case ':':
00134 T_ERR("parse_opts", "option %c missing value", optopt);
00135 return -1;
00136 case '?':
00137 T_ERR("parse_opts", "unknown option: %c", optopt);
00138 return -1;
00139 default:
00140 T_ERR("parse_opts", "getopt returned character code 0%o", c);
00141 return -1;
00142 }
00143 }
00144 if (argc - optind != 2) {
00145 T_ERR("parse_opts", "exactly two non-option args required");
00146 return -1;
00147 }
00148
00149
00150 cp = index(argv[optind], ':');
00151 cp2 = index(argv[optind+1], ':');
00152 if (cp != NULL && cp2 != NULL) {
00153 T_ERR("parse_opts", "one of file paths must be local");
00154 return -1;
00155 } else if (cp == NULL && cp2 == NULL) {
00156 T_ERR("parse_opts", "one of file paths must be remote");
00157 return -1;
00158 }
00159
00160
00161 if (cp != NULL) {
00162 if (cp == argv[optind]) {
00163 T_ERR("parse_opts", "no hostname specified for remote path");
00164 return -1;
00165 }
00166 info.from_remote = 0;
00167 r=argv[optind];
00168 l=argv[optind+1];
00169 } else {
00170 if (cp2 == argv[optind+1]) {
00171 T_ERR("parse_opts", "no hostname specified for remote path");
00172 return -1;
00173 }
00174 info.from_remote = 1;
00175 l=argv[optind];
00176 r=argv[optind+1];
00177 }
00178
00179
00180
00181
00182 strncpy(info.local_path, l, MAX_PATH);
00183
00184
00185
00186 cp = index(r, ':');
00187 if (strlen(r) - 1 + r == cp) {
00188
00189 strcpy(info.remote_path, "~/");
00190 } else {
00191 strncpy(info.remote_path, cp+1, MAX_PATH);
00192 }
00193
00194
00195 cp2 = index(r, '@');
00196 if (cp2 == NULL) {
00197
00198
00199
00200 uid=getuid();
00201 if ((pwentry = getpwuid(uid)) == NULL) {
00202 T_ERR("parse_opts", "failed getting password entry for uid(%d)", uid);
00203 return -1;
00204 }
00205 if (strlen(pwentry->pw_name) > MAX_USER) {
00206 T_ERR("parse_opts", "length of username must be less than %d", MAX_USER);
00207 return -1;
00208 }
00209 strncpy(info.user, pwentry->pw_name, MAX_USER);
00210
00211 if (cp - r > MAX_HOST) {
00212 T_ERR("parse_opts", "length of hostname must be less than %d", MAX_HOST);
00213 return -1;
00214 }
00215 strncpy(info.host, r, cp - r);
00216 } else {
00217 if (cp2 > cp) {
00218 T_ERR("parse_opts", "'@' must come before ':'");
00219 return -1;
00220 } else if (cp2 + 1 == cp) {
00221 T_ERR("parse_opts", "no hostname specified for remote path");
00222 return -1;
00223 } else if (cp2 == r) {
00224 T_ERR("parse_opts", "missing username for remote path");
00225 return -1;
00226 }
00227
00228 if (cp - cp2 > MAX_HOST) {
00229 T_ERR("parse_opts", "length of hostname must be less than %d", MAX_HOST);
00230 return -1;
00231 }
00232 strncpy(info.host, cp2+1, cp - cp2 - 1);
00233
00234 if (cp2 - r > MAX_USER) {
00235 T_ERR("parse_opts", "length of username must be less than %d", MAX_USER);
00236 return -1;
00237 }
00238 strncpy(info.user, r, cp2 - r);
00239 }
00240
00241
00242 if (info.local_path[strlen(info.local_path) - 1] == '/') {
00243 cp = rindex(info.remote_path, '/');
00244 strncpy(info.local_path + strlen(info.local_path), cp+1, MAX_PATH - strlen(info.local_path));
00245 }
00246
00247 return 0;
00248 }
00249
00250
00251
00252
00253
00254 int rcp_connect() {
00255
00256 struct sockaddr_in client_sa;
00257 struct sockaddr_in server_sa;
00258 char hostname_buf[256];
00259 char local_ip[INET_ADDRSTRLEN];
00260 char remote_ip[INET_ADDRSTRLEN];
00261 struct hostent* h;
00262 int ret;
00263
00264
00265 if (gethostname(hostname_buf, 256) == -1) {
00266 perror("gethostname");
00267 close(fd);
00268 return -1;
00269 }
00270
00271 if ((h = gethostbyname((const char*)(info.host))) == NULL) {
00272 perror("gethostbyname");
00273 close(fd);
00274 return -1;
00275 }
00276 if (h->h_addr_list != 0) {
00277 inet_ntop(h->h_addrtype, (h->h_addr_list)[0], remote_ip, sizeof(remote_ip));
00278 }
00279
00280 if ((h = gethostbyname((const char*)(hostname_buf))) == NULL) {
00281 perror("gethostbyname");
00282 close(fd);
00283 return -1;
00284 }
00285 if (h->h_addr_list != 0) {
00286 inet_ntop(h->h_addrtype, (h->h_addr_list)[0], local_ip, sizeof(local_ip));
00287 }
00288
00289 TEST_PRINT("rcp_connect","remote (%s : %s)", info.host, remote_ip);
00290 TEST_PRINT("rcp_connect","local (%s : %s)", hostname_buf, local_ip);
00291
00292
00293 bzero((char*)(&client_sa), sizeof(client_sa));
00294 client_sa.sin_port = htons(0);
00295 client_sa.sin_family = AF_INET;
00296 if (inet_pton(AF_INET, local_ip, &client_sa.sin_addr) != 1) {
00297 TEST_PRINT("rcp_connect","inet_pton failed");
00298 close(fd);
00299 return -1;
00300 }
00301
00302 bzero((char*)(&server_sa), sizeof(server_sa));
00303 server_sa.sin_family = AF_INET;
00304 server_sa.sin_port = htons(info.port);
00305 if (inet_pton(AF_INET, remote_ip, &server_sa.sin_addr) != 1) {
00306 TEST_PRINT("rcp_connect","inet_pton failed");
00307 close(fd);
00308 return -1;
00309 }
00310
00311 if ((connect_skt = vfer_socket (SOCK_DGRAM)) < 0) {
00312 TEST_PRINT("rcp_connect","vfer_socket failed [%s]", vfer_errortext(connect_skt));
00313 close(fd);
00314 return -1;
00315 }
00316
00317 if (vfer_bind (connect_skt, (struct sockaddr*) &client_sa, sizeof(client_sa)) < 0) {
00318 TEST_PRINT("rcp_connect","vfer_bind failed [%s]", vfer_errortext(connect_skt));
00319 close(fd);
00320 return -1;
00321 }
00322
00323
00324 if ((ret = vfer_connect (connect_skt, (SA*) (&server_sa), sizeof(server_sa))) < 0) {
00325 TEST_PRINT("rcp_connect","vfer_connect failed [%s]", vfer_errortext(ret));
00326 close(fd);
00327 return -1;
00328 }
00329 return 0;
00330 }
00331
00332
00333
00334
00335 void sig_handler(int sig) {
00336 exit(1);
00337 }
00338
00339
00340
00341
00342 int main (int argc, char **argv) {
00343 int ret;
00344 char* c;
00345 client_msg_t client_msg;
00346 server_msg_t server_msg;
00347 vfer_stats stats;
00348 FILE* testing_out;
00349 struct sigaction sa;
00350 connect_skt = -1;
00351
00352 if (argc == 1) {
00353 print_help(argv[0], 0);
00354 return 0;
00355 }
00356
00357 ret = parse_opts(argc, argv, &testing_out);
00358 TEST_INIT("VFER_RCP", "vfer_rcp.c", testing_out, stdout);
00359
00360 if (ret == -2) {
00361 print_help(argv[0], 1);
00362 return 0;
00363 } else if (ret == -1) {
00364 print_help(argv[0], 0);
00365 return -1;
00366 }
00367
00368 TEST_PRINT("main", "parsed: from_remote[%d] lpath[%s] uname[%s] host[%s] port[%d] rpath[%s]",
00369 info.from_remote, info.local_path, info.user, info.host, info.port, info.remote_path);
00370
00371
00372 strncpy(client_msg.remote_path, info.remote_path, MAX_PATH);
00373 strncpy(client_msg.user, info.user, MAX_USER);
00374 strncpy(client_msg.user, info.user, MAX_USER);
00375 client_msg.from_remote = info.from_remote;
00376
00377 if ((c = rindex(info.local_path, '/')) == NULL) {
00378 strncpy(client_msg.local_name, info.local_path, MAX_PATH);
00379 } else {
00380 strncpy(client_msg.local_name, c+1, MAX_PATH);
00381 }
00382
00383
00384 if (info.from_remote == 1) {
00385 if ((fd = open(info.local_path, O_RDONLY)) == -1) {
00386 TEST_PRINT("main", "couldn't open local file [%s] for reading", info.local_path);
00387 return -1;
00388 }
00389 client_msg.file_size = lseek(fd, 0, SEEK_END);
00390 close(fd);
00391 } else {
00392 client_msg.file_size = 0;
00393 }
00394
00395
00396 if (rcp_connect() == -1) {
00397 return -1;
00398 }
00399 TEST_PRINT("main","connected!");
00400
00401
00402 sa.sa_handler = &(sig_handler);
00403 if (sigaction(SIGINT, &sa, NULL) == -1) {
00404 TEST_PRINT("main", "couldn't install a signal handler for SIGINT");
00405 }
00406
00407
00408 client_msg.file_size = htonl(client_msg.file_size);
00409 if ((ret = vfer_send(connect_skt, &client_msg, sizeof(client_msg_t))) < 0) {
00410 TEST_PRINT("main", "send client msg failed [%s]", vfer_errortext(ret));
00411 goto CLEAN_UP_NO_STAT;
00412 }
00413 client_msg.file_size = ntohl(client_msg.file_size);
00414
00415
00416 if ((ret = vfer_recv(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00417 TEST_PRINT("main", "receive server msg failed [%s]", vfer_errortext(ret));
00418 goto CLEAN_UP_NO_STAT;
00419 }
00420 server_msg.file_size = ntohl(server_msg.file_size);
00421 server_msg.status = ntohl(server_msg.status);
00422
00423 TEST_PRINT("main", "received server msg with status[%u] file_size[%u]", server_msg.status, server_msg.file_size);
00424
00425 switch (server_msg.status) {
00426 case RCP_READY:
00427 if (info.from_remote == 0) {
00428
00429 if ((fd = open(info.local_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
00430 perror("open for writing failed");
00431 goto CLEAN_UP_NO_STAT;
00432 }
00433 if ((ret = vfer_recvfile(connect_skt, fd, 0, server_msg.file_size)) < 0){
00434 TEST_PRINT("main","vfer_recvfile failed [%s]", vfer_errortext(ret));
00435 goto CLEAN_UP_STAT;
00436 }
00437
00438 } else {
00439
00440 if ((fd = open(info.local_path, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
00441 perror("open for reading failed");
00442 goto CLEAN_UP_NO_STAT;
00443 }
00444
00445 if ((ret = vfer_sendfile(connect_skt, fd, 0, client_msg.file_size)) < 0) {
00446 TEST_PRINT("main","vfer_sendfile failed [%s]", vfer_errortext(ret));
00447 goto CLEAN_UP_STAT;
00448 }
00449 }
00450 goto CLEAN_UP_STAT;
00451 case RCP_ENOENT:
00452 T_ERR("main", "component of the path does not exist on remote file system");
00453 break;
00454 case RCP_EOPEN:
00455 if (info.from_remote == 0) {
00456 T_ERR("main", "can't open remote file for reading");
00457 } else {
00458 T_ERR("main", "can't open remote file for writing");
00459 }
00460 break;
00461 case RCP_ENOFILE:
00462 T_ERR("main", "file doesn't exist on remote host");
00463 break;
00464 case RCP_EUSER:
00465 T_ERR("main", "wrong username specified for remote host");
00466 break;
00467 case RCP_EOTHER:
00468 T_ERR("main", "unspecified remote error");
00469 break;
00470 default:
00471 T_ERR("main", "could not interpret server msg code");
00472 break;
00473 }
00474 CLEAN_UP_NO_STAT:
00475 vfer_close(connect_skt);
00476 close(fd);
00477 return 0;
00478 CLEAN_UP_STAT:
00479 vfer_close(connect_skt);
00480 stats = vfer_sockstats(connect_skt);
00481 connect_skt = -1;
00482 if (test_out != NULL)
00483 vfer_rcp_print_stats(&stats);
00484 close(fd);
00485 return 0;
00486 }