/* * open RPC connection to rpc.metamhd */ static mhd_handle_t * open_metamhd( char *hostname, md_error_t *ep ) { CLIENT *clientp; mhd_handle_t *hp; /* default to local host */ if ((hostname == NULL) || (*hostname == '\0')) hostname = mynode(); /* open RPC connection */ assert(hostname != NULL); if ((clientp = meta_client_create(hostname, METAMHD, METAMHD_VERSION, "tcp")) == NULL) { clnt_pcreateerror(hostname); (void) mdrpccreateerror(ep, hostname, "metamhd clnt_create"); return (NULL); } else { auth_destroy(clientp->cl_auth); clientp->cl_auth = authsys_create_default(); assert(clientp->cl_auth != NULL); } /* return connection */ hp = Zalloc(sizeof (*hp)); hp->hostname = Strdup(hostname); hp->clientp = clientp; return (hp); }
int main(int argn, char *argc[]) { //Program parameters : argc[1] : HostName or Host IP // argc[2] : Server Program Number // other arguments depend on test case //run_mode can switch into stand alone program or program launch by shell script //1 : stand alone, debug mode, more screen information //0 : launch by shell script as test case, only one printf -> result status int run_mode = 0; int test_status = 1; //Default test result set to FAILED int progNum = atoi(argc[2]); AUTH *authSys = NULL; authSys = authsys_create_default(); //If we are here, macro call was successful test_status = ((AUTH *)authSys != NULL) ? 0 : 1; //This last printf gives the result status to the tests suite //normally should be 0: test has passed or 1: test has failed printf("%d\n", test_status); return test_status; }
int dotest(void) { CLIENT *client; AUTH *auth; COMPOUND4args args; COMPOUND4res res; enum clnt_stat status; struct timeval timeout; nfs_argop4 arg[1]; char *tag = "dtrace test"; volatile int a = 0; while (waiting(&a) == 0) continue; timeout.tv_sec = 30; timeout.tv_usec = 0; client = clnt_create("localhost", NFS4_PROGRAM, NFS_V4, "tcp"); if (client == NULL) { clnt_pcreateerror("test"); return (1); } auth = authsys_create_default(); client->cl_auth = auth; args.minorversion = 0; args.tag.utf8string_len = strlen(tag); args.tag.utf8string_val = tag; args.argarray.argarray_len = sizeof (arg) / sizeof (nfs_argop4); args.argarray.argarray_val = arg; arg[0].argop = OP_PUTROOTFH; /* no need to manipulate nfs_argop4_u */ bzero(&res, sizeof (res)); status = clnt_call(client, NFSPROC4_COMPOUND, xdr_COMPOUND4args, (caddr_t)&args, xdr_COMPOUND4res, (caddr_t)&res, timeout); if (status != RPC_SUCCESS) { clnt_perror(client, "test"); return (2); } return (0); }
int main(int argc, char **argv) { CLIENT *cl; square_in in; square_out out; if (argc != 3) err_quit("usage: client <hostname> <integer-value>"); cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp"); auth_destroy(cl->cl_auth); cl->cl_auth = authsys_create_default(); in.arg1 = atol(argv[2]); if (squareproc_2(&in, &out, cl) != RPC_SUCCESS) err_quit("%s", clnt_sperror(cl, argv[1])); printf("result: %ld\n", out.res1); exit(0); }
/* * Send a RPC_MNT UMOUNT request for dirp to hostname. */ int do_umount(char *hostname, char *dirp) { enum clnt_stat clnt_stat; struct timeval try; CLIENT *clp; try.tv_sec = 3; try.tv_usec = 0; clp = clnt_create_timed(hostname, MOUNTPROG, MOUNTVERS, "udp", &try); if (clp == NULL) { warnx("%s: %s", hostname, clnt_spcreateerror("MOUNTPROG")); return (0); } clp->cl_auth = authsys_create_default(); clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir, dirp, (xdrproc_t)xdr_void, (caddr_t)0, try); if (clnt_stat != RPC_SUCCESS) warnx("%s: %s", hostname, clnt_sperror(clp, "MOUNTPROC_UMNT")); auth_destroy(clp->cl_auth); clnt_destroy(clp); return (clnt_stat == RPC_SUCCESS); }
/* * This routine is designed to be able to "ping" * a list of hosts and create a list of responding * hosts sorted by response time. * This must be done without any prior * contact with the host - therefore the "ping" * must be to a "well-known" address. The outstanding * candidate here is the address of "rpcbind". * * A response to a ping is no guarantee that the host * is running NFS, has a mount daemon, or exports * the required filesystem. If the subsequent * mount attempt fails then the host will be marked * "ignore" and the host list will be re-pinged * (sans the bad host). This process continues * until a successful mount is achieved or until * there are no hosts left to try. */ enum clnt_stat nfs_cast(struct mapfs *mfs_in, struct mapfs **mfs_out, int timeout) { enum clnt_stat stat; AUTH *sys_auth = authsys_create_default(); XDR xdr_stream; register XDR *xdrs = &xdr_stream; int outlen; int if_inx; int tsec; int flag; int sent, addr_cnt, rcvd, if_cnt; fd_set readfds, mask; register ulong_t xid; /* xid - unique per addr */ register int i; struct rpc_msg msg; struct timeval t, rcv_timeout; char outbuf[UDPMSGSIZE], inbuf[UDPMSGSIZE]; struct t_unitdata t_udata, t_rdata; struct nd_hostserv hs; struct nd_addrlist *retaddrs; struct transp *tr_head; struct transp *trans, *prev_trans; struct addrs *a, *prev_addr; struct tstamps *ts, *prev_ts; NCONF_HANDLE *nc = NULL; struct netconfig *nconf; struct rlimit rl; int dtbsize; struct mapfs *mfs; /* * For each connectionless transport get a list of * host addresses. Any single host may have * addresses on several transports. */ addr_cnt = sent = rcvd = 0; tr_head = NULL; FD_ZERO(&mask); /* * Set the default select size to be the maximum FD_SETSIZE, unless * the current rlimit is lower. */ dtbsize = FD_SETSIZE; if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { if (rl.rlim_cur < FD_SETSIZE) dtbsize = rl.rlim_cur; } prev_trans = NULL; prev_addr = NULL; prev_ts = NULL; for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { if (trace > 2) trace_prt(1, "nfs_cast: host=%s\n", mfs->mfs_host); nc = setnetconfig(); if (nc == NULL) { stat = RPC_CANTSEND; goto done_broad; } while (nconf = getnetconfig(nc)) { if (!(nconf->nc_flag & NC_VISIBLE) || nconf->nc_semantics != NC_TPI_CLTS || (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)) continue; trans = (struct transp *)malloc(sizeof (*trans)); if (trans == NULL) { syslog(LOG_ERR, "no memory"); stat = RPC_CANTSEND; goto done_broad; } (void) memset(trans, 0, sizeof (*trans)); if (tr_head == NULL) tr_head = trans; else prev_trans->tr_next = trans; prev_trans = trans; trans->tr_fd = t_open(nconf->nc_device, O_RDWR, NULL); if (trans->tr_fd < 0) { syslog(LOG_ERR, "nfscast: t_open: %s:%m", nconf->nc_device); stat = RPC_CANTSEND; goto done_broad; } if (t_bind(trans->tr_fd, (struct t_bind *)NULL, (struct t_bind *)NULL) < 0) { syslog(LOG_ERR, "nfscast: t_bind: %m"); stat = RPC_CANTSEND; goto done_broad; } trans->tr_taddr = /* LINTED pointer alignment */ (struct t_bind *)t_alloc(trans->tr_fd, T_BIND, T_ADDR); if (trans->tr_taddr == (struct t_bind *)NULL) { syslog(LOG_ERR, "nfscast: t_alloc: %m"); stat = RPC_SYSTEMERROR; goto done_broad; } trans->tr_device = nconf->nc_device; FD_SET(trans->tr_fd, &mask); if_inx = 0; hs.h_host = mfs->mfs_host; hs.h_serv = "rpcbind"; if (netdir_getbyname(nconf, &hs, &retaddrs) == ND_OK) { /* * If mfs->ignore is previously set for * this map, clear it. Because a host can * have either v6 or v4 address */ if (mfs->mfs_ignore == 1) mfs->mfs_ignore = 0; a = (struct addrs *)malloc(sizeof (*a)); if (a == NULL) { syslog(LOG_ERR, "no memory"); stat = RPC_CANTSEND; goto done_broad; } (void) memset(a, 0, sizeof (*a)); if (trans->tr_addrs == NULL) trans->tr_addrs = a; else prev_addr->addr_next = a; prev_addr = a; a->addr_if_tstamps = NULL; a->addr_mfs = mfs; a->addr_addrs = retaddrs; if_cnt = retaddrs->n_cnt; while (if_cnt--) { ts = (struct tstamps *) malloc(sizeof (*ts)); if (ts == NULL) { syslog(LOG_ERR, "no memory"); stat = RPC_CANTSEND; goto done_broad; } (void) memset(ts, 0, sizeof (*ts)); ts->ts_penalty = mfs->mfs_penalty; if (a->addr_if_tstamps == NULL) a->addr_if_tstamps = ts; else prev_ts->ts_next = ts; prev_ts = ts; ts->ts_inx = if_inx++; addr_cnt++; } break; } else { mfs->mfs_ignore = 1; if (verbose) syslog(LOG_ERR, "%s:%s address not known", mfs->mfs_host, strcmp(nconf->nc_proto, NC_INET)?"IPv6":"IPv4"); } } /* while */ endnetconfig(nc); nc = NULL; } /* for */ if (addr_cnt == 0) { syslog(LOG_ERR, "nfscast: couldn't find addresses"); stat = RPC_CANTSEND; goto done_broad; } (void) gettimeofday(&t, (struct timezone *)0); xid = (getpid() ^ t.tv_sec ^ t.tv_usec) & ~0xFF; t.tv_usec = 0; /* serialize the RPC header */ msg.rm_direction = CALL; msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; msg.rm_call.cb_prog = RPCBPROG; /* * we can not use RPCBVERS here since it doesn't exist in 4.X, * the fix to bug 1139883 has made the 4.X portmapper silent to * version mismatches. This causes the RPC call to the remote * portmapper to simply be ignored if it's not Version 2. */ msg.rm_call.cb_vers = PMAPVERS; msg.rm_call.cb_proc = NULLPROC; if (sys_auth == (AUTH *)NULL) { stat = RPC_SYSTEMERROR; goto done_broad; } msg.rm_call.cb_cred = sys_auth->ah_cred; msg.rm_call.cb_verf = sys_auth->ah_verf; xdrmem_create(xdrs, outbuf, sizeof (outbuf), XDR_ENCODE); if (! xdr_callmsg(xdrs, &msg)) { stat = RPC_CANTENCODEARGS; goto done_broad; } outlen = (int)xdr_getpos(xdrs); xdr_destroy(xdrs); t_udata.opt.len = 0; t_udata.udata.buf = outbuf; t_udata.udata.len = outlen; /* * Basic loop: send packet to all hosts and wait for response(s). * The response timeout grows larger per iteration. * A unique xid is assigned to each address in order to * correctly match the replies. */ for (tsec = 4; timeout > 0; tsec *= 2) { timeout -= tsec; if (timeout <= 0) tsec += timeout; rcv_timeout.tv_sec = tsec; rcv_timeout.tv_usec = 0; sent = 0; for (trans = tr_head; trans; trans = trans->tr_next) { for (a = trans->tr_addrs; a; a = a->addr_next) { struct netbuf *if_netbuf = a->addr_addrs->n_addrs; ts = a->addr_if_tstamps; if_cnt = a->addr_addrs->n_cnt; while (if_cnt--) { /* * xid is the first thing in * preserialized buffer */ /* LINTED pointer alignment */ *((ulong_t *)outbuf) = htonl(xid + ts->ts_inx); (void) gettimeofday(&(ts->ts_timeval), (struct timezone *)0); /* * Check if already received * from a previous iteration. */ if (ts->ts_rcvd) { sent++; ts = ts->ts_next; continue; } t_udata.addr = *if_netbuf++; if (t_sndudata(trans->tr_fd, &t_udata) == 0) { sent++; } ts = ts->ts_next; } } } if (sent == 0) { /* no packets sent ? */ stat = RPC_CANTSEND; goto done_broad; } /* * Have sent all the packets. Now collect the responses... */ rcvd = 0; recv_again: msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.proc = xdr_void; readfds = mask; switch (select(dtbsize, &readfds, (fd_set *)NULL, (fd_set *)NULL, &rcv_timeout)) { case 0: /* Timed out */ /* * If we got at least one response in the * last interval, then don't wait for any * more. In theory we should wait for * the max weighting (penalty) value so * that a very slow server has a chance to * respond but this could take a long time * if the admin has set a high weighting * value. */ if (rcvd > 0) goto done_broad; stat = RPC_TIMEDOUT; continue; case -1: /* some kind of error */ if (errno == EINTR) goto recv_again; syslog(LOG_ERR, "nfscast: select: %m"); if (rcvd == 0) stat = RPC_CANTRECV; goto done_broad; } /* end of select results switch */ for (trans = tr_head; trans; trans = trans->tr_next) { if (FD_ISSET(trans->tr_fd, &readfds)) break; } if (trans == NULL) goto recv_again; try_again: t_rdata.addr = trans->tr_taddr->addr; t_rdata.udata.buf = inbuf; t_rdata.udata.maxlen = sizeof (inbuf); t_rdata.udata.len = 0; t_rdata.opt.len = 0; if (t_rcvudata(trans->tr_fd, &t_rdata, &flag) < 0) { if (errno == EINTR) goto try_again; syslog(LOG_ERR, "nfscast: t_rcvudata: %s:%m", trans->tr_device); stat = RPC_CANTRECV; continue; } if (t_rdata.udata.len < sizeof (ulong_t)) goto recv_again; if (flag & T_MORE) { syslog(LOG_ERR, "nfscast: t_rcvudata: %s: buffer overflow", trans->tr_device); goto recv_again; } /* * see if reply transaction id matches sent id. * If so, decode the results. * Note: received addr is ignored, it could be * different from the send addr if the host has * more than one addr. */ xdrmem_create(xdrs, inbuf, (uint_t)t_rdata.udata.len, XDR_DECODE); if (xdr_replymsg(xdrs, &msg)) { if (msg.rm_reply.rp_stat == MSG_ACCEPTED && (msg.rm_xid & ~0xFF) == xid) { struct addrs *curr_addr; i = msg.rm_xid & 0xFF; for (curr_addr = trans->tr_addrs; curr_addr; curr_addr = curr_addr->addr_next) { for (ts = curr_addr->addr_if_tstamps; ts; ts = ts->ts_next) if (ts->ts_inx == i && !ts->ts_rcvd) { ts->ts_rcvd = 1; calc_resp_time(&ts->ts_timeval); stat = RPC_SUCCESS; rcvd++; break; } } } /* otherwise, we just ignore the errors ... */ } xdrs->x_op = XDR_FREE; msg.acpted_rply.ar_results.proc = xdr_void; (void) xdr_replymsg(xdrs, &msg); XDR_DESTROY(xdrs); if (rcvd == sent) goto done_broad; else goto recv_again; } if (!rcvd) stat = RPC_TIMEDOUT; done_broad: if (rcvd) { *mfs_out = sort_responses(tr_head); stat = RPC_SUCCESS; } if (nc) endnetconfig(nc); free_transports(tr_head); AUTH_DESTROY(sys_auth); return (stat); }
/* * NFS stuff and unmount(2) call */ int umountfs(struct statfs *sfs) { char fsidbuf[64]; enum clnt_stat clnt_stat; struct timeval try; struct addrinfo *ai, hints; int do_rpc; CLIENT *clp; char *nfsdirname, *orignfsdirname; char *hostp, *delimp; ai = NULL; do_rpc = 0; hostp = NULL; nfsdirname = delimp = orignfsdirname = NULL; memset(&hints, 0, sizeof hints); if (strcmp(sfs->f_fstypename, "nfs") == 0) { if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL) err(1, "strdup"); orignfsdirname = nfsdirname; if (*nfsdirname == '[' && (delimp = strchr(nfsdirname + 1, ']')) != NULL && *(delimp + 1) == ':') { hostp = nfsdirname + 1; nfsdirname = delimp + 2; } else if ((delimp = strrchr(nfsdirname, ':')) != NULL) { hostp = nfsdirname; nfsdirname = delimp + 1; } if (hostp != NULL) { *delimp = '\0'; getaddrinfo(hostp, NULL, &hints, &ai); if (ai == NULL) { warnx("can't get net id for host"); } } /* * Check if we have to start the rpc-call later. * If there are still identical nfs-names mounted, * we skip the rpc-call. Obviously this has to * happen before unmount(2), but it should happen * after the previous namecheck. * A non-NULL return means that this is the last * mount from mntfromname that is still mounted. */ if (getmntentry(sfs->f_mntfromname, NULL, NULL, CHECKUNIQUE) != NULL) do_rpc = 1; } if (!namematch(ai)) { free(orignfsdirname); return (1); } /* First try to unmount using the file system ID. */ snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0], sfs->f_fsid.val[1]); if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) { /* XXX, non-root users get a zero fsid, so don't warn. */ if (errno != ENOENT || sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0) warn("unmount of %s failed", sfs->f_mntonname); if (errno != ENOENT) { free(orignfsdirname); return (1); } /* Compatibility for old kernels. */ if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0) warnx("retrying using path instead of file system ID"); if (unmount(sfs->f_mntonname, fflag) != 0) { warn("unmount of %s failed", sfs->f_mntonname); free(orignfsdirname); return (1); } } /* Mark this this file system as unmounted. */ getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE); if (vflag) (void)printf("%s: unmount from %s\n", sfs->f_mntfromname, sfs->f_mntonname); /* * Report to mountd-server which nfsname * has been unmounted. */ if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) { clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp"); if (clp == NULL) { warnx("%s: %s", hostp, clnt_spcreateerror("MOUNTPROG")); free(orignfsdirname); return (1); } clp->cl_auth = authsys_create_default(); try.tv_sec = 20; try.tv_usec = 0; clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir, nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try); if (clnt_stat != RPC_SUCCESS) { warnx("%s: %s", hostp, clnt_sperror(clp, "RPCMNT_UMOUNT")); free(orignfsdirname); return (1); } /* * Remove the unmounted entry from /var/db/mounttab. */ if (read_mtab()) { clean_mtab(hostp, nfsdirname, vflag); if(!write_mtab(vflag)) warnx("cannot remove mounttab entry %s:%s", hostp, nfsdirname); free_mtab(); } auth_destroy(clp->cl_auth); clnt_destroy(clp); }
int dotest(void) { CLIENT *client, *mountclient; AUTH *auth; struct timeval timeout; caddr_t args, res; enum clnt_stat status; rpcproc_t proc; call3_test_t *test; void *argbuf = NULL; void *resbuf = NULL; struct mountres3 mountres3; char *sp; volatile int a = 0; while (waiting(&a) == 0) continue; timeout.tv_sec = 30; timeout.tv_usec = 0; mountclient = clnt_create("localhost", MOUNTPROG, MOUNTVERS3, "tcp"); if (mountclient == NULL) { clnt_pcreateerror("clnt_create mount"); return (1); } auth = authsys_create_default(); mountclient->cl_auth = auth; sp = sharedpath; bzero(&mountres3, sizeof (mountres3)); status = clnt_call(mountclient, MOUNTPROC_MNT, xdr_dirpath, (char *)&sp, xdr_mountres3, (char *)&mountres3, timeout); if (status != RPC_SUCCESS) { clnt_perror(mountclient, "mnt"); return (1); } if (mountres3.fhs_status != 0) { fprintf(stderr, "MOUNTPROG/MOUNTVERS3 failed %d\n", mountres3.fhs_status); return (1); } rootfh = &mountres3.mountres3_u.mountinfo.fhandle; client = clnt_create("localhost", NFS3_PROGRAM, NFS_V3, "tcp"); if (client == NULL) { clnt_pcreateerror("clnt_create"); return (1); } client->cl_auth = auth; for (test = call3_tests; test->arginit; ++test) { argbuf = realloc(argbuf, test->argsize); resbuf = realloc(resbuf, test->ressize); if ((argbuf == NULL) || (resbuf == NULL)) { perror("realloc() failed"); return (1); } (test->arginit)(argbuf); bzero(resbuf, test->ressize); status = clnt_call(client, test->proc, test->xdrargs, argbuf, test->xdrres, resbuf, timeout); if (status != RPC_SUCCESS) clnt_perror(client, "call"); } status = clnt_call(mountclient, MOUNTPROC_UMNT, xdr_dirpath, (char *)&sp, xdr_void, NULL, timeout); if (status != RPC_SUCCESS) clnt_perror(mountclient, "umnt"); return (0); }