diff --git a/src/config/stds.h b/src/config/stds.h index be65339d3a..9087c71825 100644 --- a/src/config/stds.h +++ b/src/config/stds.h @@ -283,10 +283,12 @@ typedef struct afsUUID afsUUID; */ #ifdef AFS_NT40_ENV #define AFS_INT64_FMT "I64d" +#define AFS_UINT64_FMT "I64u" #define AFS_PTR_FMT "Ip" #define AFS_SIZET_FMT "Iu" #else #define AFS_INT64_FMT "lld" +#define AFS_UINT64_FMT "llu" #define AFS_PTR_FMT "p" #define AFS_SIZET_FMT "u" #endif diff --git a/src/util/afsutil_prototypes.h b/src/util/afsutil_prototypes.h index 9d0645d011..a05a64ea51 100644 --- a/src/util/afsutil_prototypes.h +++ b/src/util/afsutil_prototypes.h @@ -201,6 +201,8 @@ extern afs_int32 volutil_PartitionName2_r(afs_int32 part, char *tbuffer, size_t extern char *volutil_PartitionName(int avalue); extern afs_int32 util_GetInt32(register char *as, afs_int32 * aval); extern afs_uint32 util_GetUInt32(register char *as, afs_uint32 * aval); +extern afs_int64 util_GetInt64(char *as, afs_int64 * aval); +extern afs_uint64 util_GetUInt64(char *as, afs_uint64 * aval); extern afs_int32 util_GetHumanInt32(register char *as, afs_int32 * aval); /* winsock_nt.c */ diff --git a/src/util/volparse.c b/src/util/volparse.c index 6ba18927c0..cb969357be 100644 --- a/src/util/volparse.c +++ b/src/util/volparse.c @@ -341,3 +341,92 @@ util_GetHumanInt32(register char *as, afs_int32 * aval) return 0; } + +afs_int64 +util_GetInt64(char *as, afs_int64 * aval) +{ + afs_int64 total; + int tc; + int base; + int negative; + + total = 0; /* initialize things */ + negative = 0; + + /* skip over leading spaces */ + while ((tc = *as)) { + if (tc != ' ' && tc != '\t') + break; + } + + /* compute sign */ + if (*as == '-') { + negative = 1; + as++; /* skip over character */ + } + + /* compute the base */ + if (*as == '0') { + as++; + if (*as == 'x' || *as == 'X') { + base = 16; + as++; + } else + base = 8; + } else + base = 10; + + /* compute the # itself */ + while ((tc = *as)) { + if (!ismeta(tc, base)) + return -1; + total *= base; + total += getmeta(tc); + as++; + } + + if (negative) + *aval = -total; + else + *aval = total; + return 0; +} + +afs_uint64 +util_GetUInt64(char *as, afs_uint64 * aval) +{ + afs_uint64 total; + int tc; + int base; + + total = 0; /* initialize things */ + + /* skip over leading spaces */ + while ((tc = *as)) { + if (tc != ' ' && tc != '\t') + break; + } + + /* compute the base */ + if (*as == '0') { + as++; + if (*as == 'x' || *as == 'X') { + base = 16; + as++; + } else + base = 8; + } else + base = 10; + + /* compute the # itself */ + while ((tc = *as)) { + if (!ismeta(tc, base)) + return -1; + total *= base; + total += getmeta(tc); + as++; + } + + *aval = total; + return 0; +} diff --git a/src/venus/Makefile.in b/src/venus/Makefile.in index 0247e98d8e..c571d31793 100644 --- a/src/venus/Makefile.in +++ b/src/venus/Makefile.in @@ -66,6 +66,11 @@ fs.o: fs.c ${INCLS} AFS_component_version_number.c fs: fs.o $(LIBS) ${CC} ${CFLAGS} -o fs fs.o ${TOP_LIBDIR}/libprot.a $(LIBS) ${XLIBS} +afsio.o: afsio.c ${INCLS} AFS_component_version_number.c + +afsio: afsio.o $(LIBS) + ${CC} ${CFLAGS} -o afsio afsio.o ${TOP_LIBDIR}/libprot.a ${TOP_LIBDIR}/libafsint.a $(LIBS) ${XLIBS} + livesys.o: livesys.c ${INCLS} AFS_component_version_number.c livesys: livesys.c $(LIBS) diff --git a/src/venus/afsio.c b/src/venus/afsio.c new file mode 100644 index 0000000000..94bde8f46d --- /dev/null +++ b/src/venus/afsio.c @@ -0,0 +1,1509 @@ +/* + * Copyright (c) 2007, Hartmut Reuter, + * RZG, Max-Planck-Institut f. Plasmaphysik. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#ifdef AFS_NT40_ENV +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define FSINT_COMMON_XG 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_DIRECT_H +#include +#endif +#include +#include +#ifdef AFS_DARWIN_ENV +#include +#else +#include +#endif +#include +#include +#include +#include +#include "../rxkad/md5.h" +#define MAXHOSTS 13 +#ifdef O_LARGEFILE +#define afs_stat stat64 +#define afs_fstat fstat64 +#define afs_open open64 +#else /* !O_LARGEFILE */ +#define afs_stat stat +#define afs_fstat fstat +#define afs_open open +#endif /* !O_LARGEFILE */ +#ifdef AFS_PTHREAD_ENV +#include +pthread_key_t uclient_key; +#endif + +int readFile(struct cmd_syndesc *as, void *); +int writeFile(struct cmd_syndesc *as, void *); +struct rx_connection *FindRXConnection(afs_uint32 host, u_short port, u_short service, struct rx_securityClass *securityObject, int serviceSecurityIndex); +struct cellLookup * FindCell(char *cellName); + +char pnp[255]; +int rxInitDone = 0; +static int verbose = 0; /* Set if -verbose option given */ +static int CBServiceNeeded = 0; +static struct timeval starttime, opentime, readtime, writetime; +afs_uint64 xfered=0, oldxfered=0; +static struct timeval now; +struct timezone Timezone; +static float seconds, datarate, oldseconds; +extern int rxInitDone; +afs_uint64 transid = 0; +afs_uint32 expires = 0; +afs_uint32 server_List[MAXHOSTSPERCELL]; +char tmpstr[1024]; +char tmpstr2[1024]; +static struct ubik_client *uclient; +#define BUFFLEN 65536 +#define WRITEBUFFLEN 1024*1024*64 + +afsUUID uuid; +MD5_CTX md5; +int md5sum = 0; + +struct wbuf { + struct wbuf *next; + afs_uint32 offset; /* offset inside the buffer */ + afs_uint32 buflen; /* total length == BUFFLEN */ + afs_uint32 used; /* bytes used inside buffer */ + char buf[BUFFLEN]; +}; + +struct connectionLookup { + afs_uint32 host; + u_short port; + struct rx_connection *conn; +}; + +struct cellLookup { + struct cellLookup *next; + struct afsconf_cell info; + struct rx_securityClass *sc[3]; + afs_int32 scIndex; +}; + +struct dirLookup { + struct dirLookup *next; + struct dirLookup *prev; + afs_int32 host; + struct cellLookup *cell; + AFSFid fid; + char name[VL_MAXNAMELEN]; +}; + +struct cellLookup *Cells = 0; +struct dirLookup *Dirs = 0; +char cellFname[256]; + +#define MAX_HOSTS 256 +static struct connectionLookup ConnLookup[MAX_HOSTS]; +static int ConnLookupInitialized = 0; + +struct FsCmdInputs PioctlInputs; +struct FsCmdOutputs PioctlOutputs; + +void +printDatarate(void) +{ + seconds = now.tv_sec + now.tv_usec *.000001 + -opentime.tv_sec - opentime.tv_usec *.000001; + if ((seconds - oldseconds) > 30.) { + afs_int64 tmp; + tmp = xfered - oldxfered; + datarate = ((afs_uint32) (tmp >> 20)) / (seconds - oldseconds); + fprintf(stderr,"%llu MB transferred, present date rate = %.0f MB/sec.\n", + xfered >> 20, datarate); + oldxfered = xfered; + oldseconds = seconds; + } +} + +void +SetCellFname(char *name) +{ + struct afsconf_dir *tdir; + + strcpy((char *) &cellFname,"/afs/"); + if (name) + strcat((char *) &cellFname, name); + else { + tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH); + afsconf_GetLocalCell(tdir, &cellFname[5], MAXCELLCHARS); + } +} + +afs_int32 +main (int argc, char **argv) +{ + afs_int32 code; + struct cmd_syndesc *ts; + + strcpy(pnp, argv[0]); + +#ifdef AFS_PTHREAD_ENV + assert(pthread_key_create(&uclient_key, NULL) == 0); +#endif + ts = cmd_CreateSyntax("read", readFile, CMD_REQUIRED, + "read a file from AFS"); + cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname"); + cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0); + cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum"); + + ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED, + "read on a non AFS-client a file from AFS"); + cmd_IsAdministratorCommand(ts); + cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname"); + cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0); + cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum"); + + ts = cmd_CreateSyntax("write", writeFile, CMD_REQUIRED, + "write a file into AFS"); + cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "AFS-filename"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname"); + cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0); + cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum"); + cmd_AddParm(ts, "-synthesize", CMD_SINGLE, CMD_OPTIONAL, "create data pattern of specified length instead reading from stdin"); + + ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED, + "write a file into AFS"); + cmd_IsAdministratorCommand(ts); + cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname"); + cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0); + cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum"); + + ts = cmd_CreateSyntax("append", writeFile, CMD_REQUIRED, + "append to a file in AFS"); + cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "AFS-filename"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname"); + cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0); + + ts = cmd_CreateSyntax("fidappend", writeFile, CMD_REQUIRED, + "append to a file in AFS"); + cmd_IsAdministratorCommand(ts); + cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED, "volume.vnode.uniquifier"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname"); + cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *) 0); + + code = cmd_Dispatch(argc, argv); + exit (0); +} + +AFS_UNUSED +afs_int32 +HandleLocalAuth(struct rx_securityClass **sc[3], afs_int32 *scIndex) +{ + static struct afsconf_dir *tdir = NULL; + struct ktc_principal sname; + struct ktc_token ttoken; + int kvno; + struct ktc_encryptionKey key; + afs_uint32 host = 0; + char *cell; + afs_int32 code; + + tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH); + if (!tdir) { + fprintf(stderr,"Could not open configuration directory: %s.\n", + AFSDIR_SERVER_ETC_DIRPATH); + return -1; + } + cell = tdir->cellName; + strcpy(sname.cell, cell); + sname.instance[0] = 0; + strcpy(sname.name, "afs"); + code=afsconf_GetLatestKey(tdir, &kvno, &key); + if (code) { + fprintf(stderr,"afsconf_GetLatestKey returned %d\n", code); + return -1; + } + ttoken.kvno = kvno; + des_init_random_number_generator(ktc_to_cblock(&key)); + code = des_random_key(ktc_to_cblock(&ttoken.sessionKey)); + if (code) { + fprintf(stderr,"des_random_key returned %d\n", code); + return -1; + } + ttoken.ticketLen = MAXKTCTICKETLEN; + code = tkt_MakeTicket(ttoken.ticket, &ttoken.ticketLen, &key, + AUTH_SUPERUSER, "", sname.cell, + 0, 0xffffffff, + &ttoken.sessionKey, host, + sname.name, sname.instance); + if (code) + *scIndex = 0; + else { + *scIndex = 2; + *sc[2] = (struct rx_securityClass *) + rxkad_NewClientSecurityObject(rxkad_clear, + &ttoken.sessionKey, ttoken.kvno, + ttoken.ticketLen, ttoken.ticket); + } + if (*scIndex == 0) + *sc[0] = (struct rx_securityClass *) rxnull_NewClientSecurityObject(); + return 0; +} + +afs_int32 +AFS_Lookup(struct rx_connection *conn, AFSFid *dirfid, char *name, + AFSFid *outfid, AFSFetchStatus *outstatus, AFSFetchStatus + *dirstatus, AFSCallBack *callback, AFSVolSync *sync) +{ + afs_int32 code = VBUSY; + while (code == VBUSY) { + code = RXAFS_Lookup(conn, dirfid, name, outfid, outstatus, dirstatus, + callback, sync); + if (code == VBUSY) { + fprintf(stderr, "waiting for busy AFS volume %u.\n", + dirfid->Volume); +#ifdef AFS_PTHREAD_ENV + sleep(10); +#else + IOMGR_Sleep(10); +#endif + } + } + return code; +} + +afs_int32 +AFS_FetchStatus(struct rx_connection *conn, AFSFid *fid, AFSFetchStatus + *Status, AFSCallBack *callback, AFSVolSync *sync) +{ + afs_int32 code = VBUSY; + + while (code == VBUSY) { + code = RXAFS_FetchStatus(conn, fid, Status, callback, sync); + if (code == VBUSY) { + fprintf(stderr, "waiting for busy AFS volume %u.\n", + fid->Volume); +#ifdef AFS_PTHREAD_ENV + sleep(10); +#else + IOMGR_Sleep(10); +#endif + } + } + return code; +} + +afs_int32 +StartAFS_FetchData(struct rx_call *call, AFSFid *fid, afs_int32 pos, + afs_int32 len) +{ + afs_int32 code = VBUSY; + while (code == VBUSY) { + code = StartRXAFS_FetchData (call, fid, pos, len); + if (code == VBUSY) { + fprintf(stderr, "waiting for busy AFS volume %u.\n", + fid->Volume); +#ifdef AFS_PTHREAD_ENV + sleep(10); +#else + IOMGR_Sleep(10); +#endif + } + } + return code; +} + +afs_int32 +StartAFS_FetchData64(struct rx_call *call, AFSFid *fid, afs_int64 pos, + afs_int64 len) +{ + afs_int32 code = VBUSY; + while (code == VBUSY) { + code = StartRXAFS_FetchData64 (call, fid, pos, len); + if (code == VBUSY) { + fprintf(stderr, "waiting for busy AFS volume %u.\n", + fid->Volume); +#ifdef AFS_PTHREAD_ENV + sleep(10); +#else + IOMGR_Sleep(10); +#endif + } + } + return code; +} + +afs_int32 +StartAFS_StoreData(struct rx_call *call, AFSFid *fid, AFSStoreStatus *status, + afs_int32 pos, afs_int32 len, afs_int32 len2) +{ + afs_int32 code = VBUSY; + while (code == VBUSY) { + code = StartRXAFS_StoreData (call, fid, status, pos, len, len2); + if (code == VBUSY) { + fprintf(stderr, "waiting for busy AFS volume %u.\n", + fid->Volume); +#ifdef AFS_PTHREAD_ENV + sleep(10); +#else + IOMGR_Sleep(10); +#endif + } + } + return code; +} + +afs_uint32 +StartAFS_StoreData64(struct rx_call *call, AFSFid *fid, AFSStoreStatus *status, + afs_int64 pos, afs_int64 len, afs_int64 len2) +{ + afs_int32 code = VBUSY; + while (code == VBUSY) { + code = StartRXAFS_StoreData64 (call, fid, status, pos, len, len2); + if (code == VBUSY) { + fprintf(stderr, "waiting for busy AFS volume %u.\n", + fid->Volume); +#ifdef AFS_PTHREAD_ENV + sleep(10); +#else + IOMGR_Sleep(10); +#endif + } + } + return code; +} + +afs_int32 +SRXAFSCB_CallBack(struct rx_call *rxcall, AFSCBFids *Fids_Array, + AFSCBs *CallBack_Array) +{ + return 0; +} + +afs_int32 +SRXAFSCB_InitCallBackState(struct rx_call *rxcall) +{ + return 0; +} + +afs_int32 +SRXAFSCB_Probe(struct rx_call *rxcall) +{ + return 0; +} + +afs_int32 +SRXAFSCB_GetCE(struct rx_call *rxcall, + afs_int32 index, + AFSDBCacheEntry * ce) +{ + return(0); +} + +afs_int32 +SRXAFSCB_GetLock(struct rx_call *rxcall, + afs_int32 index, + AFSDBLock * lock) +{ + return(0); +} + +afs_int32 +SRXAFSCB_XStatsVersion(struct rx_call *rxcall, + afs_int32 * versionNumberP) +{ + return(0); +} + +afs_int32 +SRXAFSCB_GetXStats(struct rx_call *rxcall, + afs_int32 clientVersionNumber, + afs_int32 collectionNumber, + afs_int32 * srvVersionNumberP, + afs_int32 * timeP, + AFSCB_CollData * dataP) +{ + return(0); +} + +afs_int32 +SRXAFSCB_ProbeUuid(struct rx_call *a_call, afsUUID *a_uuid) +{ + return(0); +} + + +afs_int32 +SRXAFSCB_WhoAreYou(struct rx_call *a_call, struct interfaceAddr *addr) +{ + int code = 0; + + addr->numberOfInterfaces = 0; + addr->uuid = uuid; +#ifdef notdef + /* return all network interface addresses */ + addr->numberOfInterfaces = afs_cb_interface.numberOfInterfaces; + for ( i=0; i < afs_cb_interface.numberOfInterfaces; i++) { + addr->addr_in[i] = ntohl(afs_cb_interface.addr_in[i]); + addr->subnetmask[i] = ntohl(afs_cb_interface.subnetmask[i]); + addr->mtu[i] = ntohl(afs_cb_interface.mtu[i]); + } +#endif + + return code; +} + +afs_int32 +SRXAFSCB_InitCallBackState2(struct rx_call *a_call, struct interfaceAddr * + addr) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_InitCallBackState3(struct rx_call *a_call, afsUUID *a_uuid) +{ + return 0; +} + +afs_int32 +SRXAFSCB_GetCacheConfig(struct rx_call *a_call, afs_uint32 callerVersion, + afs_uint32 *serverVersion, afs_uint32 *configCount, + cacheConfig *config) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_GetLocalCell(struct rx_call *a_call, char **a_name) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_GetCellServDB(struct rx_call *a_call, afs_int32 a_index, + char **a_name, serverList *a_hosts) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_GetServerPrefs(struct rx_call *a_call, afs_int32 a_index, + afs_int32 *a_srvr_addr, afs_int32 *a_srvr_rank) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_TellMeAboutYourself(struct rx_call *a_call, struct interfaceAddr * + addr, Capabilities *capabilities) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_GetCellByNum(struct rx_call *a_call, afs_int32 a_cellnum, + char **a_name, serverList *a_hosts) +{ + return RXGEN_OPCODE; +} + +afs_int32 +SRXAFSCB_GetCE64(struct rx_call *a_call, afs_int32 a_index, + struct AFSDBCacheEntry64 *a_result) +{ + return RXGEN_OPCODE; +} + +void * +InitializeCBService_LWP(void *unused) +{ + struct rx_securityClass *CBsecobj; + struct rx_service *CBService; + + afs_uuid_create(&uuid); + + CBsecobj = (struct rx_securityClass *)rxnull_NewServerSecurityObject(); + if (!CBsecobj) { + fprintf(stderr,"rxnull_NewServerSecurityObject failed for callback service.\n"); + exit(1); + } + CBService = rx_NewService(0, 1, "afs", &CBsecobj, 1, + RXAFSCB_ExecuteRequest); + if (!CBService) { + fprintf(stderr,"rx_NewService failed for callback service.\n"); + exit(1); + } + rx_StartServer(1); + return 0; +} + + +int +InitializeCBService(void) +{ +#define RESTOOL_CBPORT 7102 +#define MAX_PORT_TRIES 1000 +#define LWP_STACK_SIZE (16 * 1024) + afs_int32 code; +#ifdef AFS_PTHREAD_ENV + pthread_t CBservicePid, parentPid; + pthread_attr_t tattr; +#else + PROCESS CBServiceLWP_ID, parentPid; +#endif + int InitialCBPort; + int CBPort; + +#ifndef NO_AFS_CLIENT + if (!CBServiceNeeded) + return 0; +#endif +#ifndef AFS_PTHREAD_ENV + code = LWP_InitializeProcessSupport(LWP_MAX_PRIORITY - 2, &parentPid); + if (code != LWP_SUCCESS) { + fprintf(stderr,"Unable to initialize LWP support, code %d\n", + code); + exit(1); + } +#endif + +#if defined(AFS_AIX_ENV) || defined(AFS_SUN_ENV) || defined(AFS_DEC_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI_ENV) + srandom(getpid()); + InitialCBPort = RESTOOL_CBPORT + random() % 1000; +#else /* AFS_AIX_ENV || AFS_SUN_ENV || AFS_OSF_ENV || AFS_SGI_ENV */ +#if defined(AFS_HPUX_ENV) + srand48(getpid()); + InitialCBPort = RESTOOL_CBPORT + lrand48() % 1000; +#else /* AFS_HPUX_ENV */ + srand(getpid()); + InitialCBPort = RESTOOL_CBPORT + rand() % 1000; +#endif /* AFS_HPUX_ENV */ +#endif /* AFS_AIX_ENV || AFS_SUN_ENV || AFS_OSF_ENV || AFS_SGI_ENV */ + + CBPort = InitialCBPort; + do { + code = rx_Init(htons(CBPort)); + if (code) { + if ((code == RX_ADDRINUSE) && + (CBPort < MAX_PORT_TRIES + InitialCBPort)) { + CBPort++; + } else if (CBPort < MAX_PORT_TRIES + InitialCBPort) { + fprintf(stderr, "rx_Init didn't succeed for callback service." + " Tried port numbers %d through %d\n", + InitialCBPort, CBPort); + exit(1); + } else { + fprintf(stderr,"Couldn't initialize callback service " + "because too many users are running this program. " + "Try again later.\n"); + exit(1); + } + } + } while(code); +#ifdef AFS_PTHREAD_ENV + assert(pthread_attr_init(&tattr) == 0); + assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0); + assert(pthread_create( + &CBservicePid, &tattr, InitializeCBService_LWP, 0) + == 0); +#else + code = LWP_CreateProcess(InitializeCBService_LWP, LWP_STACK_SIZE, + LWP_MAX_PRIORITY - 2, (int *) 0, "CBService", + &CBServiceLWP_ID); + if (code != LWP_SUCCESS) { + fprintf(stderr,"Unable to create the callback service LWP, code %d\n", + code); + exit(1); + } +#endif + return 0; +} + +int +ScanVnode(char *fname, char *cell) +{ + afs_int32 i, code = 0; + + SetCellFname(cell); + i = sscanf(fname, "%u.%u.%u", + &PioctlInputs.fid.Volume, + &PioctlInputs.fid.Vnode, + &PioctlInputs.fid.Unique); + if (i != 3) { + PioctlInputs.fid.Volume = 0; + PioctlInputs.fid.Vnode = 0; + PioctlInputs.fid.Unique = 0; + fprintf(stderr,"fs: invalid vnode triple: %s\n", fname); + code = EINVAL; + } + /* + * The following is used to handle the case of unknown uniquifier. We + * just need a valid reference to the volume to direct the RPC to the + * right fileserver. Therefore we take the root directory of the volume. + */ + if (PioctlInputs.fid.Unique == 0) { + PioctlInputs.int32s[0] = PioctlInputs.fid.Vnode; + PioctlInputs.fid.Vnode = 1; + PioctlInputs.fid.Unique = 1; + } + return code; +} + +int +VLDBInit(int noAuthFlag, struct afsconf_cell *info) +{ + afs_int32 code; + + code = ugen_ClientInit(noAuthFlag, (char *) AFSDIR_CLIENT_ETC_DIRPATH, + info->name, 0, &uclient, + NULL, pnp, rxkad_clear, + VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50, + 0, 0, USER_SERVICE_ID); + rxInitDone = 1; + return code; +} + +afs_int32 +get_vnode_hosts(char *fname, char **cellp, afs_int32 *hosts, AFSFid *Fid, + int onlyRW) +{ + struct afsconf_dir *tdir; + struct vldbentry vldbEntry; + afs_int32 i, j, code, *h, len; + struct afsconf_cell info; + afs_int32 mask; + + tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH); + if (!tdir) { + fprintf(stderr,"Could not process files in configuration directory " + "(%s).\n",AFSDIR_CLIENT_ETC_DIRPATH); + return -1; + } + if (!*cellp) { + len = MAXCELLCHARS; + *cellp = (char *) malloc(MAXCELLCHARS); + code = afsconf_GetLocalCell(tdir, *cellp, len); + if (code) return code; + } + code = afsconf_GetCellInfo(tdir, *cellp, AFSCONF_VLDBSERVICE, &info); + if (code) { + fprintf(stderr,"fs: cell %s not in %s/CellServDB\n", + *cellp, AFSDIR_CLIENT_ETC_DIRPATH); + return code; + } + + i = sscanf(fname, "%u.%u.%u", &Fid->Volume, &Fid->Vnode, &Fid->Unique); + if (i != 3) { + fprintf(stderr,"fs: invalid vnode triple: %s\n", fname); + return 1; + } + code = VLDBInit(1, &info); + if (code == 0) { + code = ubik_VL_GetEntryByID(uclient, 0, Fid->Volume, + -1, &vldbEntry); + if (code == VL_NOENT) + fprintf(stderr,"fs: volume %u does not exist in this cell.\n", + Fid->Volume); + if (code) return code; + } + h = hosts; + mask = VLSF_RWVOL; + if (!onlyRW) mask |= VLSF_RWVOL; + for (i=0, j=0; jVolume = Tmpafs_int32[1]; + Fid->Vnode = Tmpafs_int32[2]; + Fid->Unique = Tmpafs_int32[3]; + status.in_size = sizeof(struct FsCmdInputs); + status.out_size = sizeof(struct FsCmdOutputs); + status.in = (char *) &PioctlInputs; + status.out = (char *) &PioctlOutputs; + saveCommand = PioctlInputs.command; + saveVolume = PioctlInputs.fid.Volume; + PioctlInputs.command = 0; + PioctlInputs.fid.Volume = 0; + if (!pioctl(fn, VIOC_FS_CMD, &status, 0)) + memcpy((char *)Status, &PioctlOutputs.status, + sizeof(struct AFSFetchStatus)); + PioctlInputs.command = saveCommand; + PioctlInputs.fid.Volume = saveVolume; + if (create && (Status->Length || Status->Length_hi)) { + fprintf(stderr,"AFS file %s not empty, request aborted.\n", + fn); + exit(-5); + } + } + } + return code; +} + +int +DestroyConnections(void) +{ + int i; + + if (!ConnLookupInitialized) return 0; + for (i = 0; i < MAX_HOSTS; i++) { + if (!ConnLookup[i].conn) break; + RXAFS_GiveUpAllCallBacks(ConnLookup[i].conn); + rx_DestroyConnection(ConnLookup[i].conn); + } + if (!rxInitDone) + rx_Finalize(); + return 0; +} + + +int +LogErrors (int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + return vfprintf(stderr, fmt, ap); +} + +int +readFile(struct cmd_syndesc *as, void *unused) +{ + char *fname; + char *cell = 0; + afs_int32 code; + afs_int32 hosts[MAXHOSTS]; + AFSFid Fid; + int i, j; + struct rx_connection *RXConn; + struct cellLookup *cl; + struct rx_call *tcall; + struct AFSVolSync tsync; + struct AFSFetchStatus OutStatus; + struct AFSCallBack CallBack; + afs_int64 Pos; + afs_int32 len; + afs_int64 length, Len; + u_char vnode = 0; + u_char first = 1; + int bytes; + int worstCode = 0; + char *buf = 0; + int bufflen = BUFFLEN; + + i=0; + + if (as->name[0] == 'f') + vnode = 1; + if (as->parms[2].items) + verbose = 1; + if (as->parms[3].items) { + md5sum = 1; + MD5_Init(&md5); + } + + CBServiceNeeded = 1; + InitializeCBService(); + + gettimeofday (&starttime, &Timezone); + fname = as->parms[0].items->data; + cell = 0; + if (as->parms[1].items) + cell = as->parms[1].items->data; + if (vnode) + code = get_vnode_hosts(fname, &cell, hosts, &Fid, 1); + else + code = get_file_cell(fname, &cell, hosts, &Fid, &OutStatus, 0); + if (code) { + fprintf(stderr,"File not found %s\n", fname); + return code; + } + if (Fid.Vnode & 1) { + fprintf(stderr,"%s is a directory, not a file\n", fname); + return ENOENT; + } + cl = FindCell(cell); + for (j=0;jparms[6].items) { + afs_uint32 fields, ip1, ip2, ip3, ip4; + fields = sscanf(as->parms[6].items->data, "%d.%d.%d.%d", + &ip1, &ip2, &ip3, &ip4); + useHost = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4; + j--; + } else { + if (!hosts[j]) + break; + useHost = hosts[j]; + } + first = 0; + RXConn = FindRXConnection(useHost, htons(AFSCONF_FILEPORT), 1, + cl->sc[cl->scIndex], cl->scIndex); + if (!RXConn) { + fprintf(stderr,"rx_NewConnection failed to server 0x%X\n", + useHost); + continue; + } +#ifndef NO_AFS_CLIENT + if (vnode) { +#endif /* NO_AFS_CLIENT */ + code = AFS_FetchStatus(RXConn, &Fid, &OutStatus, &CallBack, &tsync); + if (code) { + fprintf(stderr,"RXAFS_FetchStatus failed to server 0x%X for" + " file %s, code was %d\n", + useHost, fname, code); + continue; + } +#ifndef NO_AFS_CLIENT + } +#endif /* NO_AFS_CLIENT */ + gettimeofday(&opentime, &Timezone); + if (verbose) { + seconds = opentime.tv_sec + opentime.tv_usec *.000001 + -starttime.tv_sec - starttime.tv_usec *.000001; + fprintf(stderr,"Startup to find the file took %.3f sec.\n", + seconds); + } + Len = OutStatus.Length_hi; + Len <<= 32; + Len += OutStatus.Length; + ZeroInt64(Pos); + { + afs_uint32 high, low; + + tcall = rx_NewCall(RXConn); + code = StartAFS_FetchData64 (tcall, &Fid, Pos, Len); + if (code == RXGEN_OPCODE) { + afs_uint32 tmpPos, tmpLen; + tmpPos = Pos; tmpLen = Len; + code = StartAFS_FetchData (tcall, &Fid, Pos, Len); + bytes = rx_Read(tcall, (char *)&low, sizeof(afs_int32)); + length = ntohl(low); + if (bytes != 4) code = -3; + } else if (!code) { + bytes = rx_Read(tcall, (char *)&high, 4); + length = ntohl(high); + length <<= 32; + bytes += rx_Read(tcall, (char *)&low, 4); + length += ntohl(low); + if (bytes != 8) code = -3; + } + if (code) { + if (code == RXGEN_OPCODE) { + fprintf(stderr, "File server for %s might not be running a" + " multi-resident AFS server\n", + fname); + } else { + fprintf(stderr, "%s for %s ended with error code %d\n", + (char *) &as->name, fname, code); + exit(1); + } + } + if (length > bufflen) + len = bufflen; + else + len = length; + buf = (char *)malloc(len); + if (!buf) { + fprintf(stderr, "couldn't allocate buffer\n"); + exit(1); + } + while (!code && NonZeroInt64(length)) { + if (length > bufflen) + len = bufflen; + else + len = length; + bytes = rx_Read(tcall, (char *) buf, len); + if (bytes != len) { + code = -3; + } + if (md5sum) + MD5_Update(&md5, buf, len); + if (!code) + write(1, buf, len); + length -= len; + xfered += len; + gettimeofday(&now, &Timezone); + if (verbose) + printDatarate(); + } + worstCode = code; + code = EndRXAFS_FetchData (tcall, &OutStatus, &CallBack, &tsync); + rx_EndCall(tcall, 0); + if (!worstCode) + worstCode = code; + } + break; + } + gettimeofday(&readtime, &Timezone); + if (worstCode) { + fprintf(stderr,"%s failed with code %d\n", + (char *) &as->name, worstCode); + } else { + if (md5sum) { + afs_uint32 md5int[4]; + char *p; + MD5_Final((char *) &md5int[0], &md5); + p = fname + strlen(fname); + while (p > fname) { + if (*(--p) == '/') { + ++p; + break; + } + } + fprintf(stderr, "%08x%08x%08x%08x %s\n", + htonl(md5int[0]), htonl(md5int[1]), + htonl(md5int[2]), htonl(md5int[3]), p); + } + if(verbose) { + seconds = readtime.tv_sec + readtime.tv_usec *.000001 + -opentime.tv_sec - opentime.tv_usec *.000001; + fprintf(stderr,"Transfer of %llu bytes took %.3f sec.\n", + xfered, seconds); + datarate = (xfered >> 20) / seconds; + fprintf(stderr,"Total data rate = %.0f MB/sec. for read\n", + datarate); + } + } + DestroyConnections(); + return worstCode; +} + +int +writeFile(struct cmd_syndesc *as, void *unused) +{ + char *fname = NULL; + char *cell = 0; + afs_int32 code, localcode = 0; + afs_int32 hosts[MAXHOSTS]; + afs_uint32 useHost; + AFSFid Fid; + int i; + struct rx_connection *RXConn; + struct cellLookup *cl; + struct rx_call *tcall; + struct AFSVolSync tsync; + struct AFSFetchStatus OutStatus; + struct AFSStoreStatus InStatus; + afs_int64 Pos; + afs_int64 length, Len, synthlength = 0, offset = 0; + u_char vnode = 0; + int bytes; + int worstCode = 0; + int append = 0; + int synthesize = 0; + afs_int32 byteswritten; + struct wbuf *bufchain = 0; + struct wbuf *previous, *tbuf; + + i=0; + + if (as->name[0] == 'f') { + vnode = 1; + if (as->name[3] == 'a') + append = 1; + } else + if (as->name[0] == 'a') + append = 1; + if (as->parms[2].items) + verbose = 1; + if (as->parms[3].items) + md5sum = 1; + if (as->parms[4].items) { + code = util_GetInt64(as->parms[4].items->data, &synthlength); + if (code) { + fprintf(stderr, "Invalid value for synthesize length %s\n", + as->parms[4].items->data); + return code; + } + synthesize = 1; + } + CBServiceNeeded = 1; + InitializeCBService(); + + if (as->parms[0].items) + fname = as->parms[0].items->data; + + cell = 0; + if (as->parms[1].items) cell = as->parms[1].items->data; + if (vnode) { + code = get_vnode_hosts(fname, &cell, hosts, &Fid, 1); + if (code) + return code; + } else + code = get_file_cell(fname, &cell, hosts, &Fid, &OutStatus, append ? 0 : 1); + if (code) { + if (code != -5) + fprintf(stderr,"File or directory not found: %s\n", + fname); + return code; + } + if (Fid.Vnode & 1) { + fprintf(stderr,"%s is a directory, not a file\n", fname); + return ENOENT; + } + if (!hosts[0]) { + fprintf(stderr,"AFS file not found: %s\n", fname); + return ENOENT; + } + cl = FindCell(cell); + gettimeofday (&starttime, &Timezone); + useHost = hosts[0]; + RXConn = FindRXConnection(useHost, htons(AFSCONF_FILEPORT), 1, + cl->sc[cl->scIndex], cl->scIndex); + if (!RXConn) { + fprintf(stderr,"rx_NewConnection failed to server 0x%X\n", + hosts[0]); + return -1; + } + InStatus.Mask = AFS_SETMODE + AFS_FSYNC; + InStatus.UnixModeBits = 0644; + if (append) { + Pos = OutStatus.Length_hi; + Pos = (Pos << 32) | OutStatus.Length; + } else + Pos = 0; + previous = (struct wbuf *)&bufchain; + if (md5sum) + MD5_Init(&md5); + + Len = 0; + while (Lenbuflen = BUFFLEN; + if (synthesize) { + afs_int32 ll, l = tbuf->buflen; + if (l > synthlength) + l = synthlength; + for (ll = 0; ll < l; ll += 4096) { + sprintf(&tbuf->buf[ll],"Offset (0x%x, 0x%x)\n", + (unsigned int)(offset >> 32), + (unsigned int)(offset & 0xffffffff) + ll); + } + offset += l; + synthlength -= l; + tbuf->used = l; + } else + tbuf->used = read(0, &tbuf->buf, tbuf->buflen); + if (!tbuf->used) { + free(tbuf); + break; + } + if (md5sum) + MD5_Update(&md5, &tbuf->buf, tbuf->used); + previous->next = tbuf; + previous = tbuf; + Len += tbuf->used; + } + gettimeofday(&opentime, &Timezone); + if (verbose) { + seconds = opentime.tv_sec + opentime.tv_usec *.000001 + -starttime.tv_sec - starttime.tv_usec *.000001; + fprintf(stderr,"Startup to find the file took %.3f sec.\n", + seconds); + } + bytes = Len; + while (!code && bytes) { + afs_int32 code2; + Len = bytes; + restart: + tcall = rx_NewCall(RXConn); + code = StartAFS_StoreData64 (tcall, &Fid, &InStatus, Pos, Len, Pos+Len); + if (code == RXGEN_OPCODE) { + afs_uint32 tmpLen, tmpPos; + tmpPos = Pos; + tmpLen = Len; + if (Pos+Len > 0x7fffffff) { + fprintf(stderr,"AFS fileserver does not support files >= 2 GB\n"); + return EFBIG; + } + code = StartAFS_StoreData (tcall, &Fid, &InStatus, tmpPos, tmpLen, + tmpPos+tmpLen); + } + if (code) { + fprintf(stderr, "StartRXAFS_StoreData had error code %d\n", code); + return code; + } + length = Len; + tbuf = bufchain; + if (Len) { + for (tbuf= bufchain; tbuf; tbuf=tbuf->next) { + if (!tbuf->used) + break; + byteswritten = rx_Write(tcall, tbuf->buf, tbuf->used); + if (byteswritten != tbuf->used) { + fprintf(stderr,"Only %d instead of %" AFS_INT64_FMT " bytes transferred by rx_Write()\n", byteswritten, length); + fprintf(stderr, "At %" AFS_UINT64_FMT " bytes from the end\n", length); + code = -4; + break; + } + xfered += tbuf->used; + gettimeofday(&now, &Timezone); + if (verbose) + printDatarate(); + length -= tbuf->used; + } + } + worstCode = code; + code = EndRXAFS_StoreData64 (tcall, &OutStatus, &tsync); + if (code) { + fprintf(stderr, "EndRXAFS_StoreData64 returned %d\n", code); + worstCode = code; + } + code2 = rx_Error(tcall); + if (code2) { + fprintf(stderr, "rx_Error returned %d\n", code2); + worstCode = code2; + } + code2 = rx_EndCall(tcall, localcode); + if (code2) { + fprintf(stderr, "rx_EndCall returned %d\n", code2); + worstCode = code2; + } + code = worstCode; + if (code == 110) { + fprintf(stderr, "Waiting for busy volume\n"); + sleep(10); + goto restart; + } + Pos += Len; + bytes = 0; + if (!code) { + for (tbuf = bufchain; tbuf; tbuf=tbuf->next) { + tbuf->offset = 0; + if (synthesize) { + afs_int32 ll, l = tbuf->buflen; + if (l > synthlength) + l = synthlength; + for (ll = 0; ll < l; ll += 4096) { + sprintf(&tbuf->buf[ll],"Offset (0x%x, 0x%x)\n", + (unsigned int)(offset >> 32), + (unsigned int)(offset & 0xffffffff) + ll); + } + offset += l; + synthlength -= l; + tbuf->used = l; + } else + tbuf->used = read(0, &tbuf->buf, tbuf->buflen); + if (!tbuf->used) + break; + if (md5sum) + MD5_Update(&md5, &tbuf->buf, tbuf->used); + Len += tbuf->used; + bytes += tbuf->used; + } + } + } + gettimeofday(&writetime, &Timezone); + if (worstCode) { + fprintf(stderr,"%s failed with code %d\n", as->name, worstCode); + } else if(verbose) { + seconds = writetime.tv_sec + writetime.tv_usec *.000001 + -opentime.tv_sec - opentime.tv_usec *.000001; + fprintf(stderr,"Transfer of %llu bytes took %.3f sec.\n", + xfered, seconds); + datarate = (xfered >> 20) / seconds; + fprintf(stderr,"Total data rate = %.0f MB/sec. for write\n", + datarate); + } + while (bufchain) { + tbuf = bufchain; + bufchain = tbuf->next; + free(tbuf); + } + DestroyConnections(); + if (md5sum) { + afs_uint32 md5int[4]; + char *p; + MD5_Final((char *) &md5int[0], &md5); + p = fname + strlen(fname); + while (p > fname) { + if (*(--p) == '/') { + ++p; + break; + } + } + fprintf(stdout, "%08x%08x%08x%08x %s\n", + htonl(md5int[0]), htonl(md5int[1]), + htonl(md5int[2]), htonl(md5int[3]), p); + } + return worstCode; +} + +struct cellLookup * +FindCell(char *cellName) +{ + char name[MAXCELLCHARS]; + char *np; + struct cellLookup *p, *p2; + static struct afsconf_dir *tdir; + struct ktc_principal sname; + struct ktc_token ttoken; + afs_int32 len, code; + + if (cellName) { + np = cellName; + } else { + if (!tdir) + tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH); + len = MAXCELLCHARS; + afsconf_GetLocalCell(tdir, name, len); + np = (char *) &name; + } + SetCellFname(np); + + p2 = (struct cellLookup *) &Cells; + for (p = Cells; p; p = p->next) { + if (!strcmp((char *)&p->info.name, np)) { +#ifdef NO_AFS_CLIENT + if (!strcmp((char *)&lastcell, np)) + code = VLDBInit(1, &p->info); +#endif + return p; + } + p2 = p; + } + p2->next = (struct cellLookup *) malloc(sizeof(struct cellLookup)); + p = p2->next; + memset(p, 0, sizeof(struct cellLookup)); + p->next = (struct cellLookup *) 0; + if (!tdir) + tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH); + if (afsconf_GetCellInfo(tdir, np, AFSCONF_VLDBSERVICE, &p->info)) { + p2->next = (struct cellLookup *) 0; + free(p); + p = (struct cellLookup *) 0; + } else { +#ifdef NO_AFS_CLIENT + if (code = VLDBInit(1, &p->info)) + fprintf(stderr,"VLDBInit failed for cell %s\n", p->info.name); +#endif + strcpy((char *)&sname.cell, (char *)&p->info.name); + sname.instance[0] = 0; + strcpy(sname.name, "afs"); + code = ktc_GetToken(&sname, &ttoken, sizeof(ttoken), NULL); + if (code) + p->scIndex = 0; + else { + if ((ttoken.kvno >= 0) && (ttoken.kvno <= 255)) + /* this is a kerberos ticket, set scIndex accordingly */ + p->scIndex = 2; + else { + fprintf(stderr,"funny kvno (%d) in ticket, proceeding\n", + ttoken.kvno); + p->scIndex = 2; + } + p->sc[2] = (struct rx_securityClass *) + rxkad_NewClientSecurityObject(rxkad_clear, &ttoken.sessionKey, + ttoken.kvno, ttoken.ticketLen, + ttoken.ticket); + } + if (p->scIndex == 0) + p->sc[0] = (struct rx_securityClass *) + rxnull_NewClientSecurityObject(); + } + + if (p) + return p; + else + return 0; +} + +struct rx_connection * +FindRXConnection(afs_uint32 host, u_short port, u_short service, + struct rx_securityClass *securityObject, + int serviceSecurityIndex) +{ + int i; + + if (!ConnLookupInitialized) { + memset(ConnLookup, 0, MAX_HOSTS * sizeof(struct connectionLookup)); + ConnLookupInitialized = 1; + } + + for (i = 0; i < MAX_HOSTS; i++) { + if ((ConnLookup[i].host == host) && (ConnLookup[i].port == port)) + return ConnLookup[i].conn; + if (!ConnLookup[i].conn) + break; + } + + if (i >= MAX_HOSTS) + return 0; + + ConnLookup[i].conn = rx_NewConnection(host, port, service, securityObject, serviceSecurityIndex); + if (ConnLookup[i].conn) { + ConnLookup[i].host = host; + ConnLookup[i].port = port; + } + + return ConnLookup[i].conn; +}