1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  26 /* All Rights Reserved */
  27 /*
  28  * University Copyright- Copyright (c) 1982, 1986, 1988
  29  * The Regents of the University of California
  30  * All Rights Reserved
  31  *
  32  * University Acknowledgment- Portions of this document are derived from
  33  * software developed by the University of California, Berkeley, and its
  34  * contributors.
  35  */
  36 
  37 #pragma ident   "%Z%%M% %I%     %E% SMI"
  38 
  39 /*
  40  * rwall.c
  41  *      The client rwall program
  42  */
  43 
  44 #include <stdio.h>
  45 #include <stdio_ext.h>
  46 #include <sys/types.h>
  47 #include <stdlib.h>
  48 #include <unistd.h>
  49 #include <thread.h>
  50 #include <string.h>
  51 #include <rpc/rpc.h>
  52 #include <signal.h>
  53 #include <pwd.h>
  54 #include <rpcsvc/rwall.h>
  55 #include <netconfig.h>
  56 #include <netdb.h>
  57 #include <sys/time.h>
  58 #include <sys/resource.h>
  59 
  60 static void init_who(void);
  61 static void doall(void);
  62 static void doit(char *);
  63 static void *do_one(void *);
  64 static void usage(void);
  65 
  66 #define PATIENCE 10
  67 #define MAX_THREADS 1024
  68 
  69 static mutex_t tty = DEFAULTMUTEX;
  70 static char who[9] = "???";
  71 static char *path;
  72 static mutex_t thr_mtx = DEFAULTMUTEX;
  73 static int thread_count = 8;    /* fudge factor for system threads/fds */
  74 static int qflag = 0;           /* quiet: we don't care about errors */
  75 
  76 int
  77 main(int argc, char *argv[])
  78 {
  79         int msize;
  80         char buf[BUFSIZ+1];
  81         int i;
  82         char hostname[256];
  83         int hflag;
  84         struct rlimit rl;
  85 
  86         if (argc < 2)
  87                 usage();
  88 
  89         if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
  90                 rl.rlim_cur = (rl.rlim_max < MAX_THREADS ?
  91                     rl.rlim_max : MAX_THREADS);
  92                 (void) setrlimit(RLIMIT_NOFILE, &rl);
  93                 (void) enable_extended_FILE_stdio(-1, -1);
  94         }
  95 
  96         (void) gethostname(hostname, sizeof (hostname));
  97 
  98         init_who();
  99 
 100         msize = snprintf(buf, sizeof (buf), "From %s@%s:  ", who, hostname);
 101         while ((i = getchar()) != EOF) {
 102                 if (msize >= (sizeof (buf) - 1)) {
 103                         (void) fprintf(stderr, "Message too long\n");
 104                         exit(1);
 105                 }
 106                 buf[msize++] = i;
 107         }
 108         buf[msize] = '\0';
 109         path = buf;
 110         hflag = 1;
 111         while (argc > 1) {
 112                 if (argv[1][0] == '-') {
 113                         switch (argv[1][1]) {
 114                                 case 'h':
 115                                         hflag = 1;
 116                                         break;
 117                                 case 'n':
 118                                         hflag = 0;
 119                                         break;
 120                                 case 'q':
 121                                         qflag = 1;
 122                                         break;
 123                                 default:
 124                                         usage();
 125                                         break;
 126                         }
 127                         argc--;
 128                         argv++;
 129                         continue;
 130                 }
 131                 if (hflag) {
 132                         doit(argv[1]);
 133                 } else {
 134                         char *machine, *user, *domain;
 135 
 136                         (void) setnetgrent(argv[1]);
 137                         while (getnetgrent(&machine, &user, &domain)) {
 138                                 if (machine)
 139                                         doit(machine);
 140                                 else
 141                                         doall();
 142                         }
 143                         (void) endnetgrent();
 144                 }
 145                 argc--;
 146                 argv++;
 147         }
 148         thr_exit(NULL);
 149         return (0);
 150 }
 151 
 152 static void
 153 init_who(void)
 154 {
 155         char *wp;
 156         struct passwd *pwd;
 157 
 158         wp = getlogin();
 159 
 160         if (wp != NULL)
 161                 (void) strncpy(who, wp, sizeof (who));
 162         else {
 163                 pwd = getpwuid(getuid());
 164                 if (pwd)
 165                         (void) strncpy(who, pwd->pw_name, sizeof (who));
 166         }
 167 
 168 }
 169 
 170 /*
 171  * Saw a wild card, so do everything
 172  */
 173 static void
 174 doall(void)
 175 {
 176         (void) mutex_lock(&tty);
 177         (void) fprintf(stderr, "writing to everyone not supported\n");
 178         (void) mutex_unlock(&tty);
 179 }
 180 
 181 /*
 182  * Fire off a detached thread for each host in the list, if the thread
 183  * create fails simply run synchronously.
 184  */
 185 static void
 186 doit(char *hostname)
 187 {
 188         thread_t tid;
 189         char *thread_hostname;
 190 
 191         (void) mutex_lock(&thr_mtx);
 192         while (thread_count >= MAX_THREADS) {
 193                 (void) mutex_unlock(&thr_mtx);
 194                 (void) sleep(PATIENCE/2);
 195                 (void) mutex_lock(&thr_mtx);
 196         }
 197 
 198         thread_count++;
 199         (void) mutex_unlock(&thr_mtx);
 200 
 201         thread_hostname = strdup(hostname);
 202         if (thread_hostname == (char *)NULL) {
 203                 (void) mutex_lock(&tty);
 204                 (void) fprintf(stderr, "Ran out of memory\n");
 205                 (void) mutex_unlock(&tty);
 206                 exit(1);
 207         }
 208 
 209         if (thr_create(NULL, 0, do_one, thread_hostname,
 210                         THR_DETACHED, &tid) != 0) {
 211                 (void) do_one(thread_hostname);
 212         }
 213 }
 214 
 215 static void *
 216 do_one(void *arg)
 217 {
 218         char *hostname = arg;
 219         CLIENT *clnt;
 220         struct timeval tp;
 221         void *vp = NULL;
 222 
 223 #ifdef DEBUG
 224         (void) mutex_lock(&tty);
 225         (void) fprintf(stderr, "sending message to %s\n%s\n", hostname, path);
 226         (void) mutex_unlock(&tty);
 227         return (0);
 228 #endif
 229         tp.tv_sec = PATIENCE;
 230         tp.tv_usec = 0;
 231         clnt = clnt_create_timed(
 232                 hostname, WALLPROG, WALLVERS, "datagram_v", &tp);
 233         if (clnt == NULL) {
 234                 if (!qflag) {
 235                         (void) mutex_lock(&tty);
 236                         (void) fprintf(stderr, "rwall: Can't send to %s\n",
 237                             hostname);
 238                         clnt_pcreateerror(hostname);
 239                         (void) mutex_unlock(&tty);
 240                 }
 241                 goto errout;
 242         }
 243 
 244         if (wallproc_wall_1(&path, vp, clnt) != RPC_SUCCESS) {
 245                 if (!qflag) {
 246                         (void) mutex_lock(&tty);
 247                         clnt_perror(clnt, hostname);
 248                         (void) mutex_unlock(&tty);
 249                 }
 250         }
 251         clnt_destroy(clnt);
 252 errout:
 253         (void) mutex_lock(&thr_mtx);
 254         thread_count--;
 255         (void) mutex_unlock(&thr_mtx);
 256         free(hostname);
 257         return (0);
 258 }
 259 
 260 static void
 261 usage(void)
 262 {
 263         (void) fprintf(stderr,
 264             "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n");
 265         exit(1);
 266 }