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