10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*1914Scasper * Common Development and Distribution License (the "License").
6*1914Scasper * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*1914Scasper * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <stdio.h>
29*1914Scasper #include <stdio_ext.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <sys/time.h>
320Sstevel@tonic-gate #include <strings.h>
330Sstevel@tonic-gate #include <limits.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <fcntl.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <pthread.h>
400Sstevel@tonic-gate #include "rdimpl.h"
410Sstevel@tonic-gate #include "rdprot.h"
420Sstevel@tonic-gate #include "rdutil.h"
430Sstevel@tonic-gate #include "rdlist.h"
440Sstevel@tonic-gate #include "rdfile.h"
450Sstevel@tonic-gate
460Sstevel@tonic-gate #define RDS_VERSION "RDS Version 1.0\n"
470Sstevel@tonic-gate #define TIMEOUT_MSG "Timeout"
480Sstevel@tonic-gate #define NOTREADY_RESPONSE "BUSY"
490Sstevel@tonic-gate
500Sstevel@tonic-gate #define DEFAULT_SCAN_INTERVAL 1000 /* milliseconds */
510Sstevel@tonic-gate #define MAXIMAL_SCAN_INTERVAL 30000 /* milliseconds */
520Sstevel@tonic-gate #define DEFAULT_CMD_TIMEOUT 2000 /* milliseconds */
530Sstevel@tonic-gate
540Sstevel@tonic-gate extern list_t users; /* list of users */
550Sstevel@tonic-gate extern list_t projects; /* list of projects */
560Sstevel@tonic-gate extern list_t sys; /* list with one sys entry */
570Sstevel@tonic-gate extern list_t processes; /* list of processes */
580Sstevel@tonic-gate extern list_t lwps; /* list of lwps */
590Sstevel@tonic-gate extern char errmsg[]; /* global message buffer */
600Sstevel@tonic-gate
610Sstevel@tonic-gate static char greeting[] = \
620Sstevel@tonic-gate "Resource Data Server\n" \
630Sstevel@tonic-gate "Copyright 2001 SMI.\n" \
640Sstevel@tonic-gate "Version 1.0\n";
650Sstevel@tonic-gate
660Sstevel@tonic-gate /* ms timeout between successive cmds */
670Sstevel@tonic-gate static int timeout = DEFAULT_CMD_TIMEOUT;
680Sstevel@tonic-gate
690Sstevel@tonic-gate /* ms interval between successive scans */
700Sstevel@tonic-gate static int interval = DEFAULT_SCAN_INTERVAL;
710Sstevel@tonic-gate
720Sstevel@tonic-gate /* global signal flag */
730Sstevel@tonic-gate static int sigterm = 0;
740Sstevel@tonic-gate
750Sstevel@tonic-gate /* print all cmd data on stdout in server mode flag */
760Sstevel@tonic-gate static int Po = 0;
770Sstevel@tonic-gate
780Sstevel@tonic-gate /* count of scans performed in server mode */
790Sstevel@tonic-gate static long scans_done = 0;
800Sstevel@tonic-gate
810Sstevel@tonic-gate /* name of rds logging file */
820Sstevel@tonic-gate static char *log_file = NULL;
830Sstevel@tonic-gate
840Sstevel@tonic-gate /* enable microstate accounting flag */
850Sstevel@tonic-gate int mo = 0;
860Sstevel@tonic-gate
870Sstevel@tonic-gate /* name of stored data file */
880Sstevel@tonic-gate char *ltdb_file = NULL;
890Sstevel@tonic-gate
900Sstevel@tonic-gate
910Sstevel@tonic-gate /* mutex lock for data lists */
920Sstevel@tonic-gate pthread_mutex_t listLock = PTHREAD_MUTEX_INITIALIZER;
930Sstevel@tonic-gate
940Sstevel@tonic-gate /* mutex lock for log */
950Sstevel@tonic-gate pthread_mutex_t logLock = PTHREAD_MUTEX_INITIALIZER;
960Sstevel@tonic-gate
970Sstevel@tonic-gate /* identifiers for the various threads */
980Sstevel@tonic-gate static pthread_t scanner = 0;
990Sstevel@tonic-gate static pthread_t server = 0;
1000Sstevel@tonic-gate static pthread_t master = 0;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate * Clean up calling thread's state.
1050Sstevel@tonic-gate */
1060Sstevel@tonic-gate static void
thread_cleanup()1070Sstevel@tonic-gate thread_cleanup()
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate pthread_t this = pthread_self();
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate if (pthread_equal(this, server)) {
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate /* shut down the command protocol */
1140Sstevel@tonic-gate (void) fprintf(stderr,
1150Sstevel@tonic-gate "cleanup_state: server thread shutdown\n");
1160Sstevel@tonic-gate log_msg("server thread shutdown init\n");
1170Sstevel@tonic-gate wr_error(errmsg);
1180Sstevel@tonic-gate log_msg("server thread shutdown complete\n");
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate } else if (pthread_equal(this, scanner)) {
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate /* shut down the scanner */
1230Sstevel@tonic-gate (void) fprintf(stderr,
1240Sstevel@tonic-gate "cleanup_state: scanner thread shutdown\n");
1250Sstevel@tonic-gate log_msg("scanner thread shutdown init\n");
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate log_msg("Waiting for server thread %d join from %d\n",
1280Sstevel@tonic-gate (int)server, (int)this);
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate if (pthread_join(server, NULL) != 0) {
1310Sstevel@tonic-gate int e = errno;
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate perror("server join (cleanup)");
1340Sstevel@tonic-gate log_msg("server join (cleanup) failed with %d\n", e);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate log_msg("Server thread joined %d.\n", (int)this);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate monitor_stop();
1400Sstevel@tonic-gate log_msg("scanner thread shutdown complete\n");
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate } else if (pthread_equal(this, master)) {
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate (void) fprintf(stderr,
1450Sstevel@tonic-gate "cleanup_state: master thread shutdown\n");
1460Sstevel@tonic-gate log_msg("master thread shutdown\n");
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate } else {
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate (void) fprintf(stderr,
1510Sstevel@tonic-gate "cleanup_state: unknown thread id %d\n", (int)this);
1520Sstevel@tonic-gate log_msg("unknown thread %d shutdown\n", (int)this);
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate * Called by any of the threads, this should set state
1600Sstevel@tonic-gate * that the other threads will pick up so they will (eventually)
1610Sstevel@tonic-gate * shut themselves down cleanly, then call pthread_exit
1620Sstevel@tonic-gate * to properly shut down the calling thread.
1630Sstevel@tonic-gate * The calling thread will exit with its code set to 1.
1640Sstevel@tonic-gate */
1650Sstevel@tonic-gate static void
generic_exit(char * msg,int status)1660Sstevel@tonic-gate generic_exit(char *msg, int status)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate char wb[256];
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /* cannot be on the stack since thread terminates with pthread_exit */
1710Sstevel@tonic-gate static int retcode = 0;
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate retcode = status;
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /* worker-specific cleanup */
1760Sstevel@tonic-gate thread_cleanup();
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate /* announce the calling thread's demise */
1790Sstevel@tonic-gate (void) snprintf(wb, sizeof (wb) - 2, "(%d) %s",
1800Sstevel@tonic-gate (int)pthread_self(), msg);
1810Sstevel@tonic-gate log_msg(wb);
1820Sstevel@tonic-gate (void) fprintf(stderr, "%s", wb);
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate /* everybody checks this periodically */
1850Sstevel@tonic-gate sigterm = 1;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate log_msg("calling thread_exit() from %d\n", (int)pthread_self());
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate /* return status as the calling thread's exit code */
1900Sstevel@tonic-gate pthread_exit(&retcode);
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate * Called by any of the threads, this should set state
1970Sstevel@tonic-gate * that the other threads will pick up so they will (eventually)
1980Sstevel@tonic-gate * shut themselves down cleanly, then call pthread_exit
1990Sstevel@tonic-gate * to properly shut down the calling thread.
2000Sstevel@tonic-gate * The calling thread will exit with its code set to 1.
2010Sstevel@tonic-gate */
2020Sstevel@tonic-gate void
err_exit()2030Sstevel@tonic-gate err_exit()
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate generic_exit(errmsg, 1);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate * Called by any of the threads, this should set state
2110Sstevel@tonic-gate * that the other threads will pick up so they will (eventually)
2120Sstevel@tonic-gate * shut themselves down cleanly, then call pthread_exit
2130Sstevel@tonic-gate * to properly shut down the calling thread.
2140Sstevel@tonic-gate * The calling thread will exit with its code set to 0.
2150Sstevel@tonic-gate */
2160Sstevel@tonic-gate static void
ok_exit()2170Sstevel@tonic-gate ok_exit()
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate generic_exit("Normal exit.\n", 0);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate static void
usage()2240Sstevel@tonic-gate usage()
2250Sstevel@tonic-gate {
2260Sstevel@tonic-gate (void) printf("rds [ options ]\n" \
2270Sstevel@tonic-gate "-u\t\t- print stats for all users\n" \
2280Sstevel@tonic-gate "-U<uid>\t\t- print stats for <uid>\n" \
2290Sstevel@tonic-gate "-j\t\t- print stats for all projects\n" \
2300Sstevel@tonic-gate "-J<projid>\t- print stats for <projid>\n" \
2310Sstevel@tonic-gate "-p\t\t- print stats for all processes\n" \
2320Sstevel@tonic-gate "-P <pid>\t- print stats for <pid>\n" \
2330Sstevel@tonic-gate "-m\t\t- enable microstate accounting\n" \
2340Sstevel@tonic-gate "-a\t\t- run in server mode\n" \
2350Sstevel@tonic-gate "-t<time>\t- set command timeout to <time>\n" \
2360Sstevel@tonic-gate "-i<interval>\t- set interval between scans to <time>\n" \
2370Sstevel@tonic-gate "-f<file>\t- use <file> to save/restore state\n" \
2380Sstevel@tonic-gate "-d\t\t- in server mode print stats on stdout\n" \
2390Sstevel@tonic-gate "-L<file>|stderr - write log messages into <file> or stderr\n" \
2400Sstevel@tonic-gate "-v\t\t- print rds version\n");
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate * Initiate the rds command protocol from the server side.
2460Sstevel@tonic-gate * Emits the header and version strings.
2470Sstevel@tonic-gate */
2480Sstevel@tonic-gate static void
start_protocol()2490Sstevel@tonic-gate start_protocol()
2500Sstevel@tonic-gate {
2510Sstevel@tonic-gate /* emit version and header strings */
2520Sstevel@tonic-gate if (wr_string(greeting) != 0)
2530Sstevel@tonic-gate err_exit();
2540Sstevel@tonic-gate if (wr_phead() != 0)
2550Sstevel@tonic-gate err_exit();
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate /*
2600Sstevel@tonic-gate * Emit the "not ready" message and a prompt.
2610Sstevel@tonic-gate */
2620Sstevel@tonic-gate static void
notready()2630Sstevel@tonic-gate notready()
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate (void) wr_string(NOTREADY_RESPONSE);
2660Sstevel@tonic-gate (void) wr_string("\n");
2670Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate * process_cmds() implements the rds server running in threaded mode.
2730Sstevel@tonic-gate *
2740Sstevel@tonic-gate * It assumes that the /proc scanner is running in another thread and
2750Sstevel@tonic-gate * guarding access to critical sections.
2760Sstevel@tonic-gate *
2770Sstevel@tonic-gate * This function writes version and header to the output stream and waits
2780Sstevel@tonic-gate * for commands on the input stream.
2790Sstevel@tonic-gate *
2800Sstevel@tonic-gate * Each received command may block on a mutex while the scanner thread is
2810Sstevel@tonic-gate * updating.
2820Sstevel@tonic-gate *
2830Sstevel@tonic-gate * If the timeout expires without receiving a command, it will write an
2840Sstevel@tonic-gate * error message and terminate. A received command resets the timeout.
2850Sstevel@tonic-gate *
2860Sstevel@tonic-gate * Each command is acknowledged with a prompt.
2870Sstevel@tonic-gate */
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*ARGSUSED*/
2900Sstevel@tonic-gate static void *
process_cmds(void * p)2910Sstevel@tonic-gate process_cmds(void *p)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate fd_set readfs;
2940Sstevel@tonic-gate struct timeval timev;
2950Sstevel@tonic-gate int interval_cnt = timeout / interval;
2960Sstevel@tonic-gate int ret;
2970Sstevel@tonic-gate char *cmd;
2980Sstevel@tonic-gate hrtime_t t1, t2, wt1, wt2;
2990Sstevel@tonic-gate double d;
3000Sstevel@tonic-gate int cmd_is_noop;
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /* start the protocol so the client knows we're alive */
3030Sstevel@tonic-gate start_protocol();
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /* establish timeout value */
3060Sstevel@tonic-gate timev.tv_sec = interval / 1000;
3070Sstevel@tonic-gate timev.tv_usec = (interval - (timev.tv_sec * 1000)) * 1000;
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate /* initialize stdin object */
3100Sstevel@tonic-gate (void) FD_ZERO(&readfs);
3110Sstevel@tonic-gate FD_SET(STDIN_FILENO, &readfs);
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /* emit initial prompt */
3140Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate while (interval_cnt > 0) {
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /* time to shut down, exit gracefully */
3190Sstevel@tonic-gate if (sigterm == 1) {
3200Sstevel@tonic-gate break; /* ok_exit(); */
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /* check for stdin status */
3240Sstevel@tonic-gate FD_SET(STDIN_FILENO, &readfs);
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /* block on stdin, max timeout */
3270Sstevel@tonic-gate if ((ret = select(1, &readfs, NULL, NULL, &timev)) == 0) {
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /* timed out waiting for a command */
3300Sstevel@tonic-gate --interval_cnt;
3310Sstevel@tonic-gate continue;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /* if interrupted system call then exit gracefully */
3350Sstevel@tonic-gate if (ret == -1 && errno == EINTR) {
3360Sstevel@tonic-gate log_msg("select() interrupted\n");
3370Sstevel@tonic-gate ok_exit();
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate /* weird error condition */
3410Sstevel@tonic-gate if (ret != 1) {
3420Sstevel@tonic-gate perror("RDS Select error");
3430Sstevel@tonic-gate log_msg("select() error = %d\n", errno);
3440Sstevel@tonic-gate continue;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /* process whatever is waiting on stdin */
3480Sstevel@tonic-gate if (FD_ISSET(STDIN_FILENO, &readfs)) {
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate cmd_is_noop = 0;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate /* try to parse out a valid command */
3530Sstevel@tonic-gate if ((cmd = r_cmd()) == NULL) {
3540Sstevel@tonic-gate err_exit();
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate log_msg("received '%s' command\n", cmd);
3570Sstevel@tonic-gate t1 = gethrtime();
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /* handle the various commands */
3600Sstevel@tonic-gate if (strcmp(cmd, CMD_EXIT) == 0) {
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /* exit now */
3630Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
3640Sstevel@tonic-gate ok_exit();
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate } else if (strcmp(cmd, CRETURN) == 0) {
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate /* null command */
3690Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
3700Sstevel@tonic-gate ++cmd_is_noop;
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate } else if (strcmp(cmd, CMD_ALIVE) == 0) {
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate /* keepalive, another null command */
3750Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
3760Sstevel@tonic-gate ++cmd_is_noop;
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETALL) == 0) {
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate /* get all project/user data */
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate * If the first scan has not yet
3840Sstevel@tonic-gate * completed, notify the requester and
3850Sstevel@tonic-gate * wait for a new command. The
3860Sstevel@tonic-gate * command timeout counter is
3870Sstevel@tonic-gate * suspended until the next command
3880Sstevel@tonic-gate * arrives.
3890Sstevel@tonic-gate */
3900Sstevel@tonic-gate if (scans_done == 0) {
3910Sstevel@tonic-gate notready();
3920Sstevel@tonic-gate continue;
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate /* grab the mutex */
3960Sstevel@tonic-gate wt1 = gethrtime();
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
3990Sstevel@tonic-gate &listLock)) == 0) {
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate wt2 = gethrtime();
4020Sstevel@tonic-gate d = (double)
4030Sstevel@tonic-gate (wt2 - wt1) / 1000000000.0;
4040Sstevel@tonic-gate log_msg("Server lock wait"
4050Sstevel@tonic-gate " was %1.5f sec\n", d);
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate if (wr_lshead(5) != 0)
4080Sstevel@tonic-gate err_exit();
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate if (list_write(L_AC_USR, Po) == -1)
4110Sstevel@tonic-gate break;
4120Sstevel@tonic-gate if (list_write(L_USR_SI, Po) == -1)
4130Sstevel@tonic-gate break;
4140Sstevel@tonic-gate if (list_write(L_AC_PRJ, Po) == -1)
4150Sstevel@tonic-gate break;
4160Sstevel@tonic-gate if (list_write(L_PRJ_SI, Po) == -1)
4170Sstevel@tonic-gate break;
4180Sstevel@tonic-gate if (list_write(L_SYSTEM, Po) == -1)
4190Sstevel@tonic-gate break;
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate /* release the mutex */
4220Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
4230Sstevel@tonic-gate &listLock)) != 0) {
4240Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \
4250Sstevel@tonic-gate "failed with %d\n", ret);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate } else {
4290Sstevel@tonic-gate log_msg("pthread_mutex_lock failed" \
4300Sstevel@tonic-gate "with %d\n", ret);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETPL) == 0) {
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate /* get all process data (deprecated?) */
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate if (scans_done == 0) {
4400Sstevel@tonic-gate notready();
4410Sstevel@tonic-gate continue;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate /* grab the mutex */
4450Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
4460Sstevel@tonic-gate &listLock)) == 0) {
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate if (wr_lshead(1) != 0)
4490Sstevel@tonic-gate err_exit();
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate if (list_write(L_PRC_SI, Po) == -1)
4520Sstevel@tonic-gate break;
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /* release the mutex */
4550Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
4560Sstevel@tonic-gate &listLock)) != 0) {
4570Sstevel@tonic-gate log_msg("pthread_mutex_unlock"\
4580Sstevel@tonic-gate "failed with %d\n", ret);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate } else {
4620Sstevel@tonic-gate log_msg("pthread_mutex_lock"\
4630Sstevel@tonic-gate "failed with %d\n", ret);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETUL) == 0) {
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate /* get the active user list */
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate if (scans_done == 0) {
4730Sstevel@tonic-gate notready();
4740Sstevel@tonic-gate continue;
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate /* grab the mutex */
4780Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
4790Sstevel@tonic-gate &listLock)) == 0) {
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate if (wr_lshead(1) != 0)
4820Sstevel@tonic-gate err_exit();
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate if (list_write(L_USR_SI, Po) == -1)
4860Sstevel@tonic-gate break;
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate /* release the mutex */
4890Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
4900Sstevel@tonic-gate &listLock)) != 0) {
4910Sstevel@tonic-gate log_msg("pthread_mutex_unlock"\
4920Sstevel@tonic-gate "failed with %d\n", ret);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate } else {
4960Sstevel@tonic-gate log_msg("pthread_mutex_lock" \
4970Sstevel@tonic-gate "failed with %d\n", ret);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETAUL) == 0) {
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate /* get data for a particular user */
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate if (scans_done == 0) {
5070Sstevel@tonic-gate notready();
5080Sstevel@tonic-gate continue;
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* grab the mutex */
5120Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
5130Sstevel@tonic-gate &listLock)) == 0) {
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate if (wr_lshead(1) != 0)
5160Sstevel@tonic-gate err_exit();
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate if (list_write(L_AC_USR, Po) == -1)
5190Sstevel@tonic-gate break;
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate /* release the mutex */
5220Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
5230Sstevel@tonic-gate &listLock)) != 0) {
5240Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \
5250Sstevel@tonic-gate "failed with %d\n", ret);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate } else {
5290Sstevel@tonic-gate log_msg("pthread_mutex_lock" \
5300Sstevel@tonic-gate "failed with %d\n", ret);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETJL) == 0) {
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate if (scans_done == 0) {
5380Sstevel@tonic-gate notready();
5390Sstevel@tonic-gate continue;
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate /* grab the mutex */
5430Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
5440Sstevel@tonic-gate &listLock)) == 0) {
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate if (wr_lshead(1) != 0)
5470Sstevel@tonic-gate err_exit();
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate /* grab the mutex here */
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate if (list_write(L_PRJ_SI, Po) == -1)
5520Sstevel@tonic-gate break;
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate /* release the mutex */
5550Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
5560Sstevel@tonic-gate &listLock)) != 0) {
5570Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \
5580Sstevel@tonic-gate "failed with %d\n", ret);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate } else {
5620Sstevel@tonic-gate log_msg("pthread_mutex_lock" \
5630Sstevel@tonic-gate "failed with %d\n", ret);
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETAJL) == 0) {
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate if (scans_done == 0) {
5710Sstevel@tonic-gate notready();
5720Sstevel@tonic-gate continue;
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate /* grab the mutex */
5760Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
5770Sstevel@tonic-gate &listLock)) == 0) {
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate if (wr_lshead(1) != 0)
5800Sstevel@tonic-gate err_exit();
5810Sstevel@tonic-gate
5820Sstevel@tonic-gate if (list_write(L_AC_PRJ, Po) == -1)
5830Sstevel@tonic-gate break;
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /* release the mutex */
5860Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
5870Sstevel@tonic-gate &listLock)) != 0) {
5880Sstevel@tonic-gate log_msg("pthread_mutex_unlock" \
5890Sstevel@tonic-gate "failed with %d\n", ret);
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate } else {
5930Sstevel@tonic-gate log_msg("pthread_mutex_lock" \
5940Sstevel@tonic-gate "failed with %d\n", ret);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate } else if (strcmp(cmd, CMD_GETASL) == 0) {
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate if (scans_done == 0) {
6020Sstevel@tonic-gate notready();
6030Sstevel@tonic-gate continue;
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /* grab the mutex */
6070Sstevel@tonic-gate if ((ret = pthread_mutex_lock(
6080Sstevel@tonic-gate &listLock)) == 0) {
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate if (wr_lshead(1) != 0)
6110Sstevel@tonic-gate err_exit();
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate if (list_write(L_SYSTEM, Po) == -1)
6140Sstevel@tonic-gate break;
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate /* release the mutex */
6170Sstevel@tonic-gate if ((ret = pthread_mutex_unlock(
6180Sstevel@tonic-gate &listLock)) != 0) {
6190Sstevel@tonic-gate log_msg("pthread_mutex_unlock"
6200Sstevel@tonic-gate "failed with %d\n", ret);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate } else {
6240Sstevel@tonic-gate log_msg("pthread_mutex_lock"
6250Sstevel@tonic-gate "failed with %d\n", ret);
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate (void) wr_prompt(PROMPT_OK);
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate } else {
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /* bad command */
6330Sstevel@tonic-gate (void) wr_prompt(PROMPT_WHAT);
6340Sstevel@tonic-gate format_err("RDS protocol error:"
6350Sstevel@tonic-gate "unknown command");
6360Sstevel@tonic-gate ++cmd_is_noop;
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if (!cmd_is_noop) {
6410Sstevel@tonic-gate t2 = gethrtime();
6420Sstevel@tonic-gate d = (double)(t2 - t1) / 1000000000.0;
6430Sstevel@tonic-gate log_msg("Command took %2.3f sec"
6440Sstevel@tonic-gate " (%ld scans done)\n",
6450Sstevel@tonic-gate d, scans_done);
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate /* reset the interval counter for timeout */
6490Sstevel@tonic-gate interval_cnt = timeout / interval;
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate continue;
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /* timed out, one less interval to wait */
6550Sstevel@tonic-gate --interval_cnt;
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate /* timed out, print message */
6590Sstevel@tonic-gate if (interval_cnt == 0) {
6600Sstevel@tonic-gate format_err("%s %d sec. left", TIMEOUT_MSG, timeout / 1000);
6610Sstevel@tonic-gate err_exit();
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate /* clean exit */
6650Sstevel@tonic-gate log_msg("process_cmds exits\n");
6660Sstevel@tonic-gate ok_exit(); /* calls pthread_exit() */
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate return (NULL);
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate * The thread procedure for the /proc scanner.
6740Sstevel@tonic-gate * Does a full scan of /proc, then sleeps for a specified time.
6750Sstevel@tonic-gate *
6760Sstevel@tonic-gate * The specified time ('interval') is adjusted according to
6770Sstevel@tonic-gate * the average of the last three scan times.
6780Sstevel@tonic-gate * The sleep time is increase if the average scan duration time
6790Sstevel@tonic-gate * exceeds a threshold. The threshold is set to 50% of the current
6800Sstevel@tonic-gate * sleep time.
6810Sstevel@tonic-gate * The sleep time is decreased in a similar way.
6820Sstevel@tonic-gate *
6830Sstevel@tonic-gate * The update of the project and user lists is guarded by aggregate_list_mutex.
6840Sstevel@tonic-gate * The update of the process list is guarded by process_list_mutex.
6850Sstevel@tonic-gate */
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate /*ARGSUSED*/
6880Sstevel@tonic-gate static void *
scanprocfs(void * p)6890Sstevel@tonic-gate scanprocfs(void *p)
6900Sstevel@tonic-gate {
6910Sstevel@tonic-gate hrtime_t t1;
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate double d0; /* duration of the for last scan */
6940Sstevel@tonic-gate double d1; /* duration of the last scan */
6950Sstevel@tonic-gate double d2; /* duration of current scan */
6960Sstevel@tonic-gate double ad; /* average duration of the last three scans */
6970Sstevel@tonic-gate double threshold_up; /* threshold for increasing scan duration */
6980Sstevel@tonic-gate double threshold_down; /* threshold for decreasing scan duration */
6990Sstevel@tonic-gate double thf = 0.5; /* */
7000Sstevel@tonic-gate int new_interval = interval;
7010Sstevel@tonic-gate int time_to_sleep;
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate threshold_up = new_interval * thf;
7040Sstevel@tonic-gate threshold_down = 0;
7050Sstevel@tonic-gate d0 = d1 = d2 = ad = 0;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate while (sigterm != 1) {
7090Sstevel@tonic-gate t1 = gethrtime();
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate if (monitor_update() != 0)
7120Sstevel@tonic-gate err_exit();
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate ++scans_done;
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate /* make sure we're sleeping a reasonable amount of time */
7170Sstevel@tonic-gate d0 = d1; d1 = d2;
7180Sstevel@tonic-gate d2 = (gethrtime() - t1) / 1000000.0;
7190Sstevel@tonic-gate ad = (d0 + d1 + d2) / 3.0;
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate if (threshold_up < ad) {
7220Sstevel@tonic-gate /* increase the new_interval in 1000 ms steps */
7230Sstevel@tonic-gate new_interval += (int)((ad - threshold_up) / thf);
7240Sstevel@tonic-gate if (new_interval > MAXIMAL_SCAN_INTERVAL)
7250Sstevel@tonic-gate new_interval = MAXIMAL_SCAN_INTERVAL;
7260Sstevel@tonic-gate if ((new_interval % 1000) > 500)
7270Sstevel@tonic-gate new_interval += 500;
7280Sstevel@tonic-gate new_interval = (new_interval / 1000) * 1000;
7290Sstevel@tonic-gate /* pull up the thresholds */
7300Sstevel@tonic-gate threshold_down = threshold_up;
7310Sstevel@tonic-gate threshold_up = new_interval * thf;
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate if (threshold_down > ad) {
7350Sstevel@tonic-gate /* decrease the new_interval in 1000 ms steps */
7360Sstevel@tonic-gate new_interval -= (int)((threshold_down - ad) / thf);
7370Sstevel@tonic-gate if ((new_interval % 1000) > 500)
7380Sstevel@tonic-gate new_interval += 500;
7390Sstevel@tonic-gate new_interval = (new_interval / 1000) * 1000;
7400Sstevel@tonic-gate /* pull down the thresholds */
7410Sstevel@tonic-gate if (new_interval < interval) {
7420Sstevel@tonic-gate /* just as at the beginning */
7430Sstevel@tonic-gate new_interval = interval;
7440Sstevel@tonic-gate threshold_down = 0;
7450Sstevel@tonic-gate threshold_up = new_interval * thf;
7460Sstevel@tonic-gate } else {
7470Sstevel@tonic-gate threshold_up = threshold_down;
7480Sstevel@tonic-gate threshold_down = new_interval * thf;
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate log_msg("scan %.0f ms, ad %.0f ms, thold_up %.0f ms,"
7530Sstevel@tonic-gate " thold_down %.0f ms, interval %d ms\n",
7540Sstevel@tonic-gate d2, ad, threshold_up, threshold_down, new_interval);
7550Sstevel@tonic-gate log_msg("%d files open\n", fd_count());
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate time_to_sleep = new_interval;
7580Sstevel@tonic-gate while (time_to_sleep > 0) {
7590Sstevel@tonic-gate napms(1000);
7600Sstevel@tonic-gate time_to_sleep -= 1000;
7610Sstevel@tonic-gate if (sigterm == 1)
7620Sstevel@tonic-gate break;
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate log_msg("scanprocfs exits\n");
7670Sstevel@tonic-gate ok_exit();
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate return (NULL);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate static void
sig_rds(int sig)7730Sstevel@tonic-gate sig_rds(int sig)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate log_msg("caught signal #%d\n", sig);
7760Sstevel@tonic-gate switch (sig) {
7770Sstevel@tonic-gate case SIGINT:
7780Sstevel@tonic-gate case SIGTERM:
7790Sstevel@tonic-gate sigterm = 1;
7800Sstevel@tonic-gate break;
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate /*
7860Sstevel@tonic-gate * Run the command processor, with the /proc scanner and rds command processor
7870Sstevel@tonic-gate * in separate threads.
7880Sstevel@tonic-gate *
7890Sstevel@tonic-gate * Initializes the mutex as a side effect.
7900Sstevel@tonic-gate *
7910Sstevel@tonic-gate * Returns on exit of the command process or as a result of a signal.
7920Sstevel@tonic-gate */
7930Sstevel@tonic-gate static void
runserver()7940Sstevel@tonic-gate runserver()
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate int rv;
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate /* keep track of main()'s thread */
7990Sstevel@tonic-gate master = pthread_self();
8000Sstevel@tonic-gate log_msg("master thread = %d\n", (int)master);
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate /* initialize the mutexes for later use */
8030Sstevel@tonic-gate rv = pthread_mutex_init(&listLock, NULL);
8040Sstevel@tonic-gate if (rv != 0) {
8050Sstevel@tonic-gate (void) sprintf(errmsg, "Mutex init failed with %d", rv);
8060Sstevel@tonic-gate err_exit();
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate rv = pthread_mutex_init(&listLock, NULL);
8100Sstevel@tonic-gate if (rv != 0) {
8110Sstevel@tonic-gate (void) sprintf(errmsg, "Mutex init failed with %d", rv);
8120Sstevel@tonic-gate err_exit();
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate log_msg("pthread_mutex_init returns %d\n", rv);
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate /* launch the command processor in its thread */
8180Sstevel@tonic-gate rv = pthread_create(&server, NULL, process_cmds, NULL);
8190Sstevel@tonic-gate if (rv != 0) {
8200Sstevel@tonic-gate (void) sprintf(errmsg,
8210Sstevel@tonic-gate "Server thread create failed with %d", rv);
8220Sstevel@tonic-gate err_exit();
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate log_msg("Server pthread_create = %d returns %d\n",
8260Sstevel@tonic-gate (int)server, rv);
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate /* launch the scanner in its thread */
8300Sstevel@tonic-gate rv = pthread_create(&scanner, NULL, scanprocfs, NULL);
8310Sstevel@tonic-gate if (rv != 0) {
8320Sstevel@tonic-gate (void) sprintf(errmsg,
8330Sstevel@tonic-gate "Scanner thread create failed with %d", rv);
8340Sstevel@tonic-gate err_exit();
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate log_msg("Scanner pthread_create = %d returns %d\n",
8370Sstevel@tonic-gate (int)scanner, rv);
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate /* nothing much else to do here */
8410Sstevel@tonic-gate while (sigterm != 1)
8420Sstevel@tonic-gate (void) sleep(1);
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate /* wait for the scanner & server threads to shut down */
8450Sstevel@tonic-gate log_msg("Waiting for scanner thread %d join from %d\n",
8460Sstevel@tonic-gate (int)scanner, (int)pthread_self());
8470Sstevel@tonic-gate if (pthread_join(scanner, NULL) != 0) {
8480Sstevel@tonic-gate int e = errno;
8490Sstevel@tonic-gate perror("scanner join");
8500Sstevel@tonic-gate log_msg("scanner join failed with %d\n", e);
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate log_msg("Scanner thread joined.\n");
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate /* finish cleaning up global state */
8550Sstevel@tonic-gate (void) pthread_mutex_destroy(&listLock);
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate log_msg("Global cleanup completed.\n");
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate int
main(int argc,char * argv[])8620Sstevel@tonic-gate main(int argc, char *argv[])
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate int i, uo = 0, jo = 0, po = 0, do_server_mode = 0,
8650Sstevel@tonic-gate selected = 0;
8660Sstevel@tonic-gate int lo_arg = 1;
8670Sstevel@tonic-gate int uid = -1, pid = -1, jid = -1;
8680Sstevel@tonic-gate int rv;
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate /* parse args */
8710Sstevel@tonic-gate while ((i = getopt(argc, argv, "uU:jJ:pP:mat:i:l:f:dvL:")) != EOF)
8720Sstevel@tonic-gate switch (i) {
8730Sstevel@tonic-gate case 'U':
8740Sstevel@tonic-gate uid = atoi(optarg);
8750Sstevel@tonic-gate uo = 1; selected = 1;
8760Sstevel@tonic-gate break;
8770Sstevel@tonic-gate case 'u':
8780Sstevel@tonic-gate uo = 1; selected = 1;
8790Sstevel@tonic-gate break;
8800Sstevel@tonic-gate case 'J':
8810Sstevel@tonic-gate jid = atoi(optarg);
8820Sstevel@tonic-gate jo = 1; selected = 1;
8830Sstevel@tonic-gate break;
8840Sstevel@tonic-gate case 'j':
8850Sstevel@tonic-gate jo = 1; selected = 1;
8860Sstevel@tonic-gate break;
8870Sstevel@tonic-gate case 'P':
8880Sstevel@tonic-gate pid = atoi(optarg);
8890Sstevel@tonic-gate po = 1; selected = 1;
8900Sstevel@tonic-gate break;
8910Sstevel@tonic-gate case 'p':
8920Sstevel@tonic-gate po = 1; selected = 1;
8930Sstevel@tonic-gate break;
8940Sstevel@tonic-gate case 'a':
8950Sstevel@tonic-gate do_server_mode = 1;
8960Sstevel@tonic-gate break;
8970Sstevel@tonic-gate case 'l':
8980Sstevel@tonic-gate if ((lo_arg = atoi(optarg)) == 0) {
8990Sstevel@tonic-gate usage();
9000Sstevel@tonic-gate exit(1);
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate break;
9030Sstevel@tonic-gate case 'd':
9040Sstevel@tonic-gate Po = 1;
9050Sstevel@tonic-gate break;
9060Sstevel@tonic-gate case 't':
9070Sstevel@tonic-gate if ((timeout = atoi(optarg)) < 1000) {
9080Sstevel@tonic-gate usage();
9090Sstevel@tonic-gate exit(1);
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate break;
9120Sstevel@tonic-gate case 'i':
9130Sstevel@tonic-gate if ((interval = atoi(optarg)) < 100) {
9140Sstevel@tonic-gate usage();
9150Sstevel@tonic-gate exit(1);
9160Sstevel@tonic-gate }
9170Sstevel@tonic-gate break;
9180Sstevel@tonic-gate case 'f':
9190Sstevel@tonic-gate ltdb_file = optarg;
9200Sstevel@tonic-gate break;
9210Sstevel@tonic-gate case 'L':
9220Sstevel@tonic-gate log_file = optarg;
9230Sstevel@tonic-gate break;
9240Sstevel@tonic-gate case 'm':
9250Sstevel@tonic-gate mo = 1;
9260Sstevel@tonic-gate break;
9270Sstevel@tonic-gate case 'v': (void) printf(RDS_VERSION);
9280Sstevel@tonic-gate exit(1);
9290Sstevel@tonic-gate break;
9300Sstevel@tonic-gate case '?':
9310Sstevel@tonic-gate usage();
9320Sstevel@tonic-gate exit(1);
9330Sstevel@tonic-gate default:
9340Sstevel@tonic-gate usage();
9350Sstevel@tonic-gate exit(1);
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate /* set handlers */
9400Sstevel@tonic-gate (void) signal(SIGINT, sig_rds);
9410Sstevel@tonic-gate (void) signal(SIGTERM, sig_rds);
9420Sstevel@tonic-gate (void) sigignore(SIGPIPE);
9430Sstevel@tonic-gate
944*1914Scasper (void) enable_extended_FILE_stdio(-1, -1);
945*1914Scasper
9460Sstevel@tonic-gate /* initialize the log mutex */
9470Sstevel@tonic-gate rv = pthread_mutex_init(&logLock, NULL);
9480Sstevel@tonic-gate if (rv != 0) {
9490Sstevel@tonic-gate (void) sprintf(errmsg, "Mutex init failed with %d", rv);
9500Sstevel@tonic-gate err_exit();
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate if (log_file != NULL)
9540Sstevel@tonic-gate log_open(log_file);
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate if (do_server_mode == 1) {
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate /*
9590Sstevel@tonic-gate * Initialize list data structures, possibly
9600Sstevel@tonic-gate * reading saved data.
9610Sstevel@tonic-gate *
9620Sstevel@tonic-gate * As a side effect this messes with the protocol
9630Sstevel@tonic-gate * state since the list reader pretends it's reading
9640Sstevel@tonic-gate * the protocol.
9650Sstevel@tonic-gate *
9660Sstevel@tonic-gate * A problem here is that we cannot start the server
9670Sstevel@tonic-gate * thread until this has completed because it will try to
9680Sstevel@tonic-gate * use the same state hidden inside the protocol code.
9690Sstevel@tonic-gate *
9700Sstevel@tonic-gate * The consequence is that this may occupy the main
9710Sstevel@tonic-gate * thread for an arbitrarily long time *before* the server
9720Sstevel@tonic-gate * thread is started and the app becomes able to respond
9730Sstevel@tonic-gate * to commands.
9740Sstevel@tonic-gate */
9750Sstevel@tonic-gate if (monitor_start() != 0)
9760Sstevel@tonic-gate err_exit();
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /* Open pipes in and out for the command protocol */
9790Sstevel@tonic-gate if (open_prot(STDOUT_FILENO, "w") == -1) {
9800Sstevel@tonic-gate err_exit();
9810Sstevel@tonic-gate }
9820Sstevel@tonic-gate if (open_prot(STDIN_FILENO, "r") == -1) {
9830Sstevel@tonic-gate err_exit();
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate /* Waits for the child threads to end */
9870Sstevel@tonic-gate runserver();
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate /* Close command I/O pipes */
9900Sstevel@tonic-gate close_prot();
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate } else {
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate if (monitor_start() != 0)
9950Sstevel@tonic-gate err_exit();
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate for (i = 0; i < lo_arg; i ++) {
9980Sstevel@tonic-gate if (sigterm == 1)
9990Sstevel@tonic-gate break;
10000Sstevel@tonic-gate if (monitor_update() != 0)
10010Sstevel@tonic-gate err_exit();
10020Sstevel@tonic-gate if (selected == 0 || uo == 1) {
10030Sstevel@tonic-gate list_print(&users, uid);
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate if (selected == 0 || jo == 1) {
10060Sstevel@tonic-gate list_print(&projects, jid);
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate if (selected == 0 || po == 1) {
10090Sstevel@tonic-gate list_print(&processes, pid);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate if (i < lo_arg - 1)
10120Sstevel@tonic-gate napms(interval);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /* clean up the log stuff at the very end */
10170Sstevel@tonic-gate log_close();
10180Sstevel@tonic-gate (void) pthread_mutex_destroy(&logLock);
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate return (0);
10210Sstevel@tonic-gate }
1022