diff options
author | David E. O'Brien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
---|---|---|
committer | David E. O'Brien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
commit | ab38884b94958f20500a215ab38fe4a675d4c4f6 (patch) | |
tree | 60b090a6cbdb64326bb128ea49a231d08eb2680e /contrib/amd/amq/amq.c | |
download | src-ab38884b94958f20500a215ab38fe4a675d4c4f6.tar.gz src-ab38884b94958f20500a215ab38fe4a675d4c4f6.zip |
Virgin import of AMD (am-utils) v6.0a16vendor/amd/6.0a16
Notes
Notes:
svn path=/vendor/amd/dist/; revision=38494
svn path=/vendor/amd/6.0a16/; revision=38496; tag=vendor/amd/6.0a16
Diffstat (limited to 'contrib/amd/amq/amq.c')
-rw-r--r-- | contrib/amd/amq/amq.c | 938 |
1 files changed, 938 insertions, 0 deletions
diff --git a/contrib/amd/amq/amq.c b/contrib/amd/amq/amq.c new file mode 100644 index 000000000000..7fba9b1c0d1d --- /dev/null +++ b/contrib/amd/amq/amq.c @@ -0,0 +1,938 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR 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. + * + * %W% (Berkeley) %G% + * + * $Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $ + * + */ + +/* + * Automounter query tool + */ + +#ifndef lint +char copyright[] = "\ +@(#)Copyright (c) 1997-1998 Erez Zadok\n\ +@(#)Copyright (c) 1990 Jan-Simon Pendry\n\ +@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\ +@(#)Copyright (c) 1990 The Regents of the University of California.\n\ +@(#)All rights reserved.\n"; +#if __GNUC__ < 2 +static char rcsid[] = "$Id: amq.c,v 6.0 1997-1998/01/01 15:09:16 ezk $"; +static char sccsid[] = "%W% (Berkeley) %G%"; +#endif /* __GNUC__ < 2 */ +#endif /* not lint */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amq.h> + +/* locals */ +char *progname; +static int flush_flag; +static int minfo_flag; +static int getpid_flag; +static int unmount_flag; +static int stats_flag; +static int getvers_flag; +static int amd_program_number = AMQ_PROGRAM; +static int use_tcp_flag, use_udp_flag; +static char *debug_opts; +static char *amq_logfile; +static char *mount_map; +static char *xlog_optstr; +static char localhost[] = "localhost"; +static char *def_server = localhost; + +/* externals */ +extern int optind; +extern char *optarg; + +/* forward decalrations */ +#ifdef HAVE_TRANSPORT_TYPE_TLI +static CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock); +static int amq_bind_resv_port(int td, u_short *pp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ +static int privsock(int ty); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + +/* dummy variables */ +char hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + +/* structures */ +enum show_opt { + Full, Stats, Calc, Short, ShowDone +}; + + +/* + * If (e) is Calc then just calculate the sizes + * Otherwise display the mount node on stdout + */ +static void +show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid) +{ + switch (e) { + case Calc: + { + int mw = strlen(mt->mt_mountinfo); + int dw = strlen(mt->mt_directory); + int tw = strlen(mt->mt_type); + if (mw > *mwid) + *mwid = mw; + if (dw > *dwid) + *dwid = dw; + if (tw > *twid) + *twid = tw; + } + break; + + case Full: + { + struct tm *tp = localtime((time_t *) &mt->mt_mounttime); + printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", + *dwid, *dwid, + *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ + *twid, *twid, + mt->mt_type, + *mwid, *mwid, + mt->mt_mountinfo, + mt->mt_mountpoint, + + mt->mt_mountuid, + mt->mt_getattr, + mt->mt_lookup, + mt->mt_readdir, + mt->mt_readlink, + mt->mt_statfs, + + tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, + tp->tm_mon + 1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); + } + break; + + case Stats: + { + struct tm *tp = localtime((time_t *) &mt->mt_mounttime); + printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", + *dwid, *dwid, + *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ + + mt->mt_mountuid, + mt->mt_getattr, + mt->mt_lookup, + mt->mt_readdir, + mt->mt_readlink, + mt->mt_statfs, + + tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, + tp->tm_mon + 1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); + } + break; + + case Short: + { + printf("%-*.*s %-*.*s %-*.*s %s\n", + *dwid, *dwid, + *mt->mt_directory ? mt->mt_directory : "/", + *twid, *twid, + mt->mt_type, + *mwid, *mwid, + mt->mt_mountinfo, + mt->mt_mountpoint); + } + break; + + default: + break; + } +} + +/* + * Display a mount tree. + */ +static void +show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid) +{ + while (mt) { + show_mti(mt, e, mwid, dwid, pwid); + show_mt(mt->mt_next, e, mwid, dwid, pwid); + mt = mt->mt_child; + } +} + +static void +show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid) +{ + int i; + + switch (e) { + + case Calc: + { + for (i = 0; i < ml->amq_mount_info_list_len; i++) { + amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; + int mw = strlen(mi->mi_mountinfo); + int dw = strlen(mi->mi_mountpt); + int tw = strlen(mi->mi_type); + if (mw > *mwid) + *mwid = mw; + if (dw > *dwid) + *dwid = dw; + if (tw > *twid) + *twid = tw; + } + } + break; + + case Full: + { + for (i = 0; i < ml->amq_mount_info_list_len; i++) { + amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; + printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s", + *mwid, *mwid, mi->mi_mountinfo, + *dwid, *dwid, mi->mi_mountpt, + *twid, *twid, mi->mi_type, + mi->mi_refc, mi->mi_fserver, + mi->mi_up > 0 ? "up" : + mi->mi_up < 0 ? "starting" : "down"); + if (mi->mi_error > 0) { + extern int sys_nerr; + if (mi->mi_error < sys_nerr) + printf(" (%s)", sys_errlist[mi->mi_error]); + else + printf(" (Error %d)", mi->mi_error); + } else if (mi->mi_error < 0) { + fputs(" (in progress)", stdout); + } + fputc('\n', stdout); + } + } + break; + + default: + break; + } +} + + +/* + * Display general mount statistics + */ +static void +show_ms(amq_mount_stats *ms) +{ + printf("\ +requests stale mount mount unmount\n\ +deferred fhandles ok failed failed\n\ +%-9d %-9d %-9d %-9d %-9d\n", + ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr); +} + + +#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) +static char * +cluster_server(void) +{ + struct cct_entry *cp; + + if (cnodeid() == 0) { + /* + * Not clustered + */ + return def_server; + } + while (cp = getccent()) + if (cp->cnode_type == 'r') + return cp->cnode_name; + + return def_server; +} +#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ + + +/* + * MAIN + */ +int +main(int argc, char *argv[]) +{ + int opt_ch; + int errs = 0; + char *server; + struct sockaddr_in server_addr; + int s; /* to pass the Amd security check, we must use a priv port */ + CLIENT *clnt = NULL; + struct hostent *hp; + int nodefault = 0; + struct timeval tv; +#ifndef HAVE_TRANSPORT_TYPE_TLI + enum clnt_stat cs; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + + /* + * Compute program name + */ + if (argv[0]) { + progname = strrchr(argv[0], '/'); + if (progname && progname[1]) + progname++; + else + progname = argv[0]; + } + if (!progname) + progname = "amq"; + + /* + * Parse arguments + */ + while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != EOF) + switch (opt_ch) { + case 'f': + flush_flag = 1; + nodefault = 1; + break; + + case 'h': + def_server = optarg; + break; + + case 'l': + amq_logfile = optarg; + nodefault = 1; + break; + + case 'm': + minfo_flag = 1; + nodefault = 1; + break; + + case 'p': + getpid_flag = 1; + nodefault = 1; + break; + + case 's': + stats_flag = 1; + nodefault = 1; + break; + + case 'u': + unmount_flag = 1; + nodefault = 1; + break; + + case 'v': + getvers_flag = 1; + nodefault = 1; + break; + + case 'x': + xlog_optstr = optarg; + nodefault = 1; + break; + + case 'D': + debug_opts = optarg; + nodefault = 1; + break; + + case 'M': + mount_map = optarg; + nodefault = 1; + break; + + case 'P': + amd_program_number = atoi(optarg); + break; + + case 'T': + use_tcp_flag = 1; + break; + + case 'U': + use_udp_flag = 1; + break; + + default: + errs = 1; + break; + } + + if (optind == argc) { + if (unmount_flag) + errs = 1; + } + if (errs) { + show_usage: + fprintf(stderr, "\ +Usage: %s [-h host] [[-f] [-m] [-p] [-v] [-s]] | [[-u] directory ...]]\n\ +\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n\ +\t[-P prognum] [-T] [-U]\n", progname); + exit(1); + } + + /* set use_udp and use_tcp flags both to on if none are defined */ + if (!use_tcp_flag && !use_udp_flag) + use_tcp_flag = use_udp_flag = 1; + +#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) + /* + * Figure out root server of cluster + */ + if (def_server == localhost) + server = cluster_server(); + else +#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ + server = def_server; + + /* + * Get address of server + */ + if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) { + fprintf(stderr, "%s: Can't get address of %s\n", progname, server); + exit(1); + } + memset(&server_addr, 0, sizeof server_addr); + server_addr.sin_family = AF_INET; + if (hp) { + memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr, + sizeof(server_addr.sin_addr)); + } else { + /* fake "localhost" */ + server_addr.sin_addr.s_addr = htonl(0x7f000001); + } + + /* + * Create RPC endpoint + */ + tv.tv_sec = 5; /* 5 seconds for timeout or per retry */ + tv.tv_usec = 0; + +#ifdef HAVE_TRANSPORT_TYPE_TLI + clnt = get_secure_amd_client(server, &tv, &s); + if (!clnt && use_tcp_flag) /* try tcp first */ + clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp"); + if (!clnt && use_udp_flag) { /* try udp next */ + clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp"); + /* if ok, set timeout (valid for connectionless transports only) */ + if (clnt) + clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv); + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* first check if remote portmapper is up */ + cs = pmap_ping(&server_addr); + if (cs == RPC_TIMEDOUT) { + fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", + progname, server, clnt_sperrno(cs)); + exit(1); + } + + /* portmapper exists: get remote amd info from it */ + if (!clnt && use_tcp_flag) { /* try tcp first */ + s = RPC_ANYSOCK; + clnt = clnttcp_create(&server_addr, amd_program_number, + AMQ_VERSION, &s, 0, 0); + } + if (!clnt && use_udp_flag) { /* try udp next */ + /* XXX: do we need to close(s) ? */ + s = privsock(SOCK_DGRAM); + clnt = clntudp_create(&server_addr, amd_program_number, + AMQ_VERSION, tv, &s); + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (!clnt) { + fprintf(stderr, "%s: ", progname); + clnt_pcreateerror(server); + exit(1); + } + + /* + * Control debugging + */ + if (debug_opts) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_DEBUG; + opt.as_str = debug_opts; + rc = amqproc_setopt_1(&opt, clnt); + if (rc && *rc < 0) { + fprintf(stderr, "%s: daemon not compiled for debug\n", progname); + errs = 1; + } else if (!rc || *rc > 0) { + fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts); + errs = 1; + } + } + + /* + * Control logging + */ + if (xlog_optstr) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_XLOG; + opt.as_str = xlog_optstr; + rc = amqproc_setopt_1(&opt, clnt); + if (!rc || *rc) { + fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr); + errs = 1; + } + } + + /* + * Control log file + */ + if (amq_logfile) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_LOGFILE; + opt.as_str = amq_logfile; + rc = amqproc_setopt_1(&opt, clnt); + if (!rc || *rc) { + fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, amq_logfile); + errs = 1; + } + } + + /* + * Flush map cache + */ + if (flush_flag) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_FLUSHMAPC; + opt.as_str = ""; + rc = amqproc_setopt_1(&opt, clnt); + if (!rc || *rc) { + fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server); + errs = 1; + } + } + + /* + * Mount info + */ + if (minfo_flag) { + int dummy; + amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); + if (ml) { + int mwid = 0, dwid = 0, twid = 0; + show_mi(ml, Calc, &mwid, &dwid, &twid); + mwid++; + dwid++; + twid++; + show_mi(ml, Full, &mwid, &dwid, &twid); + + } else { + fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server); + } + } + + /* + * Mount map + */ + if (mount_map) { + int *rc; + do { + rc = amqproc_mount_1(&mount_map, clnt); + } while (rc && *rc < 0); + if (!rc || *rc > 0) { + if (rc) + errno = *rc; + else + errno = ETIMEDOUT; + fprintf(stderr, "%s: could not start new ", progname); + perror("autmount point"); + } + } + + /* + * Get Version + */ + if (getvers_flag) { + amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); + if (spp && *spp) { + fputs(*spp, stdout); + XFREE(*spp); + } else { + fprintf(stderr, "%s: failed to get version information\n", progname); + errs = 1; + } + } + + /* + * Get PID of amd + */ + if (getpid_flag) { + int *ip = amqproc_getpid_1((voidp) 0, clnt); + if (ip && *ip) { + printf("%d\n", *ip); + } else { + fprintf(stderr, "%s: failed to get PID of amd\n", progname); + errs = 1; + } + } + + /* + * Apply required operation to all remaining arguments + */ + if (optind < argc) { + do { + char *fs = argv[optind++]; + if (unmount_flag) { + /* + * Unmount request + */ + amqproc_umnt_1(&fs, clnt); + } else { + /* + * Stats request + */ + amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); + if (mtp) { + amq_mount_tree *mt = *mtp; + if (mt) { + int mwid = 0, dwid = 0, twid = 0; + show_mt(mt, Calc, &mwid, &dwid, &twid); + mwid++; + dwid++, twid++; + printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", + dwid, dwid, "What"); + show_mt(mt, Stats, &mwid, &dwid, &twid); + } else { + fprintf(stderr, "%s: %s not automounted\n", progname, fs); + } + xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp); + } else { + fprintf(stderr, "%s: ", progname); + clnt_perror(clnt, server); + errs = 1; + } + } + } while (optind < argc); + + } else if (unmount_flag) { + goto show_usage; + + } else if (stats_flag) { + amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); + if (ms) { + show_ms(ms); + } else { + fprintf(stderr, "%s: ", progname); + clnt_perror(clnt, server); + errs = 1; + } + + } else if (!nodefault) { + amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); + if (mlp) { + enum show_opt e = Calc; + int mwid = 0, dwid = 0, pwid = 0; + while (e != ShowDone) { + int i; + for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { + show_mt(mlp->amq_mount_tree_list_val[i], + e, &mwid, &dwid, &pwid); + } + mwid++; + dwid++, pwid++; + if (e == Calc) + e = Short; + else if (e == Short) + e = ShowDone; + } + + } else { + fprintf(stderr, "%s: ", progname); + clnt_perror(clnt, server); + errs = 1; + } + } + exit(errs); + return errs; /* should never reache here */ +} + + +#ifdef HAVE_TRANSPORT_TYPE_TLI + +/* + * How to bind to reserved ports. + * TLI handle (socket) and port version. + */ +/* defined here so that it does not have to resolve it with libamu.a */ +static int +amq_bind_resv_port(int td, u_short *pp) +{ + int rc = -1, port; + struct t_bind *treq, *tret; + struct sockaddr_in *sin; + + treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); + if (!treq) { + plog(XLOG_ERROR, "t_alloc 1"); + return -1; + } + tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); + if (!tret) { + t_free((char *) treq, T_BIND); + plog(XLOG_ERROR, "t_alloc 2"); + return -1; + } + memset((char *) treq->addr.buf, 0, treq->addr.len); + sin = (struct sockaddr_in *) treq->addr.buf; + sin->sin_family = AF_INET; + treq->qlen = 0; + treq->addr.len = treq->addr.maxlen; + errno = EADDRINUSE; + port = IPPORT_RESERVED; + + do { + --port; + sin->sin_port = htons(port); + rc = t_bind(td, treq, tret); + if (rc < 0) { + } else { + if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0) + break; + else + t_unbind(td); + } + } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2); + + if (pp) { + if (rc == 0) + *pp = port; + else + plog(XLOG_ERROR, "could not t_bind to any reserved port"); + } + t_free((char *) tret, T_BIND); + t_free((char *) treq, T_BIND); + return rc; +} + + +/* + * Create a secure rpc client attached to the amd daemon. + */ +static CLIENT * +get_secure_amd_client(char *host, struct timeval *tv, int *sock) +{ + CLIENT *client; + struct netbuf nb; + struct netconfig *nc, *pm_nc; + struct sockaddr_in sin; + + + nb.maxlen = sizeof(sin); + nb.buf = (char *) &sin; + + /* + * Ensure that remote portmapper is alive + * (must use connectionless netconfig). + */ + if ((pm_nc = getnetconfigent(NC_UDP)) != NULL) { + enum clnt_stat cs; + + cs = rpcb_rmtcall(pm_nc, + host, + amd_program_number, + AMQ_VERSION, + AMQPROC_NULL, + (XDRPROC_T_TYPE) xdr_void, + NULL, + (XDRPROC_T_TYPE) xdr_void, + NULL, + *tv, + NULL); + if (cs == RPC_TIMEDOUT) { + fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", + progname, host, clnt_sperrno(cs)); + exit(1); + } + } + + /* + * First transport type to try: TCP + */ + if (use_tcp_flag) { + /* Find amd address on TCP */ + nc = getnetconfigent(NC_TCP); + if (!nc) { + fprintf(stderr, "getnetconfig for tcp failed: %s\n", nc_sperror()); + goto tryudp; + } + + if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { + /* + * don't pring error messages here, since amd might legitimately + * serve udp only + */ + goto tryudp; + } + /* Create priviledged TCP socket */ + *sock = t_open(nc->nc_device, O_RDWR, 0); + + if (*sock < 0) { + fprintf(stderr, "t_open %s: %m\n", nc->nc_device); + goto tryudp; + } + if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) + goto tryudp; + + client = clnt_vc_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); + if (!client) { + fprintf(stderr, "clnt_vc_create failed"); + t_close(*sock); + goto tryudp; + } + /* tcp succeeded */ + return client; + } + +tryudp: + /* + * TCP failed so try UDP + */ + if (use_udp_flag) { + /* find amd address on UDP */ + nc = getnetconfigent(NC_UDP); + if (!nc) { + fprintf(stderr, "getnetconfig for udp failed: %s\n", nc_sperror()); + return NULL; + } + if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { + fprintf(stderr, "%s\n", + clnt_spcreateerror("couldn't get amd address on udp")); + return NULL; + } + /* create priviledged UDP socket */ + *sock = t_open(nc->nc_device, O_RDWR, 0); + + if (*sock < 0) { + fprintf(stderr, "t_open %s: %m\n", nc->nc_device); + return NULL; /* neither tcp not udp succeeded */ + } + if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) + return NULL; + + client = clnt_dg_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); + if (!client) { + fprintf(stderr, "clnt_dg_create failed\n"); + t_close(*sock); + return NULL; /* neither tcp not udp succeeded */ + } + if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) { + fprintf(stderr, "clnt_control CLSET_RETRY_TIMEOUT for udp failed\n"); + clnt_destroy(client); + return NULL; /* neither tcp not udp succeeded */ + } + /* udp succeeded */ + return client; + } + + /* should never get here */ + return NULL; +} + +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + +/* + * inetresport creates a datagram socket and attempts to bind it to a + * secure port. + * returns: The bound socket, or -1 to indicate an error. + */ +static int +inetresport(int ty) +{ + int alport; + struct sockaddr_in addr; + int fd; + + /* Use internet address family */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if ((fd = socket(AF_INET, ty, 0)) < 0) + return -1; + + for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { + addr.sin_port = htons((u_short) alport); + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) + return fd; + if (errno != EADDRINUSE) { + close(fd); + return -1; + } + } + close(fd); + errno = EAGAIN; + return -1; +} + + +/* + * Privsock() calls inetresport() to attempt to bind a socket to a secure + * port. If inetresport() fails, privsock returns a magic socket number which + * indicates to RPC that it should make its own socket. + * returns: A privileged socket # or RPC_ANYSOCK. + */ +static int +privsock(int ty) +{ + int sock = inetresport(ty); + + if (sock < 0) { + errno = 0; + /* Couldn't get a secure port, let RPC make an insecure one */ + sock = RPC_ANYSOCK; + } + return sock; +} + +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ |