diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/rpcsvc/rusers.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/rpcsvc/rusers.c')
-rw-r--r-- | usr/src/cmd/rpcsvc/rusers.c | 652 |
1 files changed, 652 insertions, 0 deletions
diff --git a/usr/src/cmd/rpcsvc/rusers.c b/usr/src/cmd/rpcsvc/rusers.c new file mode 100644 index 0000000000..9ab0f7ae0f --- /dev/null +++ b/usr/src/cmd/rpcsvc/rusers.c @@ -0,0 +1,652 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <netconfig.h> +#include <netdir.h> +#include <rpc/rpc.h> +#include <rpcsvc/rusers.h> +#include <string.h> +#include <limits.h> + +#define NMAX 12 /* These are used as field width specifiers */ +#define LMAX 8 /* when printing. */ +#define HMAX 16 /* "Logged in" host name. */ + +#define MACHINELEN 16 /* length of machine name printed out */ +#define NUMENTRIES 256 +#define min(a, b) ((a) < (b) ? (a) : (b)) + +struct entry { + int cnt; + int idle; /* set to INT_MAX if not present */ + char *machine; + utmp_array users; +}; + +static int curentry; +static int total_entries; +static struct entry *entry; +static int hflag; /* host: sort by machine name */ +static int iflag; /* idle: sort by idle time */ +static int uflag; /* users: sort by number of users */ +static int lflag; /* print out long form */ +static int aflag; /* all: list all machines */ +static int dflag; /* debug: list only first n machines */ +static int sorted; +static int debug; +static int debugcnt; +static char *nettype; + +static int hcompare(const struct entry *, const struct entry *); +static int icompare(const struct entry *, const struct entry *); +static int ucompare(const struct entry *, const struct entry *); +static int print_info(struct utmpidlearr *, const char *); +static int print_info_3(utmp_array *, const char *); +static int collectnames(void *, struct netbuf *, struct netconfig *); +static int collectnames_3(void *, struct netbuf *, struct netconfig *); +static void singlehost(char *); +static void printnames(void); +static void putline_2(char *, struct utmpidle *); +static void putline_3(char *, rusers_utmp *); +static void prttime(uint_t, char *); +static void usage(void); + +/* + * rusers [-ahilu] [host...] + */ +int +main(int argc, char *argv[]) +{ + int c; + uint_t errflag = 0; + uint_t single = 0; + struct utmpidlearr utmpidlearr; + utmp_array utmp_array_res; + + curentry = 0; + total_entries = NUMENTRIES; + entry = malloc(sizeof (struct entry) * total_entries); + + while ((c = getopt(argc, argv, ":ad:hilun:")) != -1) { + switch (c) { + case 'a': + aflag++; + break; + case 'd': + dflag++; + debug = atoi(optarg); + (void) printf("Will collect %d responses.\n", debug); + break; + case 'h': + hflag++; + sorted++; + if (iflag || uflag) + errflag++; + break; + case 'i': + iflag++; + sorted++; + if (hflag || uflag) + errflag++; + break; + case 'u': + uflag++; + sorted++; + if (hflag || iflag) + errflag++; + break; + case 'l': + lflag++; + break; + case ':': /* required operand missing */ + errflag++; + break; + case 'n': + nettype = optarg; + break; + default: + case '?': /* Unrecognized option */ + errflag++; + break; + } + } + if (errflag) + usage(); + + for (; optind < argc; optind++) { + single++; + singlehost(argv[optind]); + } + if (single) { + if (sorted) + printnames(); + free(entry); + exit(0); + } + + if (sorted) { + (void) printf("Collecting responses...\n"); + (void) fflush(stdout); + } + utmp_array_res.utmp_array_val = NULL; + utmp_array_res.utmp_array_len = 0; + (void) printf("Sending broadcast for rusersd protocol version 3...\n"); + (void) rpc_broadcast(RUSERSPROG, RUSERSVERS_3, + RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_utmp_array, (char *)&utmp_array_res, + (resultproc_t)collectnames_3, nettype); + utmpidlearr.uia_arr = NULL; + (void) printf("Sending broadcast for rusersd protocol version 2...\n"); + (void) rpc_broadcast(RUSERSPROG, RUSERSVERS_IDLE, + RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_utmpidlearr, (char *)&utmpidlearr, + (resultproc_t)collectnames, nettype); + + if (sorted) + printnames(); + + free(entry); + return (0); +} + +static void +singlehost(char *name) +{ + enum clnt_stat err; + struct utmpidlearr utmpidlearr; + utmp_array utmp_array_res; + + if (curentry >= total_entries) { + struct entry *tmp; + + total_entries += NUMENTRIES; + if ((tmp = realloc(entry, sizeof (struct entry) + * total_entries)) == NULL) + return; + entry = tmp; + } + utmp_array_res.utmp_array_val = NULL; + utmp_array_res.utmp_array_len = 0; + err = rpc_call(name, RUSERSPROG, RUSERSVERS_3, + RUSERSPROC_NAMES, (xdrproc_t)xdr_void, 0, + (xdrproc_t)xdr_utmp_array, (char *)&utmp_array_res, + nettype); + if (err == RPC_SUCCESS) { + (void) print_info_3(&utmp_array_res, name); + return; + } + if (err == RPC_PROGVERSMISMATCH) { + utmpidlearr.uia_arr = NULL; + err = rpc_call(name, RUSERSPROG, RUSERSVERS_IDLE, + RUSERSPROC_NAMES, (xdrproc_t)xdr_void, 0, + (xdrproc_t)xdr_utmpidlearr, + (char *)&utmpidlearr, nettype); + } + if (err != RPC_SUCCESS) { + (void) fprintf(stderr, "%s: ", name); + clnt_perrno(err); + return; + } + (void) print_info(&utmpidlearr, name); +} + +/* + * Collect responses from RUSERSVERS_IDLE broadcast, convert to + * RUSERSVERS_3 format, and store in entry database. + */ +static int +collectnames(void *resultsp, struct netbuf *raddrp, struct netconfig *nconf) +{ + struct utmpidlearr utmpidlearr; + struct entry *entryp, *lim; + struct nd_hostservlist *hs; + char host[MACHINELEN + 1]; + + utmpidlearr = *(struct utmpidlearr *)resultsp; + if (utmpidlearr.uia_cnt < 1 && !aflag) + return (0); + + if (netdir_getbyaddr(nconf, &hs, raddrp)) { +#ifdef DEBUG + netdir_perror("netdir_getbyaddr"); +#endif + /* netdir routine couldn't resolve addr;just print out uaddr */ + (void) sprintf(host, "%.*s", MACHINELEN, + taddr2uaddr(nconf, raddrp)); + } else { + (void) sprintf(host, "%.*s", MACHINELEN, + hs->h_hostservs->h_host); + netdir_free((char *)hs, ND_HOSTSERVLIST); + } + /* + * need to realloc more space if we have more than 256 machines + * that respond to broadcast + */ + if (curentry >= total_entries) { + struct entry *tmp; + + total_entries += NUMENTRIES; + if ((tmp = realloc(entry, sizeof (struct entry) + * total_entries)) == NULL) + return (1); + entry = tmp; + } + + + /* + * weed out duplicates + */ + lim = entry + curentry; + for (entryp = entry; entryp < lim; entryp++) { + if (strcmp(entryp->machine, host) == 0) + return (0); + } + return (print_info((struct utmpidlearr *)resultsp, host)); +} + +static int +print_info(struct utmpidlearr *utmpidlearrp, const char *name) +{ + utmp_array *iconvert; + int i, cnt, minidle; + char host[MACHINELEN + 1]; + char username[NMAX + 1]; + + cnt = utmpidlearrp->uia_cnt; + (void) sprintf(host, "%.*s", MACHINELEN, name); + + /* + * if raw, print this entry out immediately + * otherwise store for later sorting + */ + if (!sorted) { + if (lflag && (cnt > 0)) + for (i = 0; i < cnt; i++) + putline_2(host, utmpidlearrp->uia_arr[i]); + else { + (void) printf("%-*.*s", MACHINELEN, MACHINELEN, host); + for (i = 0; i < cnt; i++) { + (void) strlcpy(username, + utmpidlearrp->uia_arr[i]->ui_utmp.ut_name, + NMAX + 1); + (void) printf(" %.*s", NMAX, username); + } + (void) printf("\n"); + } + /* store just the name */ + entry[curentry].machine = malloc(MACHINELEN + 1); + if (entry[curentry].machine == NULL) { + (void) fprintf(stderr, "Ran out of memory - exiting\n"); + exit(1); + } + (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1); + entry[curentry++].cnt = 0; + if (dflag && (++debugcnt >= debug)) + return (1); + return (0); + } + entry[curentry].machine = malloc(MACHINELEN + 1); + if (entry[curentry].machine == NULL) { + (void) fprintf(stderr, "Ran out of memory - exiting\n"); + exit(1); + } + (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1); + entry[curentry].cnt = cnt; + iconvert = &entry[curentry].users; + iconvert->utmp_array_len = cnt; + iconvert->utmp_array_val = malloc(cnt * sizeof (rusers_utmp)); + minidle = INT_MAX; + for (i = 0; i < cnt; i++) { + iconvert->utmp_array_val[i].ut_user = + strdup(utmpidlearrp->uia_arr[i]->ui_utmp.ut_name); + iconvert->utmp_array_val[i].ut_line = + strdup(utmpidlearrp->uia_arr[i]->ui_utmp.ut_line); + iconvert->utmp_array_val[i].ut_host = + strdup(utmpidlearrp->uia_arr[i]->ui_utmp.ut_host); + iconvert->utmp_array_val[i].ut_time = + utmpidlearrp->uia_arr[i]->ui_utmp.ut_time; + iconvert->utmp_array_val[i].ut_idle = + utmpidlearrp->uia_arr[i]->ui_idle; + minidle = min(minidle, utmpidlearrp->uia_arr[i]->ui_idle); + } + entry[curentry].idle = minidle; + curentry++; + if (dflag && (++debugcnt >= debug)) + return (1); + return (0); +} + + +/* + * Collect responses from RUSERSVERS_3 broadcast. + */ +static int +collectnames_3(void *resultsp, struct netbuf *raddrp, struct netconfig *nconf) +{ + utmp_array *uap; + struct entry *entryp, *lim; + struct nd_hostservlist *hs; + char host[MACHINELEN + 1]; + + uap = (utmp_array *)resultsp; + if (uap->utmp_array_len < 1 && !aflag) + return (0); + + if (netdir_getbyaddr(nconf, &hs, raddrp)) { +#ifdef DEBUG + netdir_perror("netdir_getbyaddr"); +#endif + /* netdir routine couldn't resolve addr;just print out uaddr */ + (void) sprintf(host, "%.*s", MACHINELEN, + taddr2uaddr(nconf, raddrp)); + } else { + (void) sprintf(host, "%.*s", MACHINELEN, + hs->h_hostservs->h_host); + netdir_free((char *)hs, ND_HOSTSERVLIST); + } + + /* + * need to realloc more space if we have more than 256 machines + * that respond to broadcast + */ + if (curentry >= total_entries) { + struct entry *tmp; + + total_entries += NUMENTRIES; + if ((tmp = realloc(entry, sizeof (struct entry) + * total_entries)) == NULL) + return (1); + entry = tmp; + } + + + /* + * weed out duplicates + */ + lim = entry + curentry; + for (entryp = entry; entryp < lim; entryp++) { + if (strcmp(entryp->machine, host) == 0) + return (0); + } + return (print_info_3(uap, host)); +} + +static int +print_info_3(utmp_array *uap, const char *name) +{ + int i, cnt, minidle; + char host[MACHINELEN + 1]; + + cnt = uap->utmp_array_len; + + (void) sprintf(host, "%.*s", MACHINELEN, name); + + /* + * if raw, print this entry out immediately + * otherwise store for later sorting + */ + if (!sorted) { + if (lflag && (cnt > 0)) + for (i = 0; i < cnt; i++) + putline_3(host, &uap->utmp_array_val[i]); + else { + (void) printf("%-*.*s", MACHINELEN, MACHINELEN, host); + for (i = 0; i < cnt; i++) + (void) printf(" %.*s", NMAX, + uap->utmp_array_val[i].ut_user); + (void) printf("\n"); + } + /* store just the name */ + entry[curentry].machine = malloc(MACHINELEN + 1); + if (entry[curentry].machine == NULL) { + (void) fprintf(stderr, "Ran out of memory - exiting\n"); + exit(1); + } + (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1); + entry[curentry++].cnt = 0; + if (dflag && (++debugcnt >= debug)) + return (1); + return (0); + } + + entry[curentry].machine = malloc(MACHINELEN + 1); + if (entry[curentry].machine == NULL) { + (void) fprintf(stderr, "Ran out of memory - exiting\n"); + exit(1); + } + (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1); + entry[curentry].cnt = cnt; + entry[curentry].users.utmp_array_len = cnt; + entry[curentry].users.utmp_array_val = malloc(cnt * + sizeof (rusers_utmp)); + minidle = INT_MAX; + for (i = 0; i < cnt; i++) { + entry[curentry].users.utmp_array_val[i].ut_user = + strdup(uap->utmp_array_val[i].ut_user); + entry[curentry].users.utmp_array_val[i].ut_line = + strdup(uap->utmp_array_val[i].ut_line); + entry[curentry].users.utmp_array_val[i].ut_host = + strdup(uap->utmp_array_val[i].ut_host); + entry[curentry].users.utmp_array_val[i].ut_time = + uap->utmp_array_val[i].ut_time; + entry[curentry].users.utmp_array_val[i].ut_idle = + uap->utmp_array_val[i].ut_idle; + minidle = min(minidle, uap->utmp_array_val[i].ut_idle); + } + entry[curentry].idle = minidle; + curentry++; + if (dflag && (++debugcnt >= debug)) + return (1); + return (0); +} + +static void +printnames(void) +{ + int i, j; + int (*compare)(const void *, const void *); + + /* the name of the machine should already be in the structure */ + if (iflag) + compare = (int (*)(const void *, const void *))icompare; + else if (hflag) + compare = (int (*)(const void *, const void *))hcompare; + else + compare = (int (*)(const void *, const void *))ucompare; + qsort(entry, curentry, sizeof (struct entry), compare); + for (i = 0; i < curentry; i++) { + if (!lflag || (entry[i].cnt < 1)) { + (void) printf("%-*.*s", MACHINELEN, + MACHINELEN, entry[i].machine); + for (j = 0; j < entry[i].cnt; j++) + (void) printf(" %.*s", NMAX, + entry[i].users.utmp_array_val[j].ut_user); + (void) printf("\n"); + } else { + for (j = 0; j < entry[i].cnt; j++) + putline_3(entry[i].machine, + &entry[i].users.utmp_array_val[j]); + } + } +} + +static int +hcompare(const struct entry *a, const struct entry *b) +{ + return (strcmp(a->machine, b->machine)); +} + +static int +ucompare(const struct entry *a, const struct entry *b) +{ + return (b->cnt - a->cnt); +} + +static int +icompare(const struct entry *a, const struct entry *b) +{ + return (a->idle - b->idle); +} + +static void +putline_2(char *host, struct utmpidle *uip) +{ + char *cbuf; + struct ru_utmp *up; + char buf[100]; + + up = &uip->ui_utmp; +#define NAMEMAX ((sizeof (up->ut_name) < NMAX) ? NMAX : sizeof (up->ut_name)) +#define NAMEMIN ((sizeof (up->ut_name) > NMAX) ? NMAX : sizeof (up->ut_name)) + /* Try and align this up nicely */ +#define LINEMAX sizeof (up->ut_line) +#define HOSTMAX sizeof (up->ut_host) + /* + * We copy the strings into a buffer because they aren't strictly + * speaking strings but byte arrays (and they may not have a + * terminating NULL. + */ + + (void) strncpy(buf, up->ut_name, NAMEMAX); + buf[NAMEMIN] = '\0'; + (void) printf("%-*.*s ", NAMEMAX, NAMEMAX, buf); + + (void) strcpy(buf, host); + (void) strcat(buf, ":"); + (void) strncat(buf, up->ut_line, LINEMAX); + buf[MACHINELEN+LINEMAX] = '\0'; + (void) printf("%-*.*s", MACHINELEN+LINEMAX, MACHINELEN+LINEMAX, buf); + + cbuf = (char *)ctime(&up->ut_time); + (void) printf(" %.12s ", cbuf+4); + if (uip->ui_idle == INT_MAX) + (void) printf(" ??"); + else + prttime(uip->ui_idle, ""); + if (up->ut_host[0]) { + (void) strncpy(buf, up->ut_host, HOSTMAX); + buf[HOSTMAX] = '\0'; + (void) printf(" (%.*s)", HOSTMAX, buf); + } + (void) putchar('\n'); +} + +static void +putline_3(char *host, rusers_utmp *rup) +{ + char *cbuf; + char buf[100]; + + (void) printf("%-*.*s ", NMAX, NMAX, rup->ut_user); + (void) strcpy(buf, host); + (void) strcat(buf, ":"); + (void) strncat(buf, rup->ut_line, LMAX); + (void) printf("%-*.*s", MACHINELEN+LMAX, MACHINELEN+LMAX, buf); + + cbuf = (char *)ctime((time_t *)&rup->ut_time); + (void) printf(" %.12s ", cbuf+4); + if (rup->ut_idle == INT_MAX) + (void) printf(" ??"); + else + prttime(rup->ut_idle, ""); + if (rup->ut_host[0]) + (void) printf(" (%.*s)", HMAX, rup->ut_host); + (void) putchar('\n'); +} + +/* + * prttime prints a time in hours and minutes. + * The character string tail is printed at the end, obvious + * strings to pass are "", " ", or "am". + */ +static void +prttime(uint_t tim, char *tail) +{ + int didhrs = 0; + + if (tim >= 60) { + (void) printf("%3d:", tim/60); + didhrs++; + } else { + (void) printf(" "); + } + tim %= 60; + if (tim > 0 || didhrs) { + (void) printf(didhrs && tim < 10 ? "%02d" : "%2d", tim); + } else { + (void) printf(" "); + } + (void) printf("%s", tail); +} + +#ifdef DEBUG +/* + * for debugging + */ +int +printit(int i) +{ + int j, v; + + (void) printf("%12.12s: ", entry[i].machine); + if (entry[i].cnt) { + putline_3(entry[i].machine, &entry[i].users.utmp_array_val[0]); + for (j = 1; j < entry[i].cnt; j++) { + (void) printf("\t"); + putline_3(entry[i].machine, + &entry[i].users.utmp_array_val[j]); + } + } else + (void) printf("\n"); +} +#endif + +static void +usage(void) +{ + (void) fprintf(stderr, "Usage: rusers [-ahilu] [host ...]\n"); + free(entry); + exit(1); +} |