xref: /illumos-gate/usr/src/cmd/gcore/gcore.c (revision 64e4e50a)
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
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * 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 /*
22004388ebScasper  * 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 #include <stdlib.h>
277c478bd9Sstevel@tonic-gate #include <stdio.h>
28004388ebScasper #include <stdio_ext.h>
297c478bd9Sstevel@tonic-gate #include <limits.h>
307c478bd9Sstevel@tonic-gate #include <libproc.h>
317c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <zone.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate static char *pname;
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate static void
convert_path(const char * path,char * fname,size_t size,struct ps_prochandle * P)437c478bd9Sstevel@tonic-gate convert_path(const char *path, char *fname, size_t size,
447c478bd9Sstevel@tonic-gate     struct ps_prochandle *P)
457c478bd9Sstevel@tonic-gate {
467c478bd9Sstevel@tonic-gate 	char *p, *s;
477c478bd9Sstevel@tonic-gate 	ssize_t len;
487c478bd9Sstevel@tonic-gate 	const psinfo_t *pip = Ppsinfo(P);
497c478bd9Sstevel@tonic-gate 	int got_uts = 0;
507c478bd9Sstevel@tonic-gate 	struct utsname uts;
517c478bd9Sstevel@tonic-gate 	char exec[PATH_MAX];
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	fname[size - 1] = '\0';
547c478bd9Sstevel@tonic-gate 	size--;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	while ((p = strchr(path, '%')) != NULL && size != 0) {
577c478bd9Sstevel@tonic-gate 		len = MIN(size, p - path);
587c478bd9Sstevel@tonic-gate 		bcopy(path, fname, len);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 		fname += len;
617c478bd9Sstevel@tonic-gate 		if ((size -= len) == 0)
627c478bd9Sstevel@tonic-gate 			break;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 		p++;
657c478bd9Sstevel@tonic-gate 		switch (*p) {
667c478bd9Sstevel@tonic-gate 		case 'p':
677c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%d", (int)pip->pr_pid);
687c478bd9Sstevel@tonic-gate 			break;
697c478bd9Sstevel@tonic-gate 		case 'u':
707c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%d", (int)pip->pr_uid);
717c478bd9Sstevel@tonic-gate 			break;
727c478bd9Sstevel@tonic-gate 		case 'g':
737c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%d", (int)pip->pr_gid);
747c478bd9Sstevel@tonic-gate 			break;
757c478bd9Sstevel@tonic-gate 		case 'f':
767c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", pip->pr_fname);
777c478bd9Sstevel@tonic-gate 			break;
787c478bd9Sstevel@tonic-gate 		case 'd':
797c478bd9Sstevel@tonic-gate 			len = 0;
807c478bd9Sstevel@tonic-gate 			if (Pexecname(P, exec, sizeof (exec)) == NULL ||
817c478bd9Sstevel@tonic-gate 			    exec[0] != '/' || (s = strrchr(exec, '/')) == NULL)
827c478bd9Sstevel@tonic-gate 				break;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 			*s = '\0';
857c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", &exec[1]);
867c478bd9Sstevel@tonic-gate 			break;
877c478bd9Sstevel@tonic-gate 		case 'n':
887c478bd9Sstevel@tonic-gate 			if (got_uts++ == 0)
897c478bd9Sstevel@tonic-gate 				(void) uname(&uts);
907c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", uts.nodename);
917c478bd9Sstevel@tonic-gate 			break;
927c478bd9Sstevel@tonic-gate 		case 'm':
937c478bd9Sstevel@tonic-gate 			if (got_uts++ == 0)
947c478bd9Sstevel@tonic-gate 				(void) uname(&uts);
957c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%s", uts.machine);
967c478bd9Sstevel@tonic-gate 			break;
977c478bd9Sstevel@tonic-gate 		case 't':
987c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%ld", (long)time(NULL));
997c478bd9Sstevel@tonic-gate 			break;
1007c478bd9Sstevel@tonic-gate 		case 'z':
1017c478bd9Sstevel@tonic-gate 			/*
1027c478bd9Sstevel@tonic-gate 			 * getzonenamebyid() returns the size including the
1037c478bd9Sstevel@tonic-gate 			 * terminating null byte so we need to adjust len.
1047c478bd9Sstevel@tonic-gate 			 */
1057c478bd9Sstevel@tonic-gate 			if ((len = getzonenamebyid(pip->pr_zoneid, fname,
1067c478bd9Sstevel@tonic-gate 			    size)) < 0)
1077c478bd9Sstevel@tonic-gate 				len = snprintf(fname, size, "%d",
1087c478bd9Sstevel@tonic-gate 				    (int)pip->pr_zoneid);
1097c478bd9Sstevel@tonic-gate 			else
1107c478bd9Sstevel@tonic-gate 				len--;
1117c478bd9Sstevel@tonic-gate 			break;
1127c478bd9Sstevel@tonic-gate 		case '%':
1137c478bd9Sstevel@tonic-gate 			*fname = '%';
1147c478bd9Sstevel@tonic-gate 			len = 1;
1157c478bd9Sstevel@tonic-gate 			break;
1167c478bd9Sstevel@tonic-gate 		default:
1177c478bd9Sstevel@tonic-gate 			len = snprintf(fname, size, "%%%c", *p);
1187c478bd9Sstevel@tonic-gate 		}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 		if (len >= size)
1217c478bd9Sstevel@tonic-gate 			return;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 		fname += len;
1247c478bd9Sstevel@tonic-gate 		size -= len;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 		path = p + 1;
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	(void) strncpy(fname, path, size);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static void
gcore(struct ps_prochandle * P,const char * fname,core_content_t content,int * errp)1337c478bd9Sstevel@tonic-gate gcore(struct ps_prochandle *P, const char *fname, core_content_t content,
1347c478bd9Sstevel@tonic-gate     int *errp)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	if (Pgcore(P, fname, content) == 0) {
1377c478bd9Sstevel@tonic-gate 		(void) printf("%s: %s dumped\n", pname, fname);
1387c478bd9Sstevel@tonic-gate 	} else {
1397c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s dump failed: %s\n", pname,
140*64e4e50aSKeith M Wesolowski 		    fname, errno == EBADE ? "unexpected short write" :
141*64e4e50aSKeith M Wesolowski 		    strerror(errno));
1427c478bd9Sstevel@tonic-gate 		(*errp)++;
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1477c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P;
1507c478bd9Sstevel@tonic-gate 	int gerr;
1517c478bd9Sstevel@tonic-gate 	char *prefix = NULL;
1527c478bd9Sstevel@tonic-gate 	int opt;
1537c478bd9Sstevel@tonic-gate 	int opt_p = 0, opt_g = 0, opt_c = 0;
1547c478bd9Sstevel@tonic-gate 	int oflags = 0;
1557c478bd9Sstevel@tonic-gate 	int i;
1567c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
1577c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
1587c478bd9Sstevel@tonic-gate 	int err = 0;
1597c478bd9Sstevel@tonic-gate 	core_content_t content = CC_CONTENT_DEFAULT;
1607c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	if ((pname = strrchr(argv[0], '/')) == NULL)
1637c478bd9Sstevel@tonic-gate 		pname = argv[0];
1647c478bd9Sstevel@tonic-gate 	else
1657c478bd9Sstevel@tonic-gate 		argv[0] = ++pname;		/* for getopt() */
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) {
1687c478bd9Sstevel@tonic-gate 		switch (opt) {
1697c478bd9Sstevel@tonic-gate 		case 'o':
1707c478bd9Sstevel@tonic-gate 			prefix = optarg;
1717c478bd9Sstevel@tonic-gate 			break;
1727c478bd9Sstevel@tonic-gate 		case 'c':
1737c478bd9Sstevel@tonic-gate 			if (proc_str2content(optarg, &content) != 0) {
1747c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: invalid "
1757c478bd9Sstevel@tonic-gate 				    "content string '%s'\n", pname, optarg);
1767c478bd9Sstevel@tonic-gate 				goto usage;
1777c478bd9Sstevel@tonic-gate 			}
1787c478bd9Sstevel@tonic-gate 			opt_c = 1;
1797c478bd9Sstevel@tonic-gate 			break;
1807c478bd9Sstevel@tonic-gate 		case 'F':
1817c478bd9Sstevel@tonic-gate 			oflags |= PGRAB_FORCE;
1827c478bd9Sstevel@tonic-gate 			break;
1837c478bd9Sstevel@tonic-gate 		case 'p':
1847c478bd9Sstevel@tonic-gate 			opt_p = 1;
1857c478bd9Sstevel@tonic-gate 			break;
1867c478bd9Sstevel@tonic-gate 		case 'g':
1877c478bd9Sstevel@tonic-gate 			opt_g = 1;
1887c478bd9Sstevel@tonic-gate 			break;
1897c478bd9Sstevel@tonic-gate 		default:
1907c478bd9Sstevel@tonic-gate 			goto usage;
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if ((opt_p | opt_g) == 0) {
1957c478bd9Sstevel@tonic-gate 		if (prefix == NULL)
1967c478bd9Sstevel@tonic-gate 			prefix = "core";
1977c478bd9Sstevel@tonic-gate 	} else {
1987c478bd9Sstevel@tonic-gate 		int options;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		if ((options = core_get_options()) == -1) {
2017c478bd9Sstevel@tonic-gate 			perror("core_get_options()");
2027c478bd9Sstevel@tonic-gate 			return (1);
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		if (opt_p && !(options & CC_PROCESS_PATH)) {
2067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: per-process core dumps "
2077c478bd9Sstevel@tonic-gate 			    "are disabled (ignoring -p)\n", pname);
2087c478bd9Sstevel@tonic-gate 			opt_p = 0;
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 		if (opt_g && !(options & CC_GLOBAL_PATH)) {
2127c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: global core dumps "
2137c478bd9Sstevel@tonic-gate 			    "are disabled (ignoring -g)\n", pname);
2147c478bd9Sstevel@tonic-gate 			opt_g = 0;
2157c478bd9Sstevel@tonic-gate 		}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 		if ((opt_p | opt_g) == 0 && prefix == NULL)
2187c478bd9Sstevel@tonic-gate 			return (1);
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	argc -= optind;
2227c478bd9Sstevel@tonic-gate 	argv += optind;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (argc == 0)
2257c478bd9Sstevel@tonic-gate 		goto usage;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/*
2287c478bd9Sstevel@tonic-gate 	 * Make sure we'll have enough file descriptors to handle a target
2297c478bd9Sstevel@tonic-gate 	 * that has many many mappings.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
2327c478bd9Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
2337c478bd9Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
234004388ebScasper 		(void) enable_extended_FILE_stdio(-1, -1);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
2387c478bd9Sstevel@tonic-gate 		P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr);
2397c478bd9Sstevel@tonic-gate 		if (P == NULL) {
2407c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot grab %s: %s\n",
2417c478bd9Sstevel@tonic-gate 			    pname, argv[i], Pgrab_error(gerr));
2427c478bd9Sstevel@tonic-gate 			err++;
2437c478bd9Sstevel@tonic-gate 			continue;
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 		if (prefix != NULL) {
2477c478bd9Sstevel@tonic-gate 			(void) snprintf(path, sizeof (path), "%s.%%p", prefix);
2487c478bd9Sstevel@tonic-gate 			convert_path(path, fname, sizeof (fname), P);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 			gcore(P, fname, content, &err);
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 		if (opt_p) {
2547c478bd9Sstevel@tonic-gate 			pid_t pid = Pstatus(P)->pr_pid;
2557c478bd9Sstevel@tonic-gate 			(void) core_get_process_path(path, sizeof (path), pid);
2567c478bd9Sstevel@tonic-gate 			convert_path(path, fname, sizeof (fname), P);
2577c478bd9Sstevel@tonic-gate 			if (!opt_c)
2587c478bd9Sstevel@tonic-gate 				(void) core_get_process_content(&content, pid);
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 			gcore(P, fname, content, &err);
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		if (opt_g) {
2647c478bd9Sstevel@tonic-gate 			/*
2657c478bd9Sstevel@tonic-gate 			 * Global core files are always just readable and
2667c478bd9Sstevel@tonic-gate 			 * writable by their owner so we temporarily change
2677c478bd9Sstevel@tonic-gate 			 * the umask.
2687c478bd9Sstevel@tonic-gate 			 */
2697c478bd9Sstevel@tonic-gate 			mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 			(void) core_get_global_path(path, sizeof (path));
2727c478bd9Sstevel@tonic-gate 			convert_path(path, fname, sizeof (fname), P);
2737c478bd9Sstevel@tonic-gate 			if (!opt_c)
2747c478bd9Sstevel@tonic-gate 				(void) core_get_global_content(&content);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			gcore(P, fname, content, &err);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 			(void) umask(oldmode);
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		Prelease(P, 0);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	return (err != 0);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate usage:
2877c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: %s "
2887c478bd9Sstevel@tonic-gate 	    "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname);
2897c478bd9Sstevel@tonic-gate 	return (2);
2907c478bd9Sstevel@tonic-gate }
291