1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <sys/time.h> 32*0Sstevel@tonic-gate #include <strings.h> 33*0Sstevel@tonic-gate #include <limits.h> 34*0Sstevel@tonic-gate #include <unistd.h> 35*0Sstevel@tonic-gate #include <errno.h> 36*0Sstevel@tonic-gate #include <signal.h> 37*0Sstevel@tonic-gate #include <fcntl.h> 38*0Sstevel@tonic-gate #include <sys/stat.h> 39*0Sstevel@tonic-gate #include <pthread.h> 40*0Sstevel@tonic-gate #include "rdimpl.h" 41*0Sstevel@tonic-gate #include "rdprot.h" 42*0Sstevel@tonic-gate #include "rdutil.h" 43*0Sstevel@tonic-gate #include "rdlist.h" 44*0Sstevel@tonic-gate #include "rdfile.h" 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #define RDS_VERSION "RDS Version 1.0\n" 47*0Sstevel@tonic-gate #define TIMEOUT_MSG "Timeout" 48*0Sstevel@tonic-gate #define NOTREADY_RESPONSE "BUSY" 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate #define DEFAULT_SCAN_INTERVAL 1000 /* milliseconds */ 51*0Sstevel@tonic-gate #define MAXIMAL_SCAN_INTERVAL 30000 /* milliseconds */ 52*0Sstevel@tonic-gate #define DEFAULT_CMD_TIMEOUT 2000 /* milliseconds */ 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate extern list_t users; /* list of users */ 55*0Sstevel@tonic-gate extern list_t projects; /* list of projects */ 56*0Sstevel@tonic-gate extern list_t sys; /* list with one sys entry */ 57*0Sstevel@tonic-gate extern list_t processes; /* list of processes */ 58*0Sstevel@tonic-gate extern list_t lwps; /* list of lwps */ 59*0Sstevel@tonic-gate extern char errmsg[]; /* global message buffer */ 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate static char greeting[] = \ 62*0Sstevel@tonic-gate "Resource Data Server\n" \ 63*0Sstevel@tonic-gate "Copyright 2001 SMI.\n" \ 64*0Sstevel@tonic-gate "Version 1.0\n"; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* ms timeout between successive cmds */ 67*0Sstevel@tonic-gate static int timeout = DEFAULT_CMD_TIMEOUT; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate /* ms interval between successive scans */ 70*0Sstevel@tonic-gate static int interval = DEFAULT_SCAN_INTERVAL; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* global signal flag */ 73*0Sstevel@tonic-gate static int sigterm = 0; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* print all cmd data on stdout in server mode flag */ 76*0Sstevel@tonic-gate static int Po = 0; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* count of scans performed in server mode */ 79*0Sstevel@tonic-gate static long scans_done = 0; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate /* name of rds logging file */ 82*0Sstevel@tonic-gate static char *log_file = NULL; 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate /* enable microstate accounting flag */ 85*0Sstevel@tonic-gate int mo = 0; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /* name of stored data file */ 88*0Sstevel@tonic-gate char *ltdb_file = NULL; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* mutex lock for data lists */ 92*0Sstevel@tonic-gate pthread_mutex_t listLock = PTHREAD_MUTEX_INITIALIZER; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* mutex lock for log */ 95*0Sstevel@tonic-gate pthread_mutex_t logLock = PTHREAD_MUTEX_INITIALIZER; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate /* identifiers for the various threads */ 98*0Sstevel@tonic-gate static pthread_t scanner = 0; 99*0Sstevel@tonic-gate static pthread_t server = 0; 100*0Sstevel@tonic-gate static pthread_t master = 0; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* 104*0Sstevel@tonic-gate * Clean up calling thread's state. 105*0Sstevel@tonic-gate */ 106*0Sstevel@tonic-gate static void 107*0Sstevel@tonic-gate thread_cleanup() 108*0Sstevel@tonic-gate { 109*0Sstevel@tonic-gate pthread_t this = pthread_self(); 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate if (pthread_equal(this, server)) { 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* shut down the command protocol */ 114*0Sstevel@tonic-gate (void) fprintf(stderr, 115*0Sstevel@tonic-gate "cleanup_state: server thread shutdown\n"); 116*0Sstevel@tonic-gate log_msg("server thread shutdown init\n"); 117*0Sstevel@tonic-gate wr_error(errmsg); 118*0Sstevel@tonic-gate log_msg("server thread shutdown complete\n"); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate } else if (pthread_equal(this, scanner)) { 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* shut down the scanner */ 123*0Sstevel@tonic-gate (void) fprintf(stderr, 124*0Sstevel@tonic-gate "cleanup_state: scanner thread shutdown\n"); 125*0Sstevel@tonic-gate log_msg("scanner thread shutdown init\n"); 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate log_msg("Waiting for server thread %d join from %d\n", 128*0Sstevel@tonic-gate (int)server, (int)this); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate if (pthread_join(server, NULL) != 0) { 131*0Sstevel@tonic-gate int e = errno; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate perror("server join (cleanup)"); 134*0Sstevel@tonic-gate log_msg("server join (cleanup) failed with %d\n", e); 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate log_msg("Server thread joined %d.\n", (int)this); 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate monitor_stop(); 140*0Sstevel@tonic-gate log_msg("scanner thread shutdown complete\n"); 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate } else if (pthread_equal(this, master)) { 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate (void) fprintf(stderr, 145*0Sstevel@tonic-gate "cleanup_state: master thread shutdown\n"); 146*0Sstevel@tonic-gate log_msg("master thread shutdown\n"); 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate } else { 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate (void) fprintf(stderr, 151*0Sstevel@tonic-gate "cleanup_state: unknown thread id %d\n", (int)this); 152*0Sstevel@tonic-gate log_msg("unknown thread %d shutdown\n", (int)this); 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * Called by any of the threads, this should set state 160*0Sstevel@tonic-gate * that the other threads will pick up so they will (eventually) 161*0Sstevel@tonic-gate * shut themselves down cleanly, then call pthread_exit 162*0Sstevel@tonic-gate * to properly shut down the calling thread. 163*0Sstevel@tonic-gate * The calling thread will exit with its code set to 1. 164*0Sstevel@tonic-gate */ 165*0Sstevel@tonic-gate static void 166*0Sstevel@tonic-gate generic_exit(char *msg, int status) 167*0Sstevel@tonic-gate { 168*0Sstevel@tonic-gate char wb[256]; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* cannot be on the stack since thread terminates with pthread_exit */ 171*0Sstevel@tonic-gate static int retcode = 0; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate retcode = status; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* worker-specific cleanup */ 176*0Sstevel@tonic-gate thread_cleanup(); 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* announce the calling thread's demise */ 179*0Sstevel@tonic-gate (void) snprintf(wb, sizeof (wb) - 2, "(%d) %s", 180*0Sstevel@tonic-gate (int)pthread_self(), msg); 181*0Sstevel@tonic-gate log_msg(wb); 182*0Sstevel@tonic-gate (void) fprintf(stderr, "%s", wb); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* everybody checks this periodically */ 185*0Sstevel@tonic-gate sigterm = 1; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate log_msg("calling thread_exit() from %d\n", (int)pthread_self()); 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate /* return status as the calling thread's exit code */ 190*0Sstevel@tonic-gate pthread_exit(&retcode); 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * Called by any of the threads, this should set state 197*0Sstevel@tonic-gate * that the other threads will pick up so they will (eventually) 198*0Sstevel@tonic-gate * shut themselves down cleanly, then call pthread_exit 199*0Sstevel@tonic-gate * to properly shut down the calling thread. 200*0Sstevel@tonic-gate * The calling thread will exit with its code set to 1. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate void 203*0Sstevel@tonic-gate err_exit() 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate generic_exit(errmsg, 1); 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * Called by any of the threads, this should set state 211*0Sstevel@tonic-gate * that the other threads will pick up so they will (eventually) 212*0Sstevel@tonic-gate * shut themselves down cleanly, then call pthread_exit 213*0Sstevel@tonic-gate * to properly shut down the calling thread. 214*0Sstevel@tonic-gate * The calling thread will exit with its code set to 0. 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate static void 217*0Sstevel@tonic-gate ok_exit() 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate generic_exit("Normal exit.\n", 0); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate static void 224*0Sstevel@tonic-gate usage() 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate (void) printf("rds [ options ]\n" \ 227*0Sstevel@tonic-gate "-u\t\t- print stats for all users\n" \ 228*0Sstevel@tonic-gate "-U<uid>\t\t- print stats for <uid>\n" \ 229*0Sstevel@tonic-gate "-j\t\t- print stats for all projects\n" \ 230*0Sstevel@tonic-gate "-J<projid>\t- print stats for <projid>\n" \ 231*0Sstevel@tonic-gate "-p\t\t- print stats for all processes\n" \ 232*0Sstevel@tonic-gate "-P <pid>\t- print stats for <pid>\n" \ 233*0Sstevel@tonic-gate "-m\t\t- enable microstate accounting\n" \ 234*0Sstevel@tonic-gate "-a\t\t- run in server mode\n" \ 235*0Sstevel@tonic-gate "-t<time>\t- set command timeout to <time>\n" \ 236*0Sstevel@tonic-gate "-i<interval>\t- set interval between scans to <time>\n" \ 237*0Sstevel@tonic-gate "-f<file>\t- use <file> to save/restore state\n" \ 238*0Sstevel@tonic-gate "-d\t\t- in server mode print stats on stdout\n" \ 239*0Sstevel@tonic-gate "-L<file>|stderr - write log messages into <file> or stderr\n" \ 240*0Sstevel@tonic-gate "-v\t\t- print rds version\n"); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate /* 245*0Sstevel@tonic-gate * Initiate the rds command protocol from the server side. 246*0Sstevel@tonic-gate * Emits the header and version strings. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate static void 249*0Sstevel@tonic-gate start_protocol() 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate /* emit version and header strings */ 252*0Sstevel@tonic-gate if (wr_string(greeting) != 0) 253*0Sstevel@tonic-gate err_exit(); 254*0Sstevel@tonic-gate if (wr_phead() != 0) 255*0Sstevel@tonic-gate err_exit(); 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * Emit the "not ready" message and a prompt. 261*0Sstevel@tonic-gate */ 262*0Sstevel@tonic-gate static void 263*0Sstevel@tonic-gate notready() 264*0Sstevel@tonic-gate { 265*0Sstevel@tonic-gate (void) wr_string(NOTREADY_RESPONSE); 266*0Sstevel@tonic-gate (void) wr_string("\n"); 267*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * process_cmds() implements the rds server running in threaded mode. 273*0Sstevel@tonic-gate * 274*0Sstevel@tonic-gate * It assumes that the /proc scanner is running in another thread and 275*0Sstevel@tonic-gate * guarding access to critical sections. 276*0Sstevel@tonic-gate * 277*0Sstevel@tonic-gate * This function writes version and header to the output stream and waits 278*0Sstevel@tonic-gate * for commands on the input stream. 279*0Sstevel@tonic-gate * 280*0Sstevel@tonic-gate * Each received command may block on a mutex while the scanner thread is 281*0Sstevel@tonic-gate * updating. 282*0Sstevel@tonic-gate * 283*0Sstevel@tonic-gate * If the timeout expires without receiving a command, it will write an 284*0Sstevel@tonic-gate * error message and terminate. A received command resets the timeout. 285*0Sstevel@tonic-gate * 286*0Sstevel@tonic-gate * Each command is acknowledged with a prompt. 287*0Sstevel@tonic-gate */ 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /*ARGSUSED*/ 290*0Sstevel@tonic-gate static void * 291*0Sstevel@tonic-gate process_cmds(void *p) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate fd_set readfs; 294*0Sstevel@tonic-gate struct timeval timev; 295*0Sstevel@tonic-gate int interval_cnt = timeout / interval; 296*0Sstevel@tonic-gate int ret; 297*0Sstevel@tonic-gate char *cmd; 298*0Sstevel@tonic-gate hrtime_t t1, t2, wt1, wt2; 299*0Sstevel@tonic-gate double d; 300*0Sstevel@tonic-gate int cmd_is_noop; 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /* start the protocol so the client knows we're alive */ 303*0Sstevel@tonic-gate start_protocol(); 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* establish timeout value */ 306*0Sstevel@tonic-gate timev.tv_sec = interval / 1000; 307*0Sstevel@tonic-gate timev.tv_usec = (interval - (timev.tv_sec * 1000)) * 1000; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* initialize stdin object */ 310*0Sstevel@tonic-gate (void) FD_ZERO(&readfs); 311*0Sstevel@tonic-gate FD_SET(STDIN_FILENO, &readfs); 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate /* emit initial prompt */ 314*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate while (interval_cnt > 0) { 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate /* time to shut down, exit gracefully */ 319*0Sstevel@tonic-gate if (sigterm == 1) { 320*0Sstevel@tonic-gate break; /* ok_exit(); */ 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* check for stdin status */ 324*0Sstevel@tonic-gate FD_SET(STDIN_FILENO, &readfs); 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* block on stdin, max timeout */ 327*0Sstevel@tonic-gate if ((ret = select(1, &readfs, NULL, NULL, &timev)) == 0) { 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate /* timed out waiting for a command */ 330*0Sstevel@tonic-gate --interval_cnt; 331*0Sstevel@tonic-gate continue; 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate /* if interrupted system call then exit gracefully */ 335*0Sstevel@tonic-gate if (ret == -1 && errno == EINTR) { 336*0Sstevel@tonic-gate log_msg("select() interrupted\n"); 337*0Sstevel@tonic-gate ok_exit(); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* weird error condition */ 341*0Sstevel@tonic-gate if (ret != 1) { 342*0Sstevel@tonic-gate perror("RDS Select error"); 343*0Sstevel@tonic-gate log_msg("select() error = %d\n", errno); 344*0Sstevel@tonic-gate continue; 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* process whatever is waiting on stdin */ 348*0Sstevel@tonic-gate if (FD_ISSET(STDIN_FILENO, &readfs)) { 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate cmd_is_noop = 0; 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate /* try to parse out a valid command */ 353*0Sstevel@tonic-gate if ((cmd = r_cmd()) == NULL) { 354*0Sstevel@tonic-gate err_exit(); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate log_msg("received '%s' command\n", cmd); 357*0Sstevel@tonic-gate t1 = gethrtime(); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate /* handle the various commands */ 360*0Sstevel@tonic-gate if (strcmp(cmd, CMD_EXIT) == 0) { 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* exit now */ 363*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 364*0Sstevel@tonic-gate ok_exit(); 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate } else if (strcmp(cmd, CRETURN) == 0) { 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* null command */ 369*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 370*0Sstevel@tonic-gate ++cmd_is_noop; 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_ALIVE) == 0) { 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* keepalive, another null command */ 375*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 376*0Sstevel@tonic-gate ++cmd_is_noop; 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETALL) == 0) { 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* get all project/user data */ 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate /* 383*0Sstevel@tonic-gate * If the first scan has not yet 384*0Sstevel@tonic-gate * completed, notify the requester and 385*0Sstevel@tonic-gate * wait for a new command. The 386*0Sstevel@tonic-gate * command timeout counter is 387*0Sstevel@tonic-gate * suspended until the next command 388*0Sstevel@tonic-gate * arrives. 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate if (scans_done == 0) { 391*0Sstevel@tonic-gate notready(); 392*0Sstevel@tonic-gate continue; 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate /* grab the mutex */ 396*0Sstevel@tonic-gate wt1 = gethrtime(); 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 399*0Sstevel@tonic-gate &listLock)) == 0) { 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate wt2 = gethrtime(); 402*0Sstevel@tonic-gate d = (double) 403*0Sstevel@tonic-gate (wt2 - wt1) / 1000000000.0; 404*0Sstevel@tonic-gate log_msg("Server lock wait" 405*0Sstevel@tonic-gate " was %1.5f sec\n", d); 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate if (wr_lshead(5) != 0) 408*0Sstevel@tonic-gate err_exit(); 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate if (list_write(L_AC_USR, Po) == -1) 411*0Sstevel@tonic-gate break; 412*0Sstevel@tonic-gate if (list_write(L_USR_SI, Po) == -1) 413*0Sstevel@tonic-gate break; 414*0Sstevel@tonic-gate if (list_write(L_AC_PRJ, Po) == -1) 415*0Sstevel@tonic-gate break; 416*0Sstevel@tonic-gate if (list_write(L_PRJ_SI, Po) == -1) 417*0Sstevel@tonic-gate break; 418*0Sstevel@tonic-gate if (list_write(L_SYSTEM, Po) == -1) 419*0Sstevel@tonic-gate break; 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate /* release the mutex */ 422*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 423*0Sstevel@tonic-gate &listLock)) != 0) { 424*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \ 425*0Sstevel@tonic-gate "failed with %d\n", ret); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate } else { 429*0Sstevel@tonic-gate log_msg("pthread_mutex_lock failed" \ 430*0Sstevel@tonic-gate "with %d\n", ret); 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETPL) == 0) { 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* get all process data (deprecated?) */ 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate if (scans_done == 0) { 440*0Sstevel@tonic-gate notready(); 441*0Sstevel@tonic-gate continue; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* grab the mutex */ 445*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 446*0Sstevel@tonic-gate &listLock)) == 0) { 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate if (wr_lshead(1) != 0) 449*0Sstevel@tonic-gate err_exit(); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate if (list_write(L_PRC_SI, Po) == -1) 452*0Sstevel@tonic-gate break; 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate /* release the mutex */ 455*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 456*0Sstevel@tonic-gate &listLock)) != 0) { 457*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock"\ 458*0Sstevel@tonic-gate "failed with %d\n", ret); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate } else { 462*0Sstevel@tonic-gate log_msg("pthread_mutex_lock"\ 463*0Sstevel@tonic-gate "failed with %d\n", ret); 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETUL) == 0) { 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* get the active user list */ 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate if (scans_done == 0) { 473*0Sstevel@tonic-gate notready(); 474*0Sstevel@tonic-gate continue; 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate /* grab the mutex */ 478*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 479*0Sstevel@tonic-gate &listLock)) == 0) { 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate if (wr_lshead(1) != 0) 482*0Sstevel@tonic-gate err_exit(); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate if (list_write(L_USR_SI, Po) == -1) 486*0Sstevel@tonic-gate break; 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate /* release the mutex */ 489*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 490*0Sstevel@tonic-gate &listLock)) != 0) { 491*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock"\ 492*0Sstevel@tonic-gate "failed with %d\n", ret); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate } else { 496*0Sstevel@tonic-gate log_msg("pthread_mutex_lock" \ 497*0Sstevel@tonic-gate "failed with %d\n", ret); 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETAUL) == 0) { 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate /* get data for a particular user */ 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if (scans_done == 0) { 507*0Sstevel@tonic-gate notready(); 508*0Sstevel@tonic-gate continue; 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate /* grab the mutex */ 512*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 513*0Sstevel@tonic-gate &listLock)) == 0) { 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate if (wr_lshead(1) != 0) 516*0Sstevel@tonic-gate err_exit(); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate if (list_write(L_AC_USR, Po) == -1) 519*0Sstevel@tonic-gate break; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* release the mutex */ 522*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 523*0Sstevel@tonic-gate &listLock)) != 0) { 524*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \ 525*0Sstevel@tonic-gate "failed with %d\n", ret); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate } else { 529*0Sstevel@tonic-gate log_msg("pthread_mutex_lock" \ 530*0Sstevel@tonic-gate "failed with %d\n", ret); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETJL) == 0) { 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate if (scans_done == 0) { 538*0Sstevel@tonic-gate notready(); 539*0Sstevel@tonic-gate continue; 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* grab the mutex */ 543*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 544*0Sstevel@tonic-gate &listLock)) == 0) { 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if (wr_lshead(1) != 0) 547*0Sstevel@tonic-gate err_exit(); 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* grab the mutex here */ 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate if (list_write(L_PRJ_SI, Po) == -1) 552*0Sstevel@tonic-gate break; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* release the mutex */ 555*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 556*0Sstevel@tonic-gate &listLock)) != 0) { 557*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \ 558*0Sstevel@tonic-gate "failed with %d\n", ret); 559*0Sstevel@tonic-gate } 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate } else { 562*0Sstevel@tonic-gate log_msg("pthread_mutex_lock" \ 563*0Sstevel@tonic-gate "failed with %d\n", ret); 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETAJL) == 0) { 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate if (scans_done == 0) { 571*0Sstevel@tonic-gate notready(); 572*0Sstevel@tonic-gate continue; 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate /* grab the mutex */ 576*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 577*0Sstevel@tonic-gate &listLock)) == 0) { 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate if (wr_lshead(1) != 0) 580*0Sstevel@tonic-gate err_exit(); 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate if (list_write(L_AC_PRJ, Po) == -1) 583*0Sstevel@tonic-gate break; 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate /* release the mutex */ 586*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 587*0Sstevel@tonic-gate &listLock)) != 0) { 588*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \ 589*0Sstevel@tonic-gate "failed with %d\n", ret); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate } else { 593*0Sstevel@tonic-gate log_msg("pthread_mutex_lock" \ 594*0Sstevel@tonic-gate "failed with %d\n", ret); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETASL) == 0) { 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate if (scans_done == 0) { 602*0Sstevel@tonic-gate notready(); 603*0Sstevel@tonic-gate continue; 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate /* grab the mutex */ 607*0Sstevel@tonic-gate if ((ret = pthread_mutex_lock( 608*0Sstevel@tonic-gate &listLock)) == 0) { 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate if (wr_lshead(1) != 0) 611*0Sstevel@tonic-gate err_exit(); 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate if (list_write(L_SYSTEM, Po) == -1) 614*0Sstevel@tonic-gate break; 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate /* release the mutex */ 617*0Sstevel@tonic-gate if ((ret = pthread_mutex_unlock( 618*0Sstevel@tonic-gate &listLock)) != 0) { 619*0Sstevel@tonic-gate log_msg("pthread_mutex_unlock" 620*0Sstevel@tonic-gate "failed with %d\n", ret); 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate } else { 624*0Sstevel@tonic-gate log_msg("pthread_mutex_lock" 625*0Sstevel@tonic-gate "failed with %d\n", ret); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK); 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate } else { 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* bad command */ 633*0Sstevel@tonic-gate (void) wr_prompt(PROMPT_WHAT); 634*0Sstevel@tonic-gate format_err("RDS protocol error:" 635*0Sstevel@tonic-gate "unknown command"); 636*0Sstevel@tonic-gate ++cmd_is_noop; 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate if (!cmd_is_noop) { 641*0Sstevel@tonic-gate t2 = gethrtime(); 642*0Sstevel@tonic-gate d = (double)(t2 - t1) / 1000000000.0; 643*0Sstevel@tonic-gate log_msg("Command took %2.3f sec" 644*0Sstevel@tonic-gate " (%ld scans done)\n", 645*0Sstevel@tonic-gate d, scans_done); 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* reset the interval counter for timeout */ 649*0Sstevel@tonic-gate interval_cnt = timeout / interval; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate continue; 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate /* timed out, one less interval to wait */ 655*0Sstevel@tonic-gate --interval_cnt; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* timed out, print message */ 659*0Sstevel@tonic-gate if (interval_cnt == 0) { 660*0Sstevel@tonic-gate format_err("%s %d sec. left", TIMEOUT_MSG, timeout / 1000); 661*0Sstevel@tonic-gate err_exit(); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* clean exit */ 665*0Sstevel@tonic-gate log_msg("process_cmds exits\n"); 666*0Sstevel@tonic-gate ok_exit(); /* calls pthread_exit() */ 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate return (NULL); 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * The thread procedure for the /proc scanner. 674*0Sstevel@tonic-gate * Does a full scan of /proc, then sleeps for a specified time. 675*0Sstevel@tonic-gate * 676*0Sstevel@tonic-gate * The specified time ('interval') is adjusted according to 677*0Sstevel@tonic-gate * the average of the last three scan times. 678*0Sstevel@tonic-gate * The sleep time is increase if the average scan duration time 679*0Sstevel@tonic-gate * exceeds a threshold. The threshold is set to 50% of the current 680*0Sstevel@tonic-gate * sleep time. 681*0Sstevel@tonic-gate * The sleep time is decreased in a similar way. 682*0Sstevel@tonic-gate * 683*0Sstevel@tonic-gate * The update of the project and user lists is guarded by aggregate_list_mutex. 684*0Sstevel@tonic-gate * The update of the process list is guarded by process_list_mutex. 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate /*ARGSUSED*/ 688*0Sstevel@tonic-gate static void * 689*0Sstevel@tonic-gate scanprocfs(void *p) 690*0Sstevel@tonic-gate { 691*0Sstevel@tonic-gate hrtime_t t1; 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate double d0; /* duration of the for last scan */ 694*0Sstevel@tonic-gate double d1; /* duration of the last scan */ 695*0Sstevel@tonic-gate double d2; /* duration of current scan */ 696*0Sstevel@tonic-gate double ad; /* average duration of the last three scans */ 697*0Sstevel@tonic-gate double threshold_up; /* threshold for increasing scan duration */ 698*0Sstevel@tonic-gate double threshold_down; /* threshold for decreasing scan duration */ 699*0Sstevel@tonic-gate double thf = 0.5; /* */ 700*0Sstevel@tonic-gate int new_interval = interval; 701*0Sstevel@tonic-gate int time_to_sleep; 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate threshold_up = new_interval * thf; 704*0Sstevel@tonic-gate threshold_down = 0; 705*0Sstevel@tonic-gate d0 = d1 = d2 = ad = 0; 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate while (sigterm != 1) { 709*0Sstevel@tonic-gate t1 = gethrtime(); 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate if (monitor_update() != 0) 712*0Sstevel@tonic-gate err_exit(); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate ++scans_done; 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate /* make sure we're sleeping a reasonable amount of time */ 717*0Sstevel@tonic-gate d0 = d1; d1 = d2; 718*0Sstevel@tonic-gate d2 = (gethrtime() - t1) / 1000000.0; 719*0Sstevel@tonic-gate ad = (d0 + d1 + d2) / 3.0; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate if (threshold_up < ad) { 722*0Sstevel@tonic-gate /* increase the new_interval in 1000 ms steps */ 723*0Sstevel@tonic-gate new_interval += (int)((ad - threshold_up) / thf); 724*0Sstevel@tonic-gate if (new_interval > MAXIMAL_SCAN_INTERVAL) 725*0Sstevel@tonic-gate new_interval = MAXIMAL_SCAN_INTERVAL; 726*0Sstevel@tonic-gate if ((new_interval % 1000) > 500) 727*0Sstevel@tonic-gate new_interval += 500; 728*0Sstevel@tonic-gate new_interval = (new_interval / 1000) * 1000; 729*0Sstevel@tonic-gate /* pull up the thresholds */ 730*0Sstevel@tonic-gate threshold_down = threshold_up; 731*0Sstevel@tonic-gate threshold_up = new_interval * thf; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate if (threshold_down > ad) { 735*0Sstevel@tonic-gate /* decrease the new_interval in 1000 ms steps */ 736*0Sstevel@tonic-gate new_interval -= (int)((threshold_down - ad) / thf); 737*0Sstevel@tonic-gate if ((new_interval % 1000) > 500) 738*0Sstevel@tonic-gate new_interval += 500; 739*0Sstevel@tonic-gate new_interval = (new_interval / 1000) * 1000; 740*0Sstevel@tonic-gate /* pull down the thresholds */ 741*0Sstevel@tonic-gate if (new_interval < interval) { 742*0Sstevel@tonic-gate /* just as at the beginning */ 743*0Sstevel@tonic-gate new_interval = interval; 744*0Sstevel@tonic-gate threshold_down = 0; 745*0Sstevel@tonic-gate threshold_up = new_interval * thf; 746*0Sstevel@tonic-gate } else { 747*0Sstevel@tonic-gate threshold_up = threshold_down; 748*0Sstevel@tonic-gate threshold_down = new_interval * thf; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate log_msg("scan %.0f ms, ad %.0f ms, thold_up %.0f ms," 753*0Sstevel@tonic-gate " thold_down %.0f ms, interval %d ms\n", 754*0Sstevel@tonic-gate d2, ad, threshold_up, threshold_down, new_interval); 755*0Sstevel@tonic-gate log_msg("%d files open\n", fd_count()); 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate time_to_sleep = new_interval; 758*0Sstevel@tonic-gate while (time_to_sleep > 0) { 759*0Sstevel@tonic-gate napms(1000); 760*0Sstevel@tonic-gate time_to_sleep -= 1000; 761*0Sstevel@tonic-gate if (sigterm == 1) 762*0Sstevel@tonic-gate break; 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate log_msg("scanprocfs exits\n"); 767*0Sstevel@tonic-gate ok_exit(); 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate return (NULL); 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate static void 773*0Sstevel@tonic-gate sig_rds(int sig) 774*0Sstevel@tonic-gate { 775*0Sstevel@tonic-gate log_msg("caught signal #%d\n", sig); 776*0Sstevel@tonic-gate switch (sig) { 777*0Sstevel@tonic-gate case SIGINT: 778*0Sstevel@tonic-gate case SIGTERM: 779*0Sstevel@tonic-gate sigterm = 1; 780*0Sstevel@tonic-gate break; 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* 786*0Sstevel@tonic-gate * Run the command processor, with the /proc scanner and rds command processor 787*0Sstevel@tonic-gate * in separate threads. 788*0Sstevel@tonic-gate * 789*0Sstevel@tonic-gate * Initializes the mutex as a side effect. 790*0Sstevel@tonic-gate * 791*0Sstevel@tonic-gate * Returns on exit of the command process or as a result of a signal. 792*0Sstevel@tonic-gate */ 793*0Sstevel@tonic-gate static void 794*0Sstevel@tonic-gate runserver() 795*0Sstevel@tonic-gate { 796*0Sstevel@tonic-gate int rv; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate /* keep track of main()'s thread */ 799*0Sstevel@tonic-gate master = pthread_self(); 800*0Sstevel@tonic-gate log_msg("master thread = %d\n", (int)master); 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate /* initialize the mutexes for later use */ 803*0Sstevel@tonic-gate rv = pthread_mutex_init(&listLock, NULL); 804*0Sstevel@tonic-gate if (rv != 0) { 805*0Sstevel@tonic-gate (void) sprintf(errmsg, "Mutex init failed with %d", rv); 806*0Sstevel@tonic-gate err_exit(); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate rv = pthread_mutex_init(&listLock, NULL); 810*0Sstevel@tonic-gate if (rv != 0) { 811*0Sstevel@tonic-gate (void) sprintf(errmsg, "Mutex init failed with %d", rv); 812*0Sstevel@tonic-gate err_exit(); 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate log_msg("pthread_mutex_init returns %d\n", rv); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate /* launch the command processor in its thread */ 818*0Sstevel@tonic-gate rv = pthread_create(&server, NULL, process_cmds, NULL); 819*0Sstevel@tonic-gate if (rv != 0) { 820*0Sstevel@tonic-gate (void) sprintf(errmsg, 821*0Sstevel@tonic-gate "Server thread create failed with %d", rv); 822*0Sstevel@tonic-gate err_exit(); 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate } 825*0Sstevel@tonic-gate log_msg("Server pthread_create = %d returns %d\n", 826*0Sstevel@tonic-gate (int)server, rv); 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate /* launch the scanner in its thread */ 830*0Sstevel@tonic-gate rv = pthread_create(&scanner, NULL, scanprocfs, NULL); 831*0Sstevel@tonic-gate if (rv != 0) { 832*0Sstevel@tonic-gate (void) sprintf(errmsg, 833*0Sstevel@tonic-gate "Scanner thread create failed with %d", rv); 834*0Sstevel@tonic-gate err_exit(); 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate log_msg("Scanner pthread_create = %d returns %d\n", 837*0Sstevel@tonic-gate (int)scanner, rv); 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate /* nothing much else to do here */ 841*0Sstevel@tonic-gate while (sigterm != 1) 842*0Sstevel@tonic-gate (void) sleep(1); 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate /* wait for the scanner & server threads to shut down */ 845*0Sstevel@tonic-gate log_msg("Waiting for scanner thread %d join from %d\n", 846*0Sstevel@tonic-gate (int)scanner, (int)pthread_self()); 847*0Sstevel@tonic-gate if (pthread_join(scanner, NULL) != 0) { 848*0Sstevel@tonic-gate int e = errno; 849*0Sstevel@tonic-gate perror("scanner join"); 850*0Sstevel@tonic-gate log_msg("scanner join failed with %d\n", e); 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate log_msg("Scanner thread joined.\n"); 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate /* finish cleaning up global state */ 855*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&listLock); 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate log_msg("Global cleanup completed.\n"); 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate int 862*0Sstevel@tonic-gate main(int argc, char *argv[]) 863*0Sstevel@tonic-gate { 864*0Sstevel@tonic-gate int i, uo = 0, jo = 0, po = 0, do_server_mode = 0, 865*0Sstevel@tonic-gate selected = 0; 866*0Sstevel@tonic-gate int lo_arg = 1; 867*0Sstevel@tonic-gate int uid = -1, pid = -1, jid = -1; 868*0Sstevel@tonic-gate int rv; 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate /* parse args */ 871*0Sstevel@tonic-gate while ((i = getopt(argc, argv, "uU:jJ:pP:mat:i:l:f:dvL:")) != EOF) 872*0Sstevel@tonic-gate switch (i) { 873*0Sstevel@tonic-gate case 'U': 874*0Sstevel@tonic-gate uid = atoi(optarg); 875*0Sstevel@tonic-gate uo = 1; selected = 1; 876*0Sstevel@tonic-gate break; 877*0Sstevel@tonic-gate case 'u': 878*0Sstevel@tonic-gate uo = 1; selected = 1; 879*0Sstevel@tonic-gate break; 880*0Sstevel@tonic-gate case 'J': 881*0Sstevel@tonic-gate jid = atoi(optarg); 882*0Sstevel@tonic-gate jo = 1; selected = 1; 883*0Sstevel@tonic-gate break; 884*0Sstevel@tonic-gate case 'j': 885*0Sstevel@tonic-gate jo = 1; selected = 1; 886*0Sstevel@tonic-gate break; 887*0Sstevel@tonic-gate case 'P': 888*0Sstevel@tonic-gate pid = atoi(optarg); 889*0Sstevel@tonic-gate po = 1; selected = 1; 890*0Sstevel@tonic-gate break; 891*0Sstevel@tonic-gate case 'p': 892*0Sstevel@tonic-gate po = 1; selected = 1; 893*0Sstevel@tonic-gate break; 894*0Sstevel@tonic-gate case 'a': 895*0Sstevel@tonic-gate do_server_mode = 1; 896*0Sstevel@tonic-gate break; 897*0Sstevel@tonic-gate case 'l': 898*0Sstevel@tonic-gate if ((lo_arg = atoi(optarg)) == 0) { 899*0Sstevel@tonic-gate usage(); 900*0Sstevel@tonic-gate exit(1); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate break; 903*0Sstevel@tonic-gate case 'd': 904*0Sstevel@tonic-gate Po = 1; 905*0Sstevel@tonic-gate break; 906*0Sstevel@tonic-gate case 't': 907*0Sstevel@tonic-gate if ((timeout = atoi(optarg)) < 1000) { 908*0Sstevel@tonic-gate usage(); 909*0Sstevel@tonic-gate exit(1); 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate break; 912*0Sstevel@tonic-gate case 'i': 913*0Sstevel@tonic-gate if ((interval = atoi(optarg)) < 100) { 914*0Sstevel@tonic-gate usage(); 915*0Sstevel@tonic-gate exit(1); 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate break; 918*0Sstevel@tonic-gate case 'f': 919*0Sstevel@tonic-gate ltdb_file = optarg; 920*0Sstevel@tonic-gate break; 921*0Sstevel@tonic-gate case 'L': 922*0Sstevel@tonic-gate log_file = optarg; 923*0Sstevel@tonic-gate break; 924*0Sstevel@tonic-gate case 'm': 925*0Sstevel@tonic-gate mo = 1; 926*0Sstevel@tonic-gate break; 927*0Sstevel@tonic-gate case 'v': (void) printf(RDS_VERSION); 928*0Sstevel@tonic-gate exit(1); 929*0Sstevel@tonic-gate break; 930*0Sstevel@tonic-gate case '?': 931*0Sstevel@tonic-gate usage(); 932*0Sstevel@tonic-gate exit(1); 933*0Sstevel@tonic-gate default: 934*0Sstevel@tonic-gate usage(); 935*0Sstevel@tonic-gate exit(1); 936*0Sstevel@tonic-gate } 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate /* set handlers */ 940*0Sstevel@tonic-gate (void) signal(SIGINT, sig_rds); 941*0Sstevel@tonic-gate (void) signal(SIGTERM, sig_rds); 942*0Sstevel@tonic-gate (void) sigignore(SIGPIPE); 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate /* initialize the log mutex */ 945*0Sstevel@tonic-gate rv = pthread_mutex_init(&logLock, NULL); 946*0Sstevel@tonic-gate if (rv != 0) { 947*0Sstevel@tonic-gate (void) sprintf(errmsg, "Mutex init failed with %d", rv); 948*0Sstevel@tonic-gate err_exit(); 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate if (log_file != NULL) 952*0Sstevel@tonic-gate log_open(log_file); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate if (do_server_mode == 1) { 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate /* 957*0Sstevel@tonic-gate * Initialize list data structures, possibly 958*0Sstevel@tonic-gate * reading saved data. 959*0Sstevel@tonic-gate * 960*0Sstevel@tonic-gate * As a side effect this messes with the protocol 961*0Sstevel@tonic-gate * state since the list reader pretends it's reading 962*0Sstevel@tonic-gate * the protocol. 963*0Sstevel@tonic-gate * 964*0Sstevel@tonic-gate * A problem here is that we cannot start the server 965*0Sstevel@tonic-gate * thread until this has completed because it will try to 966*0Sstevel@tonic-gate * use the same state hidden inside the protocol code. 967*0Sstevel@tonic-gate * 968*0Sstevel@tonic-gate * The consequence is that this may occupy the main 969*0Sstevel@tonic-gate * thread for an arbitrarily long time *before* the server 970*0Sstevel@tonic-gate * thread is started and the app becomes able to respond 971*0Sstevel@tonic-gate * to commands. 972*0Sstevel@tonic-gate */ 973*0Sstevel@tonic-gate if (monitor_start() != 0) 974*0Sstevel@tonic-gate err_exit(); 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate /* Open pipes in and out for the command protocol */ 977*0Sstevel@tonic-gate if (open_prot(STDOUT_FILENO, "w") == -1) { 978*0Sstevel@tonic-gate err_exit(); 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate if (open_prot(STDIN_FILENO, "r") == -1) { 981*0Sstevel@tonic-gate err_exit(); 982*0Sstevel@tonic-gate } 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate /* Waits for the child threads to end */ 985*0Sstevel@tonic-gate runserver(); 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate /* Close command I/O pipes */ 988*0Sstevel@tonic-gate close_prot(); 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate } else { 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate if (monitor_start() != 0) 993*0Sstevel@tonic-gate err_exit(); 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate for (i = 0; i < lo_arg; i ++) { 996*0Sstevel@tonic-gate if (sigterm == 1) 997*0Sstevel@tonic-gate break; 998*0Sstevel@tonic-gate if (monitor_update() != 0) 999*0Sstevel@tonic-gate err_exit(); 1000*0Sstevel@tonic-gate if (selected == 0 || uo == 1) { 1001*0Sstevel@tonic-gate list_print(&users, uid); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate if (selected == 0 || jo == 1) { 1004*0Sstevel@tonic-gate list_print(&projects, jid); 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate if (selected == 0 || po == 1) { 1007*0Sstevel@tonic-gate list_print(&processes, pid); 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate if (i < lo_arg - 1) 1010*0Sstevel@tonic-gate napms(interval); 1011*0Sstevel@tonic-gate } 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate /* clean up the log stuff at the very end */ 1015*0Sstevel@tonic-gate log_close(); 1016*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&logLock); 1017*0Sstevel@tonic-gate 1018*0Sstevel@tonic-gate return (0); 1019*0Sstevel@tonic-gate } 1020