e795e6bb0da658cf623cc2f2df7e6a8769e1eed1
[openafs.git] / src / venus / afsio.c
1 /*
2  * Copyright (c) 2007, Hartmut Reuter,
3  * RZG, Max-Planck-Institut f. Plasmaphysik.
4  * All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in
13  *      the documentation and/or other materials provided with the
14  *      distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <afsconfig.h>
29 #include <afs/param.h>
30 #include <afs/stds.h>
31
32 #include <stdio.h>
33 #include <setjmp.h>
34 #include <sys/types.h>
35 #include <string.h>
36 #include <ctype.h>
37 #ifdef AFS_NT40_ENV
38 #include <windows.h>
39 #include <winsock2.h>
40 #define _CRT_RAND_S
41 #include <stdlib.h>
42 #include <process.h>
43 #include <fcntl.h>
44 #include <io.h>
45 #include <afs/smb_iocons.h>
46 #include <afs/afsd.h>
47 #include <afs/cm_ioctl.h>
48 #include <afs/pioctl_nt.h>
49 #else
50 #include <sys/param.h>
51 #include <sys/file.h>
52 #include <sys/ioctl.h>
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
56 #include <netdb.h>
57 #include <string.h>
58 #include <fcntl.h>
59 #include <pwd.h>
60 #include <afs/venus.h>
61 #include <sys/time.h>
62 #include <netdb.h>
63 #include <afs/afsint.h>
64 #define FSINT_COMMON_XG 1
65 #endif
66 #include <sys/stat.h>
67 #include <errno.h>
68 #include <signal.h>
69 #include <afs/vice.h>
70 #include <afs/cmd.h>
71 #include <afs/auth.h>
72 #include <afs/cellconfig.h>
73 #include <afs/afsutil.h>
74 #include <rx/rx.h>
75 #include <rx/xdr.h>
76 #include <afs/afs_consts.h>
77 #include <afs/afscbint.h>
78 #include <afs/vldbint.h>
79 #include <afs/vlserver.h>
80 #include <afs/volser.h>
81 #include <afs/ptint.h>
82 #include <afs/dir.h>
83 #include <afs/nfs.h>
84 #include <afs/ihandle.h>
85 #include <afs/vnode.h>
86 #include <afs/com_err.h>
87 #ifdef HAVE_DIRENT_H
88 #include <dirent.h>
89 #endif
90 #ifdef HAVE_DIRECT_H
91 #include <direct.h>
92 #endif
93 #ifdef AFS_DARWIN_ENV
94 #include <sys/malloc.h>
95 #else
96 #include <malloc.h>
97 #endif
98 #include <afs/errors.h>
99 #include <afs/sys_prototypes.h>
100 #include <des_prototypes.h>
101 #include <rx_prototypes.h>
102 #include "../rxkad/md5.h"
103 #ifdef O_LARGEFILE
104 #define afs_stat        stat64
105 #define afs_fstat       fstat64
106 #define afs_open        open64
107 #else /* !O_LARGEFILE */
108 #define afs_stat        stat
109 #define afs_fstat       fstat
110 #define afs_open        open
111 #endif /* !O_LARGEFILE */
112 #ifdef AFS_PTHREAD_ENV
113 #include <assert.h>
114 pthread_key_t uclient_key;
115 #endif
116
117 int readFile(struct cmd_syndesc *as, void *);
118 int writeFile(struct cmd_syndesc *as, void *);
119 struct rx_connection *FindRXConnection(afs_uint32 host, u_short port, u_short service, struct rx_securityClass *securityObject, int serviceSecurityIndex);
120 struct cellLookup * FindCell(char *cellName);
121
122 char pnp[255];
123 int rxInitDone = 0;
124 static int verbose = 0;         /* Set if -verbose option given */
125 static int CBServiceNeeded = 0;
126 static struct timeval starttime, opentime, readtime, writetime;
127 afs_uint64 xfered=0, oldxfered=0;
128 static struct timeval now;
129 struct timezone Timezone;
130 static float seconds, datarate, oldseconds;
131 extern int rxInitDone;
132 afs_uint64 transid = 0;
133 afs_uint32 expires = 0;
134 afs_uint32 server_List[MAXHOSTSPERCELL];
135 char tmpstr[1024];
136 char tmpstr2[1024];
137 static struct ubik_client *uclient;
138 #define BUFFLEN 65536
139 #define WRITEBUFFLEN 1024*1024*64
140
141 afsUUID uuid;
142 MD5_CTX md5;
143 int md5sum = 0;
144
145 struct wbuf {
146     struct wbuf *next;
147     afs_uint32 offset;          /* offset inside the buffer */
148     afs_uint32 buflen;          /* total length == BUFFLEN */
149     afs_uint32 used;            /* bytes used inside buffer */
150     char buf[BUFFLEN];
151 };
152
153 struct connectionLookup {
154     afs_uint32 host;
155     u_short port;
156     struct rx_connection *conn;
157 };
158
159 struct cellLookup {
160     struct cellLookup *next;
161     struct afsconf_cell info;
162     struct rx_securityClass *sc;
163     afs_int32 scIndex;
164 };
165
166 struct dirLookup {
167     struct dirLookup *next;
168     struct dirLookup *prev;
169     afs_int32 host;
170     struct cellLookup *cell;
171     AFSFid fid;
172     char name[VL_MAXNAMELEN];
173 };
174
175 struct cellLookup *Cells = 0;
176 struct dirLookup  *Dirs = 0;
177 char cellFname[256];
178
179 #define MAX_HOSTS 256
180 static struct connectionLookup ConnLookup[MAX_HOSTS];
181 static int ConnLookupInitialized = 0;
182
183 struct FsCmdInputs PioctlInputs;
184 struct FsCmdOutputs PioctlOutputs;
185
186 void
187 printDatarate(void)
188 {
189     seconds = (float)(now.tv_sec + now.tv_usec *.000001
190         -opentime.tv_sec - opentime.tv_usec *.000001);
191     if ((seconds - oldseconds) > 30.) {
192         afs_int64 tmp;
193         tmp = xfered - oldxfered;
194         datarate = ((afs_uint32) (tmp >> 20)) / (seconds - oldseconds);
195         fprintf(stderr,"%llu MB transferred, present date rate = %.0f MB/sec.\n",
196                 xfered >> 20, datarate);
197         oldxfered = xfered;
198         oldseconds = seconds;
199     }
200 }
201
202 void
203 SetCellFname(char *name)
204 {
205     struct afsconf_dir *tdir;
206
207     strcpy((char *) &cellFname,"/afs/");
208     if (name)
209         strcat((char *) &cellFname, name);
210     else {
211         tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
212         afsconf_GetLocalCell(tdir, &cellFname[5], MAXCELLCHARS);
213     }
214 }
215
216 afs_int32
217 main (int argc, char **argv)
218 {
219     afs_int32 code;
220     struct cmd_syndesc *ts;
221
222     strcpy(pnp, argv[0]);
223
224 #ifdef AFS_PTHREAD_ENV
225     assert(pthread_key_create(&uclient_key, NULL) == 0);
226 #endif
227     ts = cmd_CreateSyntax("read", readFile, CMD_REQUIRED,
228                           "read a file from AFS");
229     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
230     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
231     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
232     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
233
234     ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED,
235                           "read on a non AFS-client a file from AFS");
236     cmd_IsAdministratorCommand(ts);
237     cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier");
238     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
239     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
240     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
241
242     ts = cmd_CreateSyntax("write", writeFile, CMD_REQUIRED,
243                           "write a file into AFS");
244     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "AFS-filename");
245     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
246     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
247     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
248     cmd_AddParm(ts, "-synthesize", CMD_SINGLE, CMD_OPTIONAL, "create data pattern of specified length instead reading from stdin");
249
250     ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED,
251                           "write a file into AFS");
252     cmd_IsAdministratorCommand(ts);
253     cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier");
254     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
255     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
256     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
257
258     ts = cmd_CreateSyntax("append", writeFile, CMD_REQUIRED,
259                           "append to a file in AFS");
260     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "AFS-filename");
261     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
262     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
263
264     ts = cmd_CreateSyntax("fidappend", writeFile, CMD_REQUIRED,
265                           "append to a file in AFS");
266     cmd_IsAdministratorCommand(ts);
267     cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier");
268     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
269     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0);
270
271     code = cmd_Dispatch(argc, argv);
272     exit (0);
273 }
274
275 AFS_UNUSED
276 afs_int32
277 HandleLocalAuth(struct rx_securityClass **sc, afs_int32 *scIndex)
278 {
279     static struct afsconf_dir *tdir = NULL;
280     struct ktc_principal sname;
281     struct ktc_token ttoken;
282     int kvno;
283     struct ktc_encryptionKey key;
284     afs_uint32 host = 0;
285     char *cell;
286     afs_int32 code;
287
288     *sc = NULL;
289     *scIndex = 0;
290
291     tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
292     if (!tdir) {
293         fprintf(stderr,"Could not open configuration directory: %s.\n",
294                 AFSDIR_SERVER_ETC_DIRPATH);
295         return -1;
296     }
297     code = afsconf_ClientAuth(tdir, sc, &scIndex);
298     if (code) {
299         fprintf(stderr,"afsconf_ClientAuth returned %d\n", code);
300         return -1;
301     }
302     return 0;
303 }
304
305 afs_int32
306 AFS_Lookup(struct rx_connection *conn, AFSFid *dirfid, char *name,
307            AFSFid *outfid, AFSFetchStatus *outstatus, AFSFetchStatus
308            *dirstatus, AFSCallBack *callback, AFSVolSync *sync)
309 {
310     afs_int32 code = VBUSY;
311     while (code == VBUSY) {
312         code = RXAFS_Lookup(conn, dirfid, name, outfid, outstatus, dirstatus,
313                             callback, sync);
314         if (code == VBUSY) {
315             fprintf(stderr, "waiting for busy AFS volume %u.\n",
316                     dirfid->Volume);
317 #ifdef AFS_PTHREAD_ENV
318             sleep(10);
319 #else
320             IOMGR_Sleep(10);
321 #endif
322         }
323     }
324     return code;
325 }
326
327 afs_int32
328 AFS_FetchStatus(struct rx_connection *conn, AFSFid *fid, AFSFetchStatus
329                 *Status, AFSCallBack *callback, AFSVolSync *sync)
330 {
331     afs_int32 code = VBUSY;
332
333     while (code == VBUSY) {
334         code = RXAFS_FetchStatus(conn, fid, Status, callback, sync);
335         if (code == VBUSY) {
336             fprintf(stderr, "waiting for busy AFS volume %u.\n",
337                     fid->Volume);
338 #ifdef AFS_PTHREAD_ENV
339             sleep(10);
340 #else
341             IOMGR_Sleep(10);
342 #endif
343         }
344     }
345     return code;
346 }
347
348 afs_int32
349 StartAFS_FetchData(struct rx_call *call, AFSFid *fid, afs_int32 pos,
350                    afs_int32 len)
351 {
352     afs_int32 code = VBUSY;
353     while (code == VBUSY) {
354         code = StartRXAFS_FetchData (call, fid, pos, len);
355         if (code == VBUSY) {
356             fprintf(stderr, "waiting for busy AFS volume %u.\n",
357                     fid->Volume);
358 #ifdef AFS_PTHREAD_ENV
359             sleep(10);
360 #else
361             IOMGR_Sleep(10);
362 #endif
363         }
364     }
365     return code;
366 }
367
368 afs_int32
369 StartAFS_FetchData64(struct rx_call *call, AFSFid *fid, afs_int64 pos,
370                      afs_int64 len)
371 {
372     afs_int32 code = VBUSY;
373     while (code == VBUSY) {
374         code = StartRXAFS_FetchData64 (call, fid, pos, len);
375         if (code == VBUSY) {
376             fprintf(stderr, "waiting for busy AFS volume %u.\n",
377                     fid->Volume);
378 #ifdef AFS_PTHREAD_ENV
379             sleep(10);
380 #else
381             IOMGR_Sleep(10);
382 #endif
383         }
384     }
385     return code;
386 }
387
388 afs_int32
389 StartAFS_StoreData(struct rx_call *call, AFSFid *fid, AFSStoreStatus *status,
390                    afs_int32 pos, afs_int32 len, afs_int32 len2)
391 {
392     afs_int32 code = VBUSY;
393     while (code == VBUSY) {
394         code = StartRXAFS_StoreData (call, fid, status, pos, len, len2);
395         if (code == VBUSY) {
396             fprintf(stderr, "waiting for busy AFS volume %u.\n",
397                     fid->Volume);
398 #ifdef AFS_PTHREAD_ENV
399             sleep(10);
400 #else
401             IOMGR_Sleep(10);
402 #endif
403         }
404     }
405     return code;
406 }
407
408 afs_uint32
409 StartAFS_StoreData64(struct rx_call *call, AFSFid *fid, AFSStoreStatus *status,
410                      afs_int64 pos, afs_int64 len, afs_int64 len2)
411 {
412     afs_int32 code = VBUSY;
413     while (code == VBUSY) {
414         code = StartRXAFS_StoreData64 (call, fid, status, pos, len, len2);
415         if (code == VBUSY) {
416             fprintf(stderr, "waiting for busy AFS volume %u.\n",
417                     fid->Volume);
418 #ifdef AFS_PTHREAD_ENV
419             sleep(10);
420 #else
421             IOMGR_Sleep(10);
422 #endif
423         }
424     }
425     return code;
426 }
427
428 afs_int32
429 SRXAFSCB_CallBack(struct rx_call *rxcall, AFSCBFids *Fids_Array,
430                   AFSCBs *CallBack_Array)
431 {
432     return 0;
433 }
434
435 afs_int32
436 SRXAFSCB_InitCallBackState(struct rx_call *rxcall)
437 {
438     return 0;
439 }
440
441 afs_int32
442 SRXAFSCB_Probe(struct rx_call *rxcall)
443 {
444     return 0;
445 }
446
447 afs_int32
448 SRXAFSCB_GetCE(struct rx_call *rxcall,
449                afs_int32 index,
450                AFSDBCacheEntry * ce)
451 {
452     return(0);
453 }
454
455 afs_int32
456 SRXAFSCB_GetLock(struct rx_call *rxcall,
457                  afs_int32 index,
458                  AFSDBLock * lock)
459 {
460     return(0);
461 }
462
463 afs_int32
464 SRXAFSCB_XStatsVersion(struct rx_call *rxcall,
465                        afs_int32 * versionNumberP)
466 {
467     return(0);
468 }
469
470 afs_int32
471 SRXAFSCB_GetXStats(struct rx_call *rxcall,
472                    afs_int32 clientVersionNumber,
473                    afs_int32 collectionNumber,
474                    afs_int32 * srvVersionNumberP,
475                    afs_int32 * timeP,
476                    AFSCB_CollData * dataP)
477 {
478     return(0);
479 }
480
481 afs_int32
482 SRXAFSCB_ProbeUuid(struct rx_call *a_call, afsUUID *a_uuid)
483 {
484     return(0);
485 }
486
487
488 afs_int32
489 SRXAFSCB_WhoAreYou(struct rx_call *a_call, struct interfaceAddr *addr)
490 {
491     int code = 0;
492
493     addr->numberOfInterfaces = 0;
494     addr->uuid = uuid;
495 #ifdef notdef
496     /* return all network interface addresses */
497     addr->numberOfInterfaces = afs_cb_interface.numberOfInterfaces;
498     for ( i=0; i < afs_cb_interface.numberOfInterfaces; i++) {
499         addr->addr_in[i] = ntohl(afs_cb_interface.addr_in[i]);
500         addr->subnetmask[i] = ntohl(afs_cb_interface.subnetmask[i]);
501         addr->mtu[i] = ntohl(afs_cb_interface.mtu[i]);
502     }
503 #endif
504
505     return code;
506 }
507
508 afs_int32
509 SRXAFSCB_InitCallBackState2(struct rx_call *a_call, struct interfaceAddr *
510                             addr)
511 {
512     return RXGEN_OPCODE;
513 }
514
515 afs_int32
516 SRXAFSCB_InitCallBackState3(struct rx_call *a_call, afsUUID *a_uuid)
517 {
518     return 0;
519 }
520
521 afs_int32
522 SRXAFSCB_GetCacheConfig(struct rx_call *a_call, afs_uint32 callerVersion,
523                         afs_uint32 *serverVersion, afs_uint32 *configCount,
524                         cacheConfig *config)
525 {
526     return RXGEN_OPCODE;
527 }
528
529 afs_int32
530 SRXAFSCB_GetLocalCell(struct rx_call *a_call, char **a_name)
531 {
532     return RXGEN_OPCODE;
533 }
534
535 afs_int32
536 SRXAFSCB_GetCellServDB(struct rx_call *a_call, afs_int32 a_index,
537                        char **a_name, serverList *a_hosts)
538 {
539     return RXGEN_OPCODE;
540 }
541
542 afs_int32
543 SRXAFSCB_GetServerPrefs(struct rx_call *a_call, afs_int32 a_index,
544                         afs_int32 *a_srvr_addr, afs_int32 *a_srvr_rank)
545 {
546     return RXGEN_OPCODE;
547 }
548
549 afs_int32
550 SRXAFSCB_TellMeAboutYourself(struct rx_call *a_call, struct interfaceAddr *
551                              addr, Capabilities *capabilities)
552 {
553     return RXGEN_OPCODE;
554 }
555
556 afs_int32
557 SRXAFSCB_GetCellByNum(struct rx_call *a_call, afs_int32 a_cellnum,
558                       char **a_name, serverList *a_hosts)
559 {
560     return RXGEN_OPCODE;
561 }
562
563 afs_int32
564 SRXAFSCB_GetCE64(struct rx_call *a_call, afs_int32 a_index,
565                  struct AFSDBCacheEntry64 *a_result)
566 {
567     return RXGEN_OPCODE;
568 }
569
570 void *
571 InitializeCBService_LWP(void *unused)
572 {
573     struct rx_securityClass *CBsecobj;
574     struct rx_service *CBService;
575
576     afs_uuid_create(&uuid);
577
578     CBsecobj = (struct rx_securityClass *)rxnull_NewServerSecurityObject();
579     if (!CBsecobj) {
580         fprintf(stderr,"rxnull_NewServerSecurityObject failed for callback service.\n");
581         exit(1);
582     }
583     CBService = rx_NewService(0, 1, "afs", &CBsecobj, 1,
584                               RXAFSCB_ExecuteRequest);
585     if (!CBService) {
586         fprintf(stderr,"rx_NewService failed for callback service.\n");
587         exit(1);
588     }
589     rx_StartServer(1);
590     return 0;
591 }
592
593
594 int
595 InitializeCBService(void)
596 {
597 #define RESTOOL_CBPORT 7102
598 #define MAX_PORT_TRIES 1000
599 #define LWP_STACK_SIZE  (16 * 1024)
600     afs_int32 code;
601 #ifdef AFS_PTHREAD_ENV
602     pthread_t CBservicePid;
603     pthread_attr_t tattr;
604 #else
605     PROCESS CBServiceLWP_ID, parentPid;
606 #endif
607     int InitialCBPort;
608     int CBPort;
609
610 #ifndef NO_AFS_CLIENT
611     if (!CBServiceNeeded)
612         return 0;
613 #endif
614 #ifndef AFS_PTHREAD_ENV
615     code = LWP_InitializeProcessSupport(LWP_MAX_PRIORITY - 2, &parentPid);
616     if (code != LWP_SUCCESS) {
617         fprintf(stderr,"Unable to initialize LWP support, code %d\n",
618                 code);
619         exit(1);
620     }
621 #endif
622
623 #if defined(AFS_AIX_ENV) || defined(AFS_SUN_ENV) || defined(AFS_DEC_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI_ENV)
624     srandom(getpid());
625     InitialCBPort = RESTOOL_CBPORT + random() % 1000;
626 #else /* AFS_AIX_ENV || AFS_SUN_ENV || AFS_OSF_ENV || AFS_SGI_ENV */
627 #if defined(AFS_HPUX_ENV)
628     srand48(getpid());
629     InitialCBPort = RESTOOL_CBPORT + lrand48() % 1000;
630 #else /* AFS_HPUX_ENV */
631 #if defined AFS_NT40_ENV
632     srand(_getpid());
633     InitialCBPort = RESTOOL_CBPORT + rand() % 1000;
634 #else /* AFS_NT40_ENV */
635     srand(getpid());
636     InitialCBPort = RESTOOL_CBPORT + rand() % 1000;
637 #endif /* AFS_NT40_ENV */
638 #endif /* AFS_HPUX_ENV */
639 #endif /* AFS_AIX_ENV || AFS_SUN_ENV || AFS_OSF_ENV || AFS_SGI_ENV */
640
641     CBPort = InitialCBPort;
642     do {
643         code = rx_Init(htons(CBPort));
644         if (code) {
645             if ((code == RX_ADDRINUSE) &&
646                 (CBPort < MAX_PORT_TRIES + InitialCBPort)) {
647                 CBPort++;
648             } else if (CBPort < MAX_PORT_TRIES + InitialCBPort) {
649                 fprintf(stderr, "rx_Init didn't succeed for callback service."
650                         " Tried port numbers %d through %d\n",
651                         InitialCBPort, CBPort);
652                 exit(1);
653             } else {
654                 fprintf(stderr,"Couldn't initialize callback service "
655                         "because too many users are running this program. "
656                         "Try again later.\n");
657                 exit(1);
658             }
659         }
660     } while(code);
661 #ifdef AFS_PTHREAD_ENV
662     assert(pthread_attr_init(&tattr) == 0);
663     assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
664     assert(pthread_create(
665                &CBservicePid, &tattr, InitializeCBService_LWP, 0)
666            == 0);
667 #else
668     code = LWP_CreateProcess(InitializeCBService_LWP, LWP_STACK_SIZE,
669                              LWP_MAX_PRIORITY - 2, (int *) 0, "CBService",
670                              &CBServiceLWP_ID);
671     if (code != LWP_SUCCESS) {
672         fprintf(stderr,"Unable to create the callback service LWP, code %d\n",
673                 code);
674         exit(1);
675     }
676 #endif
677     return 0;
678 }
679
680 int
681 ScanVnode(char *fname, char *cell)
682 {
683     afs_int32 i, code = 0;
684
685     SetCellFname(cell);
686     i = sscanf(fname, "%u.%u.%u",
687                &PioctlInputs.fid.Volume,
688                &PioctlInputs.fid.Vnode,
689                &PioctlInputs.fid.Unique);
690     if (i != 3) {
691         PioctlInputs.fid.Volume = 0;
692         PioctlInputs.fid.Vnode = 0;
693         PioctlInputs.fid.Unique = 0;
694         fprintf(stderr,"fs: invalid vnode triple: %s\n", fname);
695         code = EINVAL;
696     }
697     /*
698      * The following is used to handle the case of unknown uniquifier. We
699      * just need a valid reference to the volume to direct the RPC to the
700      * right fileserver. Therefore we take the root directory of the volume.
701      */
702     if (PioctlInputs.fid.Unique == 0) {
703         PioctlInputs.int32s[0] = PioctlInputs.fid.Vnode;
704         PioctlInputs.fid.Vnode = 1;
705         PioctlInputs.fid.Unique = 1;
706     }
707     return code;
708 }
709
710 int
711 VLDBInit(int noAuthFlag, struct afsconf_cell *info)
712 {
713     afs_int32 code;
714
715     code = ugen_ClientInit(noAuthFlag, (char *) AFSDIR_CLIENT_ETC_DIRPATH,
716                            info->name, 0, &uclient,
717                            NULL, pnp, rxkad_clear,
718                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
719                            0, 0, USER_SERVICE_ID);
720     rxInitDone = 1;
721     return code;
722 }
723
724 afs_int32
725 get_vnode_hosts(char *fname, char **cellp, afs_int32 *hosts, AFSFid *Fid,
726                 int onlyRW)
727 {
728     struct afsconf_dir *tdir;
729     struct vldbentry vldbEntry;
730     afs_int32 i, j, code, *h, len;
731     struct afsconf_cell info;
732     afs_int32 mask;
733
734     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
735     if (!tdir) {
736         fprintf(stderr,"Could not process files in configuration directory "
737                 "(%s).\n",AFSDIR_CLIENT_ETC_DIRPATH);
738         return -1;
739     }
740     if (!*cellp) {
741         len = MAXCELLCHARS;
742         *cellp = (char *) malloc(MAXCELLCHARS);
743         code = afsconf_GetLocalCell(tdir, *cellp, len);
744         if (code) return code;
745     }
746     code = afsconf_GetCellInfo(tdir, *cellp, AFSCONF_VLDBSERVICE, &info);
747     if (code) {
748         fprintf(stderr,"fs: cell %s not in %s/CellServDB\n",
749                 *cellp, AFSDIR_CLIENT_ETC_DIRPATH);
750         return code;
751     }
752
753     i = sscanf(fname, "%u.%u.%u", &Fid->Volume, &Fid->Vnode, &Fid->Unique);
754     if (i != 3) {
755         fprintf(stderr,"fs: invalid vnode triple: %s\n", fname);
756         return 1;
757     }
758     code = VLDBInit(1, &info);
759     if (code == 0) {
760         code = ubik_VL_GetEntryByID(uclient, 0, Fid->Volume,
761                                     -1, &vldbEntry);
762         if (code == VL_NOENT)
763             fprintf(stderr,"fs: volume %u does not exist in this cell.\n",
764                     Fid->Volume);
765         if (code) return code;
766     }
767     h = hosts;
768     mask = VLSF_RWVOL;
769     if (!onlyRW) mask |= VLSF_RWVOL;
770     for (i=0, j=0; j<vldbEntry.nServers; j++) {
771         if (vldbEntry.serverFlags[j] & mask) {
772             *h++ = ntohl(vldbEntry.serverNumber[j]);
773             i++;
774         }
775     }
776     for (; i<AFS_MAXHOSTS; i++) *h++ = 0;
777     return 0;
778 }
779
780 /* get_file_cell()
781  *     Determine which AFS cell file 'fn' lives in, the list of servers that
782  *     offer it, and the FID.
783  */
784 afs_int32
785 get_file_cell(char *fn, char **cellp, afs_int32 hosts[AFS_MAXHOSTS], AFSFid *Fid,
786               struct AFSFetchStatus *Status, afs_int32 create)
787 {
788     afs_int32 code;
789     char buf[256];
790     struct ViceIoctl status;
791     int j;
792     afs_int32 *Tmpafs_int32;
793
794     memset( Status, 0, sizeof(struct AFSFetchStatus));
795     memset(buf, 0, sizeof(buf));
796     status.in_size = 0;
797     status.out_size = sizeof(buf);
798     status.in = buf;
799     status.out = buf;
800     errno = 0;
801     code = pioctl(fn, VIOC_FILE_CELL_NAME, &status, 0);
802     if (code && create) {
803         char *c;
804         int fd;
805         strcpy(buf,fn);
806         if ((c = strrchr(buf,'/'))) {
807             *c = 0;
808             code = pioctl(buf,VIOC_FILE_CELL_NAME, &status, 0);
809             if (!code) {
810                 fd = open(fn, O_CREAT, 0644);
811                 close(fd);
812             }
813             code = pioctl(fn, VIOC_FILE_CELL_NAME, &status, 0);
814         }
815     }
816     if (code) {
817         fprintf(stderr, "Unable to determine cell for %s\n", fn);
818         if (errno) {
819             perror(fn);
820             if (errno == EINVAL)
821                 fprintf(stderr, "(File might not be in AFS)\n");
822         } else
823             afs_com_err(pnp, code, (char *) 0);
824     } else {
825         *cellp = (char *) malloc(strlen(buf)+1);
826         strcpy(*cellp, buf);
827         SetCellFname(*cellp);
828         memset(buf, 0, sizeof(buf));
829         status.in = 0;
830         status.in_size = 0;
831         status.out = buf;
832         status.out_size = sizeof(buf);
833         code = pioctl(fn, VIOCWHEREIS, &status, 0);
834         if (code) {
835             fprintf(stderr, "Unable to determine fileservers for %s\n", fn);
836             if (errno) {
837                 perror(fn);
838             }
839             else
840                 afs_com_err(pnp, code, (char *) 0);
841         } else {
842             Tmpafs_int32 = (afs_int32 *)buf;
843             for (j=0;j<AFS_MAXHOSTS;++j) {
844                 hosts[j] = Tmpafs_int32[j];
845                 if (!Tmpafs_int32[j])
846                     break;
847             }
848         }
849         memset(buf, 0, sizeof(buf));
850         status.in_size = 0;
851         status.out_size = sizeof(buf);
852         status.in = 0;
853         status.out = buf;
854         code = pioctl(fn, VIOCGETFID, &status, 0);
855         if (code) {
856             fprintf(stderr, "Unable to determine FID for %s\n", fn);
857             if (errno) {
858                 perror(fn);
859             } else {
860                 afs_com_err(pnp, code, (char *) 0);
861             }
862         } else {
863             Tmpafs_int32 = (afs_int32 *)buf;
864             Fid->Volume = Tmpafs_int32[1];
865             Fid->Vnode = Tmpafs_int32[2];
866             Fid->Unique = Tmpafs_int32[3];
867         }
868     }
869     return code;
870 }
871
872 int
873 DestroyConnections(void)
874 {
875     int i;
876
877     if (!ConnLookupInitialized) return 0;
878     for (i = 0; i < MAX_HOSTS; i++) {
879         if (!ConnLookup[i].conn) break;
880         RXAFS_GiveUpAllCallBacks(ConnLookup[i].conn);
881         rx_DestroyConnection(ConnLookup[i].conn);
882     }
883     if (!rxInitDone)
884         rx_Finalize();
885     return 0;
886 }
887
888
889 int
890 LogErrors (int level, const char *fmt, ...)
891 {
892     va_list ap;
893
894     va_start(ap, fmt);
895     return vfprintf(stderr, fmt, ap);
896 }
897
898 int
899 readFile(struct cmd_syndesc *as, void *unused)
900 {
901     char *fname;
902     char *cell = 0;
903     afs_int32 code;
904     afs_int32 hosts[AFS_MAXHOSTS];
905     AFSFid Fid;
906     int i, j;
907     struct rx_connection *RXConn;
908     struct cellLookup *cl;
909     struct rx_call *tcall;
910     struct AFSVolSync tsync;
911     struct AFSFetchStatus OutStatus;
912     struct AFSCallBack CallBack;
913     afs_int64 Pos;
914     afs_int32 len;
915     afs_int64 length, Len;
916     u_char vnode = 0;
917     u_char first = 1;
918     int bytes;
919     int worstCode = 0;
920     char *buf = 0;
921     int bufflen = BUFFLEN;
922
923     i=0;
924
925     if (as->name[0] == 'f')
926         vnode = 1;
927     if (as->parms[2].items)
928         verbose = 1;
929     if (as->parms[3].items) {
930         md5sum = 1;
931         MD5_Init(&md5);
932     }
933
934     CBServiceNeeded = 1;
935     InitializeCBService();
936
937     gettimeofday (&starttime, &Timezone);
938     fname = as->parms[0].items->data;
939     cell = 0;
940     if (as->parms[1].items)
941         cell = as->parms[1].items->data;
942     if (vnode)
943         code = get_vnode_hosts(fname, &cell, hosts, &Fid, 1);
944     else
945         code = get_file_cell(fname, &cell, hosts, &Fid, &OutStatus, 0);
946     if (code) {
947         fprintf(stderr,"File not found %s\n", fname);
948         return code;
949     }
950     if (Fid.Vnode & 1) {
951         fprintf(stderr,"%s is a directory, not a file\n", fname);
952         return ENOENT;
953     }
954     cl = FindCell(cell);
955     for (j=0;j<AFS_MAXHOSTS;++j) {
956         int useHost;
957
958         if (first && as->parms[6].items) {
959             afs_uint32 fields, ip1, ip2, ip3, ip4;
960             fields = sscanf(as->parms[6].items->data, "%d.%d.%d.%d",
961                             &ip1, &ip2, &ip3, &ip4);
962             useHost = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
963             j--;
964         } else {
965             if (!hosts[j])
966                 break;
967             useHost = hosts[j];
968         }
969         first = 0;
970         RXConn = FindRXConnection(useHost, htons(AFSCONF_FILEPORT), 1,
971                                   cl->sc, cl->scIndex);
972         if (!RXConn) {
973             fprintf(stderr,"rx_NewConnection failed to server 0x%X\n",
974                     useHost);
975             continue;
976         }
977 #ifndef NO_AFS_CLIENT
978         if (vnode) {
979 #endif /* NO_AFS_CLIENT */
980             code = AFS_FetchStatus(RXConn, &Fid, &OutStatus, &CallBack, &tsync);
981             if (code) {
982                 fprintf(stderr,"RXAFS_FetchStatus failed to server 0x%X for"
983                         " file %s, code was %d\n",
984                         useHost, fname, code);
985                 continue;
986             }
987 #ifndef NO_AFS_CLIENT
988         }
989 #endif /* NO_AFS_CLIENT */
990         gettimeofday(&opentime, &Timezone);
991         if (verbose) {
992             seconds = (float)(opentime.tv_sec + opentime.tv_usec *.000001
993                 -starttime.tv_sec - starttime.tv_usec *.000001);
994             fprintf(stderr,"Startup to find the file took %.3f sec.\n",
995                     seconds);
996         }
997         Len = OutStatus.Length_hi;
998         Len <<= 32;
999         Len += OutStatus.Length;
1000         ZeroInt64(Pos);
1001         {
1002             afs_uint32 high, low;
1003
1004             tcall = rx_NewCall(RXConn);
1005             code = StartAFS_FetchData64 (tcall, &Fid, Pos, Len);
1006             if (code == RXGEN_OPCODE) {
1007                 afs_int32 tmpPos,  tmpLen;
1008                 tmpPos = (afs_int32)Pos; tmpLen = (afs_int32)Len;
1009                 code = StartAFS_FetchData (tcall, &Fid, tmpPos, tmpLen);
1010                 bytes = rx_Read(tcall, (char *)&low, sizeof(afs_int32));
1011                 length = ntohl(low);
1012                 if (bytes != 4) code = -3;
1013             } else if (!code) {
1014                 bytes = rx_Read(tcall, (char *)&high, 4);
1015                 length = ntohl(high);
1016                 length <<= 32;
1017                 bytes += rx_Read(tcall, (char *)&low, 4);
1018                 length += ntohl(low);
1019                 if (bytes != 8) code = -3;
1020             }
1021             if (code) {
1022                 if (code == RXGEN_OPCODE) {
1023                     fprintf(stderr, "File server for %s might not be running a"
1024                             " multi-resident AFS server\n",
1025                             fname);
1026                 } else {
1027                     fprintf(stderr, "%s for %s ended with error code %d\n",
1028                             (char *) &as->name, fname, code);
1029                     exit(1);
1030                 }
1031             }
1032             if (length > bufflen)
1033                 len = bufflen;
1034             else
1035                 len = (afs_int32) length;
1036             buf = (char *)malloc(len);
1037             if (!buf) {
1038                 fprintf(stderr, "couldn't allocate buffer\n");
1039                 exit(1);
1040             }
1041             while (!code && NonZeroInt64(length)) {
1042                 if (length > bufflen)
1043                     len = bufflen;
1044                 else
1045                     len = (afs_int32) length;
1046                 bytes = rx_Read(tcall, (char *) buf, len);
1047                 if (bytes != len) {
1048                     code = -3;
1049                 }
1050                 if (md5sum)
1051                     MD5_Update(&md5, buf, len);
1052                 if (!code)
1053                     write(1, buf, len);
1054                 length -= len;
1055                 xfered += len;
1056                 gettimeofday(&now, &Timezone);
1057                 if (verbose)
1058                     printDatarate();
1059             }
1060             worstCode = code;
1061             code = EndRXAFS_FetchData (tcall, &OutStatus, &CallBack, &tsync);
1062             rx_EndCall(tcall, 0);
1063             if (!worstCode)
1064                 worstCode = code;
1065         }
1066         break;
1067     }
1068     gettimeofday(&readtime, &Timezone);
1069     if (worstCode) {
1070         fprintf(stderr,"%s failed with code %d\n",
1071                 (char *) &as->name, worstCode);
1072     } else {
1073         if (md5sum) {
1074             afs_uint32 md5int[4];
1075             char *p;
1076             MD5_Final((char *) &md5int[0], &md5);
1077             p = fname + strlen(fname);
1078             while (p > fname) {
1079                 if (*(--p) == '/') {
1080                     ++p;
1081                     break;
1082                 }
1083             }
1084             fprintf(stderr, "%08x%08x%08x%08x  %s\n",
1085                     htonl(md5int[0]), htonl(md5int[1]),
1086                     htonl(md5int[2]), htonl(md5int[3]), p);
1087         }
1088         if(verbose) {
1089             seconds = (float)(readtime.tv_sec + readtime.tv_usec *.000001
1090                 -opentime.tv_sec - opentime.tv_usec *.000001);
1091             fprintf(stderr,"Transfer of %llu bytes took %.3f sec.\n",
1092                     xfered, seconds);
1093             datarate = (xfered >> 20) / seconds;
1094             fprintf(stderr,"Total data rate = %.0f MB/sec. for read\n",
1095                     datarate);
1096         }
1097     }
1098     DestroyConnections();
1099     return worstCode;
1100 }
1101
1102 int
1103 writeFile(struct cmd_syndesc *as, void *unused)
1104 {
1105     char *fname = NULL;
1106     char *cell = 0;
1107     afs_int32 code, localcode = 0;
1108     afs_int32 hosts[AFS_MAXHOSTS];
1109     afs_uint32 useHost;
1110     AFSFid Fid;
1111     int i;
1112     struct rx_connection *RXConn;
1113     struct cellLookup *cl;
1114     struct rx_call *tcall;
1115     struct AFSVolSync tsync;
1116     struct AFSFetchStatus OutStatus;
1117     struct AFSStoreStatus InStatus;
1118     struct AFSCallBack CallBack;
1119     afs_int64 Pos;
1120     afs_int64 length, Len, synthlength = 0, offset = 0;
1121     u_char vnode = 0;
1122     afs_int64 bytes;
1123     int worstCode = 0;
1124     int append = 0;
1125     int synthesize = 0;
1126     afs_int32 byteswritten;
1127     struct wbuf *bufchain = 0;
1128     struct wbuf *previous, *tbuf;
1129
1130     i=0;
1131
1132     if (as->name[0] == 'f') {
1133         vnode = 1;
1134         if (as->name[3] == 'a')
1135             append = 1;
1136     } else
1137         if (as->name[0] == 'a')
1138             append = 1;
1139     if (as->parms[2].items)
1140         verbose = 1;
1141     if (as->parms[3].items)
1142         md5sum = 1;
1143     if (as->parms[4].items) {
1144         code = util_GetInt64(as->parms[4].items->data, &synthlength);
1145         if (code) {
1146             fprintf(stderr, "Invalid value for synthesize length %s\n",
1147                     as->parms[4].items->data);
1148             return code;
1149         }
1150         synthesize = 1;
1151     }
1152     CBServiceNeeded = 1;
1153     InitializeCBService();
1154
1155     if (as->parms[0].items)
1156         fname = as->parms[0].items->data;
1157
1158     cell = 0;
1159     if (as->parms[1].items) cell = as->parms[1].items->data;
1160     if (vnode) {
1161         code = get_vnode_hosts(fname, &cell, hosts, &Fid, 1);
1162         if (code)
1163             return code;
1164     } else
1165         code = get_file_cell(fname, &cell, hosts, &Fid, &OutStatus, append ? 0 : 1);
1166     if (code) {
1167         fprintf(stderr,"File or directory not found: %s\n",
1168                     fname);
1169         return code;
1170     }
1171     if (Fid.Vnode & 1) {
1172         fprintf(stderr,"%s is a directory, not a file\n", fname);
1173         return ENOENT;
1174     }
1175     if (!hosts[0]) {
1176         fprintf(stderr,"AFS file not found: %s\n", fname);
1177         return ENOENT;
1178     }
1179     cl = FindCell(cell);
1180     gettimeofday (&starttime, &Timezone);
1181     useHost = hosts[0];
1182     RXConn = FindRXConnection(useHost, htons(AFSCONF_FILEPORT), 1,
1183                               cl->sc, cl->scIndex);
1184     if (!RXConn) {
1185         fprintf(stderr,"rx_NewConnection failed to server 0x%X\n",
1186                 hosts[0]);
1187         return -1;
1188     }
1189     code = AFS_FetchStatus(RXConn, &Fid, &OutStatus, &CallBack, &tsync);
1190     if (code) {
1191         fprintf(stderr,"RXAFS_FetchStatus failed to server 0x%X for file %s, code was%d\n",
1192                             useHost, fname, code);
1193        return -1;
1194     }
1195     if (!append && (OutStatus.Length || OutStatus.Length_hi)) {
1196         fprintf(stderr,"AFS file %s not empty, request aborted.\n", fname);
1197         DestroyConnections();
1198         return -5;
1199     }
1200     InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
1201     InStatus.UnixModeBits = 0644;
1202     if (append) {
1203         Pos = OutStatus.Length_hi;
1204         Pos = (Pos << 32) | OutStatus.Length;
1205     } else
1206         Pos = 0;
1207     previous = (struct wbuf *)&bufchain;
1208     if (md5sum)
1209         MD5_Init(&md5);
1210
1211     Len = 0;
1212     while (Len<WRITEBUFFLEN) {
1213         tbuf = (struct wbuf *)malloc(sizeof(struct wbuf));
1214         if (!tbuf) {
1215             if (!bufchain) {
1216                 fprintf(stderr, "Couldn't allocate buffer, aborting\n");
1217                 exit(1);
1218             }
1219             break;
1220         }
1221         memset(tbuf, 0, sizeof(struct wbuf));
1222         tbuf->buflen = BUFFLEN;
1223         if (synthesize) {
1224             afs_int64 ll, l = tbuf->buflen;
1225             if (l > synthlength)
1226                 l = synthlength;
1227             for (ll = 0; ll < l; ll += 4096) {
1228                 sprintf(&tbuf->buf[ll],"Offset (0x%x, 0x%x)\n",
1229                         (unsigned int)((offset + ll) >> 32),
1230                         (unsigned int)((offset + ll) & 0xffffffff));
1231             }
1232             offset += l;
1233             synthlength -= l;
1234             tbuf->used = (afs_int32)l;
1235         } else
1236             tbuf->used = read(0, &tbuf->buf, tbuf->buflen);
1237         if (!tbuf->used) {
1238             free(tbuf);
1239             break;
1240         }
1241         if (md5sum)
1242             MD5_Update(&md5, &tbuf->buf, tbuf->used);
1243         previous->next = tbuf;
1244         previous = tbuf;
1245         Len += tbuf->used;
1246     }
1247     gettimeofday(&opentime, &Timezone);
1248     if (verbose) {
1249         seconds = (float) (opentime.tv_sec + opentime.tv_usec *.000001
1250             -starttime.tv_sec - starttime.tv_usec *.000001);
1251         fprintf(stderr,"Startup to find the file took %.3f sec.\n",
1252                 seconds);
1253     }
1254     bytes = Len;
1255     while (!code && bytes) {
1256         afs_int32 code2;
1257         Len = bytes;
1258     restart:
1259         tcall = rx_NewCall(RXConn);
1260         code = StartAFS_StoreData64 (tcall, &Fid, &InStatus, Pos, Len, Pos+Len);
1261         if (code == RXGEN_OPCODE) {
1262             afs_uint32 tmpLen, tmpPos;
1263             tmpPos = (afs_int32) Pos;
1264             tmpLen = (afs_int32) Len;
1265             if (Pos+Len > 0x7fffffff) {
1266                 fprintf(stderr,"AFS fileserver does not support files >= 2 GB\n");
1267                 return EFBIG;
1268             }
1269             code = StartAFS_StoreData (tcall, &Fid, &InStatus, tmpPos, tmpLen,
1270                                        tmpPos+tmpLen);
1271         }
1272         if (code) {
1273             fprintf(stderr, "StartRXAFS_StoreData had error code %d\n", code);
1274             return code;
1275         }
1276         length = Len;
1277         tbuf = bufchain;
1278         if (Len) {
1279             for (tbuf= bufchain; tbuf; tbuf=tbuf->next) {
1280                 if (!tbuf->used)
1281                     break;
1282                 byteswritten = rx_Write(tcall, tbuf->buf, tbuf->used);
1283                 if (byteswritten != tbuf->used) {
1284                     fprintf(stderr,"Only %d instead of %" AFS_INT64_FMT " bytes transferred by rx_Write()\n", byteswritten, length);
1285                     fprintf(stderr, "At %" AFS_UINT64_FMT " bytes from the end\n", length);
1286                     code = -4;
1287                     break;
1288                 }
1289                 xfered += tbuf->used;
1290                 gettimeofday(&now, &Timezone);
1291                 if (verbose)
1292                     printDatarate();
1293                 length -= tbuf->used;
1294             }
1295         }
1296         worstCode = code;
1297         code = EndRXAFS_StoreData64 (tcall, &OutStatus, &tsync);
1298         if (code) {
1299             fprintf(stderr, "EndRXAFS_StoreData64 returned %d\n", code);
1300             worstCode = code;
1301         }
1302         code2 = rx_Error(tcall);
1303         if (code2) {
1304             fprintf(stderr, "rx_Error returned %d\n", code2);
1305             worstCode = code2;
1306         }
1307         code2 = rx_EndCall(tcall, localcode);
1308         if (code2) {
1309             fprintf(stderr, "rx_EndCall returned %d\n", code2);
1310             worstCode = code2;
1311         }
1312         code = worstCode;
1313         if (code == 110) {
1314             fprintf(stderr, "Waiting for busy volume\n");
1315             sleep(10);
1316             goto restart;
1317         }
1318         Pos += Len;
1319         bytes = 0;
1320         if (!code) {
1321             for (tbuf = bufchain; tbuf; tbuf=tbuf->next) {
1322                 tbuf->offset = 0;
1323                 if (synthesize) {
1324                     afs_int64 ll, l = tbuf->buflen;
1325                     if (l > synthlength)
1326                         l = synthlength;
1327                     for (ll = 0; ll < l; ll += 4096) {
1328                         sprintf(&tbuf->buf[ll],"Offset (0x%x, 0x%x)\n",
1329                                 (unsigned int)((offset + ll) >> 32),
1330                                 (unsigned int)((offset + ll) & 0xffffffff));
1331                     }
1332                     offset += l;
1333                     synthlength -= l;
1334                     tbuf->used = (afs_int32) l;
1335                 } else
1336                     tbuf->used = read(0, &tbuf->buf, tbuf->buflen);
1337                 if (!tbuf->used)
1338                     break;
1339                 if (md5sum)
1340                     MD5_Update(&md5, &tbuf->buf, tbuf->used);
1341                 Len += tbuf->used;
1342                 bytes += tbuf->used;
1343             }
1344         }
1345     }
1346     gettimeofday(&writetime, &Timezone);
1347     if (worstCode) {
1348         fprintf(stderr,"%s failed with code %d\n", as->name, worstCode);
1349     } else if(verbose) {
1350         seconds = (float) (writetime.tv_sec + writetime.tv_usec *.000001
1351             -opentime.tv_sec - opentime.tv_usec *.000001);
1352         fprintf(stderr,"Transfer of %llu bytes took %.3f sec.\n",
1353                 xfered, seconds);
1354         datarate = (xfered >> 20) / seconds;
1355         fprintf(stderr,"Total data rate = %.0f MB/sec. for write\n",
1356                 datarate);
1357     }
1358     while (bufchain) {
1359         tbuf = bufchain;
1360         bufchain = tbuf->next;
1361         free(tbuf);
1362     }
1363     DestroyConnections();
1364     if (md5sum) {
1365         afs_uint32 md5int[4];
1366         char *p;
1367         MD5_Final((char *) &md5int[0], &md5);
1368         p = fname + strlen(fname);
1369         while (p > fname) {
1370             if (*(--p) == '/') {
1371                 ++p;
1372                 break;
1373             }
1374         }
1375         fprintf(stdout, "%08x%08x%08x%08x  %s\n",
1376                 htonl(md5int[0]), htonl(md5int[1]),
1377                 htonl(md5int[2]), htonl(md5int[3]), p);
1378     }
1379     return worstCode;
1380 }
1381
1382 struct cellLookup *
1383 FindCell(char *cellName)
1384 {
1385     char name[MAXCELLCHARS];
1386     char *np;
1387     struct cellLookup *p, *p2;
1388     static struct afsconf_dir *tdir;
1389     struct ktc_principal sname;
1390     struct ktc_token ttoken;
1391     afs_int32 len, code;
1392
1393     if (cellName) {
1394         np = cellName;
1395     } else {
1396         if (!tdir)
1397             tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
1398         len = MAXCELLCHARS;
1399         afsconf_GetLocalCell(tdir, name, len);
1400         np = (char *) &name;
1401     }
1402     SetCellFname(np);
1403
1404     p2 = (struct cellLookup *) &Cells;
1405     for (p = Cells; p; p = p->next) {
1406         if (!strcmp((char *)&p->info.name, np)) {
1407 #ifdef NO_AFS_CLIENT
1408             if (!strcmp((char *)&lastcell, np))
1409                 code = VLDBInit(1, &p->info);
1410 #endif
1411             return p;
1412         }
1413         p2 = p;
1414     }
1415     p2->next = (struct cellLookup *) malloc(sizeof(struct cellLookup));
1416     p = p2->next;
1417     memset(p, 0, sizeof(struct cellLookup));
1418     p->next = (struct cellLookup *) 0;
1419     if (!tdir)
1420         tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
1421     if (afsconf_GetCellInfo(tdir, np, AFSCONF_VLDBSERVICE, &p->info)) {
1422         p2->next = (struct cellLookup *) 0;
1423         free(p);
1424         p = (struct cellLookup *) 0;
1425     } else {
1426 #ifdef NO_AFS_CLIENT
1427         if (code = VLDBInit(1, &p->info))
1428             fprintf(stderr,"VLDBInit failed for cell %s\n", p->info.name);
1429 #endif
1430         code = afsconf_ClientAuthToken(&p->info, 0, &p->sc, &p->scIndex);
1431         if (code) {
1432             p->scIndex = 0;
1433             p->sc = rxnull_NewClientSecurityObject();
1434         }
1435     }
1436
1437     if (p)
1438         return p;
1439     else
1440         return 0;
1441 }
1442
1443 struct rx_connection *
1444 FindRXConnection(afs_uint32 host, u_short port, u_short service,
1445                  struct rx_securityClass *securityObject,
1446                  int serviceSecurityIndex)
1447 {
1448     int i;
1449
1450     if (!ConnLookupInitialized) {
1451         memset(ConnLookup, 0, MAX_HOSTS * sizeof(struct connectionLookup));
1452         ConnLookupInitialized = 1;
1453     }
1454
1455     for (i = 0; i < MAX_HOSTS; i++) {
1456         if ((ConnLookup[i].host == host) && (ConnLookup[i].port == port))
1457             return ConnLookup[i].conn;
1458         if (!ConnLookup[i].conn)
1459             break;
1460     }
1461
1462     if (i >= MAX_HOSTS)
1463         return 0;
1464
1465     ConnLookup[i].conn = rx_NewConnection(host, port, service, securityObject, serviceSecurityIndex);
1466     if (ConnLookup[i].conn) {
1467         ConnLookup[i].host = host;
1468         ConnLookup[i].port = port;
1469     }
1470
1471     return ConnLookup[i].conn;
1472 }