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