Home | History | Annotate | Download | only in pwait
      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 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <stdio.h>
     29 #include <stdio_ext.h>
     30 #include <ctype.h>
     31 #include <stdlib.h>
     32 #include <unistd.h>
     33 #include <fcntl.h>
     34 #include <string.h>
     35 #include <dirent.h>
     36 #include <errno.h>
     37 #include <sys/types.h>
     38 #include <stropts.h>
     39 #include <poll.h>
     40 #include <procfs.h>
     41 #include <sys/resource.h>
     42 
     43 static int count_my_files();
     44 static char *command;
     45 
     46 /* slop to account for extra file descriptors opened by libraries we call */
     47 #define	SLOP	5
     48 
     49 int
     50 main(int argc, char **argv)
     51 {
     52 	unsigned long remain = 0;
     53 	struct pollfd *pollfd;
     54 	struct pollfd *pfd;
     55 	struct rlimit rlim;
     56 	char *arg;
     57 	unsigned i;
     58 	int verbose = 0;
     59 
     60 	if ((command = strrchr(argv[0], '/')) != NULL)
     61 		command++;
     62 	else
     63 		command = argv[0];
     64 
     65 	argc--;
     66 	argv++;
     67 
     68 	if (argc > 0 && strcmp(argv[0], "-v") == 0) {
     69 		verbose = 1;
     70 		argc--;
     71 		argv++;
     72 	}
     73 
     74 	if (argc <= 0) {
     75 		(void) fprintf(stderr, "usage:\t%s [-v] pid ...\n", command);
     76 		(void) fprintf(stderr, "  (wait for processes to terminate)\n");
     77 		(void) fprintf(stderr,
     78 			"  -v: verbose; report terminations to standard out\n");
     79 		return (2);
     80 	}
     81 
     82 	/* make sure we have enough file descriptors */
     83 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
     84 		int nfiles = count_my_files();
     85 
     86 		if (rlim.rlim_cur < argc + nfiles + SLOP) {
     87 			rlim.rlim_cur = argc + nfiles + SLOP;
     88 			if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
     89 				(void) fprintf(stderr,
     90 					"%s: insufficient file descriptors\n",
     91 					command);
     92 				return (2);
     93 			}
     94 		}
     95 		(void) enable_extended_FILE_stdio(-1, -1);
     96 	}
     97 
     98 	pollfd = (struct pollfd *)malloc(argc*sizeof (struct pollfd));
     99 	if (pollfd == NULL) {
    100 		perror("malloc");
    101 		return (2);
    102 	}
    103 
    104 	for (i = 0; i < argc; i++) {
    105 		char psinfofile[100];
    106 
    107 		arg = argv[i];
    108 		if (strchr(arg, '/') != NULL)
    109 			(void) strncpy(psinfofile, arg, sizeof (psinfofile));
    110 		else {
    111 			(void) strcpy(psinfofile, "/proc/");
    112 			(void) strncat(psinfofile, arg, sizeof (psinfofile)-6);
    113 		}
    114 		(void) strncat(psinfofile, "/psinfo",
    115 			sizeof (psinfofile)-strlen(psinfofile));
    116 
    117 		pfd = &pollfd[i];
    118 		if ((pfd->fd = open(psinfofile, O_RDONLY)) >= 0) {
    119 			remain++;
    120 			/*
    121 			 * We set POLLPRI to detect system processes.
    122 			 * We will get POLLNVAL below for a POLLPRI
    123 			 * requested event on a system process.
    124 			 */
    125 			pfd->events = POLLPRI;
    126 			pfd->revents = 0;
    127 		} else if (errno == ENOENT) {
    128 			(void) fprintf(stderr, "%s: no such process: %s\n",
    129 				command, arg);
    130 		} else {
    131 			perror(arg);
    132 		}
    133 	}
    134 
    135 	while (remain != 0) {
    136 		while (poll(pollfd, argc, INFTIM) < 0) {
    137 			if (errno != EAGAIN) {
    138 				perror("poll");
    139 				return (2);
    140 			}
    141 			(void) sleep(2);
    142 		}
    143 		for (i = 0; i < argc; i++) {
    144 			pfd = &pollfd[i];
    145 			if (pfd->fd < 0 || (pfd->revents & ~POLLPRI) == 0) {
    146 				/*
    147 				 * We don't care if a non-system process
    148 				 * stopped.  Don't check for that again.
    149 				 */
    150 				pfd->events = 0;
    151 				pfd->revents = 0;
    152 				continue;
    153 			}
    154 
    155 			if (verbose) {
    156 				arg = argv[i];
    157 				if (pfd->revents & POLLHUP) {
    158 					psinfo_t psinfo;
    159 
    160 					if (pread(pfd->fd, &psinfo,
    161 					    sizeof (psinfo), (off_t)0)
    162 					    == sizeof (psinfo)) {
    163 						(void) printf(
    164 					"%s: terminated, wait status 0x%.4x\n",
    165 							arg, psinfo.pr_wstat);
    166 					} else {
    167 						(void) printf(
    168 						    "%s: terminated\n", arg);
    169 					}
    170 				}
    171 				if (pfd->revents & POLLNVAL)
    172 					(void) printf("%s: system process\n",
    173 						arg);
    174 				if (pfd->revents & ~(POLLPRI|POLLHUP|POLLNVAL))
    175 					(void) printf("%s: unknown error\n",
    176 						arg);
    177 			}
    178 
    179 			(void) close(pfd->fd);
    180 			pfd->fd = -1;
    181 			remain--;
    182 		}
    183 	}
    184 
    185 	return (0);
    186 }
    187 
    188 /* ARGSUSED1 */
    189 static int
    190 do_count(void *nofilesp, int fd)
    191 {
    192 	(*(int *)nofilesp)++;
    193 	return (0);
    194 }
    195 
    196 static int
    197 count_my_files()
    198 {
    199 	int nofiles = 0;
    200 
    201 	(void) fdwalk(do_count, &nofiles);
    202 	return (nofiles);
    203 }
    204