xref: /illumos-gate/usr/src/cmd/gcore/gcore.c (revision 004388eb)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*004388ebScasper  * Common Development and Distribution License (the "License").
6*004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*004388ebScasper  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
30*004388ebScasper #include <stdio_ext.h>
317c478bd9Sstevel@tonic-gate #include <limits.h>
327c478bd9Sstevel@tonic-gate #include <libproc.h>
337c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <errno.h>
407c478bd9Sstevel@tonic-gate #include <zone.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate static char *pname;
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static void
457c478bd9Sstevel@tonic-gate convert_path(const char *path, char *fname, size_t size,
467c478bd9Sstevel@tonic-gate     struct ps_prochandle *P)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	char *p, *s;
497c478bd9Sstevel@tonic-gate 	ssize_t len;
507c478bd9Sstevel@tonic-gate 	const psinfo_t *pip = Ppsinfo(P);
517c478bd9Sstevel@tonic-gate 	int got_uts = 0;
527c478bd9Sstevel@tonic-gate 	struct utsname uts;
537c478bd9Sstevel@tonic-gate 	char exec[PATH_MAX];
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	fname[size - 1] = '\0';
567c478bd9Sstevel@tonic-gate 	size--;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	while ((p = strchr(path, '%')) != NULL && size != 0) {
597c478bd9Sstevel@tonic-gate 		len = MIN(size, p - path);
607c478bd9Sstevel@tonic-gate 		bcopy(path, fname, len);
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 		fname += len;
637c478bd9Sstevel@tonic-gate 		if ((size -= len) == 0)
647c478bd9Sstevel@tonic-gate 			break;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 		p++;
677c478bd9Sstevel@tonic-gate 		switch (*p) {
687c478bd9Sstevel@tonic-gate 		case 'p':
697c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%d", (int)pip->pr_pid);
707c478bd9Sstevel@tonic-gate 			break;
717c478bd9Sstevel@tonic-gate 		case 'u':
727c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%d", (int)pip->pr_uid);
737c478bd9Sstevel@tonic-gate 			break;
747c478bd9Sstevel@tonic-gate 		case 'g':
757c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%d", (int)pip->pr_gid);
767c478bd9Sstevel@tonic-gate 			break;
777c478bd9Sstevel@tonic-gate 		case 'f':
787c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", pip->pr_fname);
797c478bd9Sstevel@tonic-gate 			break;
807c478bd9Sstevel@tonic-gate 		case 'd':
817c478bd9Sstevel@tonic-gate 			len = 0;
827c478bd9Sstevel@tonic-gate 			if (Pexecname(P, exec, sizeof (exec)) == NULL ||
837c478bd9Sstevel@tonic-gate 			    exec[0] != '/' || (s = strrchr(exec, '/')) == NULL)
847c478bd9Sstevel@tonic-gate 				break;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 			*s = '\0';
877c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", &exec[1]);
887c478bd9Sstevel@tonic-gate 			break;
897c478bd9Sstevel@tonic-gate 		case 'n':
907c478bd9Sstevel@tonic-gate 			if (got_uts++ == 0)
917c478bd9Sstevel@tonic-gate 				(void) uname(&uts);
927c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", uts.nodename);
937c478bd9Sstevel@tonic-gate 			break;
947c478bd9Sstevel@tonic-gate 		case 'm':
957c478bd9Sstevel@tonic-gate 			if (got_uts++ == 0)
967c478bd9Sstevel@tonic-gate 				(void) uname(&uts);
977c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", uts.machine);
987c478bd9Sstevel@tonic-gate 			break;
997c478bd9Sstevel@tonic-gate 		case 't':
1007c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%ld", (long)time(NULL));
1017c478bd9Sstevel@tonic-gate 			break;
1027c478bd9Sstevel@tonic-gate 		case 'z':
1037c478bd9Sstevel@tonic-gate 			/*
1047c478bd9Sstevel@tonic-gate 			 * getzonenamebyid() returns the size including the
1057c478bd9Sstevel@tonic-gate 			 * terminating null byte so we need to adjust len.
1067c478bd9Sstevel@tonic-gate 			 */
1077c478bd9Sstevel@tonic-gate 			if ((len = getzonenamebyid(pip->pr_zoneid, fname,
1087c478bd9Sstevel@tonic-gate 			    size)) < 0)
1097c478bd9Sstevel@tonic-gate 				len = snprintf(fname, size, "%d",
1107c478bd9Sstevel@tonic-gate 				    (int)pip->pr_zoneid);
1117c478bd9Sstevel@tonic-gate 			else
1127c478bd9Sstevel@tonic-gate 				len--;
1137c478bd9Sstevel@tonic-gate 			break;
1147c478bd9Sstevel@tonic-gate 		case '%':
1157c478bd9Sstevel@tonic-gate 			*fname = '%';
1167c478bd9Sstevel@tonic-gate 			len = 1;
1177c478bd9Sstevel@tonic-gate 			break;
1187c478bd9Sstevel@tonic-gate 		default:
1197c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%%%c", *p);
1207c478bd9Sstevel@tonic-gate 		}
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 		if (len >= size)
1237c478bd9Sstevel@tonic-gate 			return;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 		fname += len;
1267c478bd9Sstevel@tonic-gate 		size -= len;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 		path = p + 1;
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	(void) strncpy(fname, path, size);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static void
1357c478bd9Sstevel@tonic-gate gcore(struct ps_prochandle *P, const char *fname, core_content_t content,
1367c478bd9Sstevel@tonic-gate     int *errp)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate 	if (Pgcore(P, fname, content) == 0) {
1397c478bd9Sstevel@tonic-gate 		(void) printf("%s: %s dumped\n", pname, fname);
1407c478bd9Sstevel@tonic-gate 	} else {
1417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s dump failed: %s\n", pname,
1427c478bd9Sstevel@tonic-gate 		    fname, strerror(errno));
1437c478bd9Sstevel@tonic-gate 		(*errp)++;
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate int
1487c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P;
1517c478bd9Sstevel@tonic-gate 	int gerr;
1527c478bd9Sstevel@tonic-gate 	char *prefix = NULL;
1537c478bd9Sstevel@tonic-gate 	int opt;
1547c478bd9Sstevel@tonic-gate 	int opt_p = 0, opt_g = 0, opt_c = 0;
1557c478bd9Sstevel@tonic-gate 	int oflags = 0;
1567c478bd9Sstevel@tonic-gate 	int i;
1577c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
1587c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
1597c478bd9Sstevel@tonic-gate 	int err = 0;
1607c478bd9Sstevel@tonic-gate 	core_content_t content = CC_CONTENT_DEFAULT;
1617c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if ((pname = strrchr(argv[0], '/')) == NULL)
1647c478bd9Sstevel@tonic-gate 		pname = argv[0];
1657c478bd9Sstevel@tonic-gate 	else
1667c478bd9Sstevel@tonic-gate 		argv[0] = ++pname;		/* for getopt() */
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) {
1697c478bd9Sstevel@tonic-gate 		switch (opt) {
1707c478bd9Sstevel@tonic-gate 		case 'o':
1717c478bd9Sstevel@tonic-gate 			prefix = optarg;
1727c478bd9Sstevel@tonic-gate 			break;
1737c478bd9Sstevel@tonic-gate 		case 'c':
1747c478bd9Sstevel@tonic-gate 			if (proc_str2content(optarg, &content) != 0) {
1757c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: invalid "
1767c478bd9Sstevel@tonic-gate 				    "content string '%s'\n", pname, optarg);
1777c478bd9Sstevel@tonic-gate 				goto usage;
1787c478bd9Sstevel@tonic-gate 			}
1797c478bd9Sstevel@tonic-gate 			opt_c = 1;
1807c478bd9Sstevel@tonic-gate 			break;
1817c478bd9Sstevel@tonic-gate 		case 'F':
1827c478bd9Sstevel@tonic-gate 			oflags |= PGRAB_FORCE;
1837c478bd9Sstevel@tonic-gate 			break;
1847c478bd9Sstevel@tonic-gate 		case 'p':
1857c478bd9Sstevel@tonic-gate 			opt_p = 1;
1867c478bd9Sstevel@tonic-gate 			break;
1877c478bd9Sstevel@tonic-gate 		case 'g':
1887c478bd9Sstevel@tonic-gate 			opt_g = 1;
1897c478bd9Sstevel@tonic-gate 			break;
1907c478bd9Sstevel@tonic-gate 		default:
1917c478bd9Sstevel@tonic-gate 			goto usage;
1927c478bd9Sstevel@tonic-gate 		}
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	if ((opt_p | opt_g) == 0) {
1967c478bd9Sstevel@tonic-gate 		if (prefix == NULL)
1977c478bd9Sstevel@tonic-gate 			prefix = "core";
1987c478bd9Sstevel@tonic-gate 	} else {
1997c478bd9Sstevel@tonic-gate 		int options;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 		if ((options = core_get_options()) == -1) {
2027c478bd9Sstevel@tonic-gate 			perror("core_get_options()");
2037c478bd9Sstevel@tonic-gate 			return (1);
2047c478bd9Sstevel@tonic-gate 		}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		if (opt_p && !(options & CC_PROCESS_PATH)) {
2077c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: per-process core dumps "
2087c478bd9Sstevel@tonic-gate 			    "are disabled (ignoring -p)\n", pname);
2097c478bd9Sstevel@tonic-gate 			opt_p = 0;
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		if (opt_g && !(options & CC_GLOBAL_PATH)) {
2137c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: global core dumps "
2147c478bd9Sstevel@tonic-gate 			    "are disabled (ignoring -g)\n", pname);
2157c478bd9Sstevel@tonic-gate 			opt_g = 0;
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 		if ((opt_p | opt_g) == 0 && prefix == NULL)
2197c478bd9Sstevel@tonic-gate 			return (1);
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	argc -= optind;
2237c478bd9Sstevel@tonic-gate 	argv += optind;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if (argc == 0)
2267c478bd9Sstevel@tonic-gate 		goto usage;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/*
2297c478bd9Sstevel@tonic-gate 	 * Make sure we'll have enough file descriptors to handle a target
2307c478bd9Sstevel@tonic-gate 	 * that has many many mappings.
2317c478bd9Sstevel@tonic-gate 	 */
2327c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
2337c478bd9Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
2347c478bd9Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
235*004388ebScasper 		(void) enable_extended_FILE_stdio(-1, -1);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
2397c478bd9Sstevel@tonic-gate 		P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr);
2407c478bd9Sstevel@tonic-gate 		if (P == NULL) {
2417c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot grab %s: %s\n",
2427c478bd9Sstevel@tonic-gate 			    pname, argv[i], Pgrab_error(gerr));
2437c478bd9Sstevel@tonic-gate 			err++;
2447c478bd9Sstevel@tonic-gate 			continue;
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		if (prefix != NULL) {
2487c478bd9Sstevel@tonic-gate 			(void) snprintf(path, sizeof (path), "%s.%%p", prefix);
2497c478bd9Sstevel@tonic-gate 			convert_path(path, fname, sizeof (fname), P);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 			gcore(P, fname, content, &err);
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 		if (opt_p) {
2557c478bd9Sstevel@tonic-gate 			pid_t pid = Pstatus(P)->pr_pid;
2567c478bd9Sstevel@tonic-gate 			(void) core_get_process_path(path, sizeof (path), pid);
2577c478bd9Sstevel@tonic-gate 			convert_path(path, fname, sizeof (fname), P);
2587c478bd9Sstevel@tonic-gate 			if (!opt_c)
2597c478bd9Sstevel@tonic-gate 				(void) core_get_process_content(&content, pid);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 			gcore(P, fname, content, &err);
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		if (opt_g) {
2657c478bd9Sstevel@tonic-gate 			/*
2667c478bd9Sstevel@tonic-gate 			 * Global core files are always just readable and
2677c478bd9Sstevel@tonic-gate 			 * writable by their owner so we temporarily change
2687c478bd9Sstevel@tonic-gate 			 * the umask.
2697c478bd9Sstevel@tonic-gate 			 */
2707c478bd9Sstevel@tonic-gate 			mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 			(void) core_get_global_path(path, sizeof (path));
2737c478bd9Sstevel@tonic-gate 			convert_path(path, fname, sizeof (fname), P);
2747c478bd9Sstevel@tonic-gate 			if (!opt_c)
2757c478bd9Sstevel@tonic-gate 				(void) core_get_global_content(&content);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 			gcore(P, fname, content, &err);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 			(void) umask(oldmode);
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		Prelease(P, 0);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	return (err != 0);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate usage:
2887c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: %s "
2897c478bd9Sstevel@tonic-gate 	    "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname);
2907c478bd9Sstevel@tonic-gate 	return (2);
2917c478bd9Sstevel@tonic-gate }
292