/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include <stdio.h> #include <stdio_ext.h> #include <ctype.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <dirent.h> #include <errno.h> #include <sys/types.h> #include <stropts.h> #include <poll.h> #include <procfs.h> #include <sys/resource.h> static int count_my_files(); static char *command; /* slop to account for extra file descriptors opened by libraries we call */ #define SLOP 5 int main(int argc, char **argv) { unsigned long remain = 0; struct pollfd *pollfd; struct pollfd *pfd; struct rlimit rlim; char *arg; unsigned i; int verbose = 0; if ((command = strrchr(argv[0], '/')) != NULL) command++; else command = argv[0]; argc--; argv++; if (argc > 0 && strcmp(argv[0], "-v") == 0) { verbose = 1; argc--; argv++; } if (argc <= 0) { (void) fprintf(stderr, "usage:\t%s [-v] pid ...\n", command); (void) fprintf(stderr, " (wait for processes to terminate)\n"); (void) fprintf(stderr, " -v: verbose; report terminations to standard out\n"); return (2); } /* make sure we have enough file descriptors */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { int nfiles = count_my_files(); if (rlim.rlim_cur < argc + nfiles + SLOP) { rlim.rlim_cur = argc + nfiles + SLOP; if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { (void) fprintf(stderr, "%s: insufficient file descriptors\n", command); return (2); } } (void) enable_extended_FILE_stdio(-1, -1); } pollfd = (struct pollfd *)malloc(argc*sizeof (struct pollfd)); if (pollfd == NULL) { perror("malloc"); return (2); } for (i = 0; i < argc; i++) { char psinfofile[100]; arg = argv[i]; if (strchr(arg, '/') != NULL) (void) strncpy(psinfofile, arg, sizeof (psinfofile)); else { (void) strcpy(psinfofile, "/proc/"); (void) strncat(psinfofile, arg, sizeof (psinfofile)-6); } (void) strncat(psinfofile, "/psinfo", sizeof (psinfofile)-strlen(psinfofile)); pfd = &pollfd[i]; if ((pfd->fd = open(psinfofile, O_RDONLY)) >= 0) { remain++; /* * We set POLLPRI to detect system processes. * We will get POLLNVAL below for a POLLPRI * requested event on a system process. */ pfd->events = POLLPRI; pfd->revents = 0; } else if (errno == ENOENT) { (void) fprintf(stderr, "%s: no such process: %s\n", command, arg); } else { perror(arg); } } while (remain != 0) { while (poll(pollfd, argc, INFTIM) < 0) { if (errno != EAGAIN) { perror("poll"); return (2); } (void) sleep(2); } for (i = 0; i < argc; i++) { pfd = &pollfd[i]; if (pfd->fd < 0 || (pfd->revents & ~POLLPRI) == 0) { /* * We don't care if a non-system process * stopped. Don't check for that again. */ pfd->events = 0; pfd->revents = 0; continue; } if (verbose) { arg = argv[i]; if (pfd->revents & POLLHUP) { psinfo_t psinfo; if (pread(pfd->fd, &psinfo, sizeof (psinfo), (off_t)0) == sizeof (psinfo)) { (void) printf( "%s: terminated, wait status 0x%.4x\n", arg, psinfo.pr_wstat); } else { (void) printf( "%s: terminated\n", arg); } } if (pfd->revents & POLLNVAL) (void) printf("%s: system process\n", arg); if (pfd->revents & ~(POLLPRI|POLLHUP|POLLNVAL)) (void) printf("%s: unknown error\n", arg); } (void) close(pfd->fd); pfd->fd = -1; remain--; } } return (0); } /* ARGSUSED1 */ static int do_count(void *nofilesp, int fd) { (*(int *)nofilesp)++; return (0); } static int count_my_files() { int nofiles = 0; (void) fdwalk(do_count, &nofiles); return (nofiles); }