afscp: Add -l option
[openafs.git] / src / tests / afscp.c
1 #include <afsconfig.h>
2 #include <afs/param.h>
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/select.h>
14 #include <sys/stat.h>
15 #include <netdb.h>
16
17 #include <afs/afsint.h>
18 #define FSINT_COMMON_XG 1
19 #include <afs/afscbint.h>
20 #include <sys/ioctl.h>
21 #include <afs/venus.h>
22 #include <afs/cellconfig.h>
23 #include <afs/sys_prototypes.h>
24
25 #include <afs/afs_consts.h>
26
27 /*#include <rx/rxkad.h>*/
28 #include <rx/rx_null.h>
29 #include <rx/rx_prototypes.h>
30
31 /*#include <krb.h>*/
32 #include <afs/com_err.h>
33
34 struct VenusFid {
35     afs_int32 Cell;
36     struct AFSFid Fid;
37 };
38
39 int
40 statfile(char *path, char *cellname, afs_uint32 * server, struct AFSFid *f)
41 {
42
43     struct ViceIoctl v;
44     struct VenusFid vf;
45     afs_int32 srvbuf[AFS_MAXHOSTS];
46     int code;
47
48     if (!strncmp(path, "@afs:", 5)) {
49         char *pdup, *p;
50         struct hostent *he;
51
52         pdup = strdup(path);
53         strtok(pdup, ":");
54
55         if (!(p = strtok(NULL, ":"))) {
56             free(pdup);
57             return -1;
58         }
59         strncpy(cellname, p, MAXCELLCHARS);
60
61         if (!(p = strtok(NULL, ":"))) {
62             free(pdup);
63             return -1;
64         }
65         he = gethostbyname(p);
66         if (!he) {
67             printf("Unknown host %s\n", p);
68             free(pdup);
69             return -1;
70         }
71         memcpy(server, he->h_addr, he->h_length);
72
73         if (!(p = strtok(NULL, ":"))) {
74             free(pdup);
75             return -1;
76         }
77         f->Volume = atoi(p);
78
79         if (!(p = strtok(NULL, ":"))) {
80             free(pdup);
81             return -1;
82         }
83         f->Vnode = atoi(p);
84
85         if (!(p = strtok(NULL, ":"))) {
86             free(pdup);
87             return -1;
88         }
89         f->Unique = atoi(p);
90
91         if (strtok(NULL, ":")) {
92             printf("Too much extra stuff after @afs:...\n");
93             free(pdup);
94             return -1;
95         }
96
97         return 0;
98     }
99
100     v.in = 0;
101     v.in_size = 0;
102     v.out = cellname;
103     v.out_size = MAXCELLCHARS;
104     if ((code = pioctl(path, VIOC_FILE_CELL_NAME, &v, 1)))
105         return code;
106
107     v.out = (char *)&vf;
108     v.out_size = sizeof(struct VenusFid);
109     if ((code = pioctl(path, VIOCGETFID, &v, 1)))
110         return code;
111     memcpy(f, &vf.Fid, sizeof(struct AFSFid));
112
113     v.out = (char *)srvbuf;
114     v.out_size = sizeof(srvbuf);
115     if ((code = pioctl(path, VIOCWHEREIS, &v, 1)))
116         return code;
117     if (v.out_size <= sizeof(afs_int32))
118         return EINVAL;
119
120     memcpy(server, srvbuf, sizeof(afs_int32));
121     return 0;
122 }
123
124
125 struct rx_securityClass *sc;
126
127 extern int
128 start_cb_server(void)
129 {
130     struct rx_service *s;
131
132     sc = rxnull_NewServerSecurityObject();
133     s = rx_NewService(0, 1, "afs", &sc, 1, RXAFSCB_ExecuteRequest);
134     if (!s)
135         return 1;
136     rx_StartServer(0);
137     return 0;
138 }
139
140
141 /*extern int rx_socket;*/
142 extern unsigned short rx_port;
143 int
144 do_rx_Init(void)
145 {
146     struct sockaddr_in s;
147     int len;
148
149     if (rx_Init(0)) {
150         fprintf(stderr, "Cannot initialize rx\n");
151         return 1;
152     }
153
154     len = sizeof(struct sockaddr_in);
155     if (getsockname(rx_socket, (struct sockaddr *)&s, (socklen_t *)&len)) {
156         perror("getsockname");
157         return 1;
158     }
159     rx_port = ntohs(s.sin_port);
160
161     return 0;
162 }
163
164 struct rx_securityClass *
165 get_sc(char *cellname)
166 {
167 #if 0
168     char realm[REALM_SZ];
169     CREDENTIALS c;
170 #endif
171
172     return rxnull_NewClientSecurityObject();
173 #if 0
174
175     ucstring(realm, cellname, REALM_SZ);
176
177     if (krb_get_cred("afs", "", realm, &c)) {
178         if (get_ad_tkt("afs", "", realm, DEFAULT_TKT_LIFE)) {
179             return NULL;
180         } else {
181             if (krb_get_cred("afs", "", realm, &c)) {
182                 return NULL;
183             }
184         }
185     }
186
187     return rxkad_NewClientSecurityObject(rxkad_clear, c.session, c.kvno,
188                                          c.ticket_st.length, c.ticket_st.dat);
189 #endif
190 }
191
192 static volatile int loop_stop = 1;
193 static void
194 int_handler(int sig)
195 {
196     loop_stop = 1;
197 }
198
199 #define scindex_NULL 0
200 #define scindex_RXKAD 2
201
202 #define scindex scindex_RXKAD
203 int
204 main(int argc, char **argv)
205 {
206     char scell[MAXCELLCHARS], dcell[MAXCELLCHARS];
207     afs_uint32 ssrv, dsrv;
208     char *databuffer, *srcf = NULL, *destd = NULL, *destf = NULL, *destpath = NULL;
209     struct stat statbuf;
210
211     struct AFSStoreStatus sst;
212     struct AFSFetchStatus fst, dfst;
213     struct AFSVolSync vs;
214     struct AFSCallBack scb, dcb;
215     struct AFSFid sf, dd, df;
216
217     int filesz = 0;
218     unsigned long total_xfer = 0;
219     int ch, blksize, bytesremaining, bytes;
220     struct timeval start, finish;
221     struct rx_securityClass *ssc = 0, *dsc = 0;
222     int sscindex, dscindex;
223     struct rx_connection *sconn = NULL, *dconn = NULL;
224     struct rx_call *scall = NULL, *dcall = NULL;
225     struct rx_call *scall_2 = NULL, *dcall_2 = NULL;
226     int code = 0, fetchcode, storecode, printcallerrs = 0;
227     int slcl = 0, dlcl = 0, unlock = 0;
228     int sfd = 0, dfd = 0, unauth = 0;
229     int sleeptime = 0;
230     int did_start = 0;
231     int loop_seconds = 0;
232     int first;
233
234     struct AFSCBFids theFids;
235     struct AFSCBs theCBs;
236
237
238     blksize = 8 * 1024;
239
240     while ((ch = getopt(argc, argv, "iouUb:s:l:")) != -1) {
241         switch (ch) {
242         case 'b':
243             blksize = atoi(optarg);
244             break;
245         case 'i':
246             slcl = 1;
247             break;
248         case 'o':
249             dlcl = 1;
250             break;
251         case 's':
252             sleeptime = atoi(optarg);
253             break;
254         case 'u':
255             unauth = 1;
256             break;
257         case 'U':
258             unlock = 1;
259             break;
260         case 'l': {
261             struct sigaction sa;
262             loop_stop = 0;
263             loop_seconds = atoi(optarg);
264             memset(&sa, 0, sizeof(sa));
265             sa.sa_handler = int_handler;
266             sigaction(SIGINT, &sa, NULL);
267             break;
268         }
269         default:
270             printf("Unknown option '%c'\n", ch);
271             exit(1);
272         }
273     }
274
275
276     if (argc - optind + unlock < 2) {
277         fprintf(stderr,
278                 "Usage: afscp [-i|-o]] [-b xfersz] [-s time] [-l n] [-u] [-U] source [dest]\n");
279         fprintf(stderr, "  -b   Set block size\n");
280         fprintf(stderr, "  -i   Source is local (copy into AFS)\n");
281         fprintf(stderr, "  -o   Dest is local (copy out of AFS)\n");
282         fprintf(stderr, "  -s   Set the seconds to sleep before reading/writing data\n");
283         fprintf(stderr, "  -u   Run unauthenticated\n");
284         fprintf(stderr, "  -U   Send an unlock request for source. (dest path not required)\n");
285         fprintf(stderr, "  -l   repeat request for N seconds (0 for forever)\n");
286         fprintf(stderr, "source and dest can be paths or specified as:\n");
287         fprintf(stderr, "     @afs:cellname:servername:volume:vnode:uniq\n");
288         exit(1);
289     }
290     srcf = argv[optind++];
291     if (!unlock) {
292         destpath = argv[optind++];
293         destd = strdup(destpath);
294         if (!destd) {
295             perror("strdup");
296             exit(1);
297         }
298         if ((destf = strrchr(destd, '/'))) {
299             *destf++ = 0;
300         } else {
301             destf = destd;
302             destd = ".";
303         }
304     } else if (slcl) {
305         fprintf(stderr, "-i and -U cannot be used together\n");
306     }
307
308     if (!slcl && statfile(srcf, scell, &ssrv, &sf)) {
309         fprintf(stderr, "Cannot get attributes of %s\n", srcf);
310         exit(1);
311     }
312     if (!unlock && !dlcl && statfile(destd, dcell, &dsrv, &dd)) {
313         fprintf(stderr, "Cannot get attributes of %s\n", destd);
314         exit(1);
315     }
316
317     if ((databuffer = malloc(blksize)) == NULL) {
318         perror("malloc");
319         exit(1);
320     }
321
322     if (do_rx_Init())
323         exit(1);
324
325     if (start_cb_server()) {
326         printf("Cannot start callback service\n");
327         goto Fail_rx;
328     }
329
330     if (!slcl) {
331         sscindex = scindex_RXKAD;
332         if (unauth || (ssc = get_sc(scell)) == NULL) {
333             ssc = rxnull_NewClientSecurityObject();
334             sscindex = scindex_NULL;
335             /*printf("Cannot get authentication for cell %s; running unauthenticated\n", scell); */
336         }
337         sscindex = scindex_NULL;
338
339         if ((sconn =
340              rx_NewConnection(ssrv, htons(AFSCONF_FILEPORT), 1, ssc,
341                               sscindex))
342             == NULL) {
343             struct in_addr s;
344             s.s_addr = ssrv;
345             printf("Cannot initialize rx connection to source server (%s)\n",
346                    inet_ntoa(s));
347             goto Fail_sc;
348         }
349     }
350
351     if (!dlcl && !unlock) {
352         if (!slcl && ssrv == dsrv) {
353             dconn = sconn;
354             dsc = NULL;
355         } else {
356             if (slcl || strcmp(scell, dcell)) {
357                 dscindex = scindex_RXKAD;
358                 if (unauth || (dsc = get_sc(dcell)) == NULL) {
359                     dsc = rxnull_NewClientSecurityObject();
360                     dscindex = scindex_NULL;
361                     /*printf("Cannot get authentication for cell %s; running unauthenticated\n", dcell); */
362                 }
363                 dscindex = scindex_NULL;
364             } else {
365                 dsc = ssc;
366                 dscindex = sscindex;
367             }
368
369             if ((dconn =
370                  rx_NewConnection(dsrv, htons(AFSCONF_FILEPORT), 1, dsc,
371                                   dscindex))
372                 == NULL) {
373                 struct in_addr s;
374                 s.s_addr = dsrv;
375                 printf
376                     ("Cannot initialize rx connection to dest server (%s)\n",
377                      inet_ntoa(s));
378                 goto Fail_sconn;
379             }
380         }
381     }
382
383     first = 2;
384  repeat:
385     if (first == 2) {
386         first = 1;
387     } else if (first == 1) {
388         first = 0;
389     }
390
391     memset(&sst, 0, sizeof(struct AFSStoreStatus));
392
393     if (dlcl && !unlock) {
394         dfd = open(destpath, O_RDWR | O_CREAT | O_EXCL, 0666);
395         if (dfd < 0 && errno == EEXIST) {
396             if (first) {
397                 printf("%s already exists, overwriting\n", destpath);
398             }
399             dfd = open(destpath, O_RDWR | O_TRUNC, 0666);
400             if (dfd < 0) {
401                 fprintf(stderr, "Cannot open %s (%s)\n", destpath,
402                         afs_error_message(errno));
403                 goto Fail_dconn;
404             }
405         } else if (dfd < 0) {
406             fprintf(stderr, "Cannot open %s (%s)\n", destpath,
407                     afs_error_message(errno));
408             goto Fail_dconn;
409         }
410     } else if (!unlock) {
411         if ((code =
412              RXAFS_CreateFile(dconn, &dd, destf, &sst, &df, &fst, &dfst, &dcb,
413                               &vs))) {
414             if (code == EEXIST) {
415                 if (first) {
416                     printf("%s already exits, overwriting\n", destpath);
417                 }
418                 if (statfile(destpath, dcell, &dsrv, &df))
419                     fprintf(stderr, "Cannot get attributes of %s\n",
420                             destpath);
421                 else
422                     code = 0;
423             } else {
424                 printf("Cannot create %s (%s)\n", destpath,
425                        afs_error_message(code));
426                 if (code)
427                     goto Fail_dconn;
428             }
429         }
430     }
431
432     if (slcl) {
433         sfd = open(srcf, O_RDONLY, 0);
434         if (sfd < 0) {
435             fprintf(stderr, "Cannot open %s (%s)\n", srcf,
436                     afs_error_message(errno));
437             goto Fail_dconn;
438         }
439         if (fstat(sfd, &statbuf) < 0) {
440             fprintf(stderr, "Cannot stat %s (%s)\n", srcf,
441                     afs_error_message(errno));
442             close(sfd);
443             goto Fail_dconn;
444         }
445     } else {
446         if ((code = RXAFS_FetchStatus(sconn, &sf, &fst, &scb, &vs))) {
447             printf("Cannot fetchstatus of %d.%d (%s)\n", sf.Volume, sf.Vnode,
448                    afs_error_message(code));
449             goto Fail_dconn;
450         }
451     }
452
453
454
455     if (slcl) {
456         filesz = statbuf.st_size;
457     } else {
458         filesz = fst.Length;
459     }
460     total_xfer += filesz;
461
462     printcallerrs = 0;
463     fetchcode = 0;
464     storecode = 0;
465     if (!slcl && !unlock) {
466         if (first) {
467             scall = rx_NewCall(sconn);
468         } else {
469             scall = scall_2;
470         }
471         scall_2 = rx_NewCall(sconn);
472     }
473     if (!dlcl && !unlock) {
474         if (first) {
475             dcall = rx_NewCall(dconn);
476         } else {
477             dcall = dcall_2;
478         }
479         dcall_2 = rx_NewCall(dconn);
480     }
481     if (!did_start) {
482         gettimeofday(&start, NULL);
483         did_start = 1;
484     }
485     if (unlock) {
486         if (fst.lockCount) {
487             printf("Sending 1 unlock for %s (%d locks)\n", srcf, fst.lockCount);
488             if ((code = RXAFS_ReleaseLock(sconn, &sf, &vs))) {
489                 printf("Unable to unlock %s (%s)\n", srcf,
490                        afs_error_message(code));
491             }
492         } else {
493             printf("No locks for %s\n", srcf);
494         }
495         fetchcode = code;
496         goto Finish;
497     }
498
499     if (!slcl) {
500         if ((code = StartRXAFS_FetchData(scall, &sf, 0, filesz))) {
501             printf("Unable to fetch data from %s (%s)\n", srcf,
502                    afs_error_message(code));
503             goto Fail_call;
504         }
505     }
506
507     if (!dlcl) {
508         if (slcl) {
509             sst.Mask = AFS_SETMODTIME | AFS_SETMODE;
510             sst.ClientModTime = statbuf.st_mtime;
511             sst.UnixModeBits =
512                 statbuf.st_mode & ~(S_IFMT | S_ISUID | S_ISGID);
513         } else {
514             sst.Mask = AFS_SETMODTIME | AFS_SETMODE;
515             sst.ClientModTime = fst.ClientModTime;
516             sst.UnixModeBits =
517                 fst.UnixModeBits & ~(S_IFMT | S_ISUID | S_ISGID);
518         }
519
520         if ((code =
521              StartRXAFS_StoreData(dcall, &df, &sst, 0, filesz, filesz))) {
522             printf("Unable to store data to %s (%s)\n", destpath,
523                    afs_error_message(code));
524             goto Fail_call;
525         }
526     }
527
528     if (slcl) {
529         bytesremaining = statbuf.st_size;
530     } else {
531         rx_Read(scall, (char *)&bytesremaining, sizeof(afs_int32));
532         bytesremaining = ntohl(bytesremaining);
533     }
534
535     while (bytesremaining > 0) {
536         /*printf("%d bytes remaining\n",bytesremaining); */
537         if (slcl) {
538             if ((bytes =
539                  read(sfd, databuffer, min(blksize, bytesremaining))) <= 0) {
540                 fetchcode = errno;
541                 break;
542             }
543         } else {
544             if ((bytes =
545                  rx_Read(scall, databuffer,
546                          min(blksize, bytesremaining))) <= 0)
547                 break;
548         }
549         if (dlcl) {
550             if (write(dfd, databuffer, bytes) != bytes) {
551                 storecode = errno;
552                 break;
553             }
554         } else {
555             if (rx_Write(dcall, databuffer, bytes) != bytes)
556                 break;
557         }
558
559         if (sleeptime > 0) {
560 #ifdef AFS_PTHREAD_ENV
561             sleep(sleeptime);
562 #else
563             IOMGR_Sleep(sleeptime);
564 #endif
565             /* only sleep once */
566             sleeptime = 0;
567         }
568
569         bytesremaining -= bytes;
570         /*printf("%d bytes copied\n",bytes); */
571     }
572
573
574     if (bytesremaining > 0) {
575         printf("Some network error occured while copying data\n");
576         goto Fail_call;
577     }
578
579     if (!slcl)
580         fetchcode = EndRXAFS_FetchData(scall, &fst, &scb, &vs);
581     if (!dlcl)
582         storecode = EndRXAFS_StoreData(dcall, &fst, &vs);
583     printcallerrs = 1;
584   Fail_call:
585
586     if (slcl) {
587         if (close(sfd) && !fetchcode)
588             fetchcode = errno;
589     } else {
590         fetchcode = rx_EndCall(scall, fetchcode);
591     }
592     if (fetchcode)
593         printf("Error returned from fetch: %s\n", afs_error_message(fetchcode));
594
595     if (dlcl) {
596         if (close(dfd) && !storecode)
597             storecode = errno;
598     } else if (!unlock) {
599         storecode = rx_EndCall(dcall, storecode);
600     }
601     if (storecode)
602         printf("Error returned from store: %s\n", afs_error_message(storecode));
603
604     if (!loop_stop) {
605         struct timeval cur;
606         double elapsed;
607         if (loop_seconds == 0) {
608             goto repeat;
609         }
610         gettimeofday(&cur, NULL);
611         elapsed = cur.tv_sec - start.tv_sec + (cur.tv_usec - start.tv_usec) / 1e+06;
612         if (elapsed < loop_seconds) {
613             goto repeat;
614         }
615     }
616 Finish:
617     gettimeofday(&finish, NULL);
618
619     if (!slcl) {
620         theFids.AFSCBFids_len = 1;
621         theFids.AFSCBFids_val = &sf;
622         theCBs.AFSCBs_len = 1;
623         theCBs.AFSCBs_val = &scb;
624         scb.CallBackType = CB_DROPPED;
625         if ((code = RXAFS_GiveUpCallBacks(sconn, &theFids, &theCBs)))
626             printf("Could not give up source callback: %s\n",
627                    afs_error_message(code));
628     }
629
630     if (!dlcl) {
631         theFids.AFSCBFids_len = 1;
632         theFids.AFSCBFids_val = &df;
633         theCBs.AFSCBs_len = 1;
634         theCBs.AFSCBs_val = &dcb;
635         dcb.CallBackType = CB_DROPPED;
636         if ((code = RXAFS_GiveUpCallBacks(dconn, &theFids, &theCBs)))
637             printf("Could not give up target callback: %s\n",
638                    afs_error_message(code));
639     }
640
641     if (code == 0)
642         code = storecode;
643     if (code == 0)
644         code = fetchcode;
645
646   Fail_dconn:
647     if (!dlcl && !unlock && (slcl || dconn != sconn))
648         rx_DestroyConnection(dconn);
649   Fail_sconn:
650     if (!slcl)
651         rx_DestroyConnection(sconn);
652   Fail_sc:
653     if (dsc && dsc != ssc)
654         RXS_Close(dsc);
655     if (ssc)
656         RXS_Close(ssc);
657   Fail_rx:
658     rx_Finalize();
659
660     free(databuffer);
661     if (printcallerrs && !unlock) {
662         double rate, size, time;
663         if (finish.tv_sec == start.tv_sec) {
664             printf("Copied %lu bytes in %d microseconds\n", total_xfer,
665                    (int)(finish.tv_usec - start.tv_usec));
666         } else {
667             printf("Copied %lu bytes in %d seconds\n", total_xfer,
668                    (int)(finish.tv_sec - start.tv_sec));
669         }
670
671         size = total_xfer / 1024.0;
672         time =
673             finish.tv_sec - start.tv_sec + (finish.tv_usec -
674                                             start.tv_usec) / 1e+06;
675         rate = size / time;
676         printf("Transfer rate %.4g Kbytes/sec\n", rate);
677
678     }
679
680     exit(code != 0);
681 }