OpenSolaris_b135/cmd/gcore/gcore.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 <stdlib.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <limits.h>
#include <libproc.h>
#include <sys/corectl.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <zone.h>

static char *pname;

static void
convert_path(const char *path, char *fname, size_t size,
    struct ps_prochandle *P)
{
	char *p, *s;
	ssize_t len;
	const psinfo_t *pip = Ppsinfo(P);
	int got_uts = 0;
	struct utsname uts;
	char exec[PATH_MAX];

	fname[size - 1] = '\0';
	size--;

	while ((p = strchr(path, '%')) != NULL && size != 0) {
		len = MIN(size, p - path);
		bcopy(path, fname, len);

		fname += len;
		if ((size -= len) == 0)
			break;

		p++;
		switch (*p) {
		case 'p':
			len = snprintf(fname, size, "%d", (int)pip->pr_pid);
			break;
		case 'u':
			len = snprintf(fname, size, "%d", (int)pip->pr_uid);
			break;
		case 'g':
			len = snprintf(fname, size, "%d", (int)pip->pr_gid);
			break;
		case 'f':
			len = snprintf(fname, size, "%s", pip->pr_fname);
			break;
		case 'd':
			len = 0;
			if (Pexecname(P, exec, sizeof (exec)) == NULL ||
			    exec[0] != '/' || (s = strrchr(exec, '/')) == NULL)
				break;

			*s = '\0';
			len = snprintf(fname, size, "%s", &exec[1]);
			break;
		case 'n':
			if (got_uts++ == 0)
				(void) uname(&uts);
			len = snprintf(fname, size, "%s", uts.nodename);
			break;
		case 'm':
			if (got_uts++ == 0)
				(void) uname(&uts);
			len = snprintf(fname, size, "%s", uts.machine);
			break;
		case 't':
			len = snprintf(fname, size, "%ld", (long)time(NULL));
			break;
		case 'z':
			/*
			 * getzonenamebyid() returns the size including the
			 * terminating null byte so we need to adjust len.
			 */
			if ((len = getzonenamebyid(pip->pr_zoneid, fname,
			    size)) < 0)
				len = snprintf(fname, size, "%d",
				    (int)pip->pr_zoneid);
			else
				len--;
			break;
		case '%':
			*fname = '%';
			len = 1;
			break;
		default:
			len = snprintf(fname, size, "%%%c", *p);
		}

		if (len >= size)
			return;

		fname += len;
		size -= len;

		path = p + 1;
	}

	(void) strncpy(fname, path, size);
}

static void
gcore(struct ps_prochandle *P, const char *fname, core_content_t content,
    int *errp)
{
	if (Pgcore(P, fname, content) == 0) {
		(void) printf("%s: %s dumped\n", pname, fname);
	} else {
		(void) fprintf(stderr, "%s: %s dump failed: %s\n", pname,
		    fname, strerror(errno));
		(*errp)++;
	}
}

int
main(int argc, char **argv)
{
	struct ps_prochandle *P;
	int gerr;
	char *prefix = NULL;
	int opt;
	int opt_p = 0, opt_g = 0, opt_c = 0;
	int oflags = 0;
	int i;
	char fname[MAXPATHLEN];
	char path[MAXPATHLEN];
	int err = 0;
	core_content_t content = CC_CONTENT_DEFAULT;
	struct rlimit rlim;

	if ((pname = strrchr(argv[0], '/')) == NULL)
		pname = argv[0];
	else
		argv[0] = ++pname;		/* for getopt() */

	while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) {
		switch (opt) {
		case 'o':
			prefix = optarg;
			break;
		case 'c':
			if (proc_str2content(optarg, &content) != 0) {
				(void) fprintf(stderr, "%s: invalid "
				    "content string '%s'\n", pname, optarg);
				goto usage;
			}
			opt_c = 1;
			break;
		case 'F':
			oflags |= PGRAB_FORCE;
			break;
		case 'p':
			opt_p = 1;
			break;
		case 'g':
			opt_g = 1;
			break;
		default:
			goto usage;
		}
	}

	if ((opt_p | opt_g) == 0) {
		if (prefix == NULL)
			prefix = "core";
	} else {
		int options;

		if ((options = core_get_options()) == -1) {
			perror("core_get_options()");
			return (1);
		}

		if (opt_p && !(options & CC_PROCESS_PATH)) {
			(void) fprintf(stderr, "%s: per-process core dumps "
			    "are disabled (ignoring -p)\n", pname);
			opt_p = 0;
		}

		if (opt_g && !(options & CC_GLOBAL_PATH)) {
			(void) fprintf(stderr, "%s: global core dumps "
			    "are disabled (ignoring -g)\n", pname);
			opt_g = 0;
		}

		if ((opt_p | opt_g) == 0 && prefix == NULL)
			return (1);
	}

	argc -= optind;
	argv += optind;

	if (argc == 0)
		goto usage;

	/*
	 * Make sure we'll have enough file descriptors to handle a target
	 * that has many many mappings.
	 */
	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
		rlim.rlim_cur = rlim.rlim_max;
		(void) setrlimit(RLIMIT_NOFILE, &rlim);
		(void) enable_extended_FILE_stdio(-1, -1);
	}

	for (i = 0; i < argc; i++) {
		P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr);
		if (P == NULL) {
			(void) fprintf(stderr, "%s: cannot grab %s: %s\n",
			    pname, argv[i], Pgrab_error(gerr));
			err++;
			continue;
		}

		if (prefix != NULL) {
			(void) snprintf(path, sizeof (path), "%s.%%p", prefix);
			convert_path(path, fname, sizeof (fname), P);

			gcore(P, fname, content, &err);
		}

		if (opt_p) {
			pid_t pid = Pstatus(P)->pr_pid;
			(void) core_get_process_path(path, sizeof (path), pid);
			convert_path(path, fname, sizeof (fname), P);
			if (!opt_c)
				(void) core_get_process_content(&content, pid);

			gcore(P, fname, content, &err);
		}

		if (opt_g) {
			/*
			 * Global core files are always just readable and
			 * writable by their owner so we temporarily change
			 * the umask.
			 */
			mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO);

			(void) core_get_global_path(path, sizeof (path));
			convert_path(path, fname, sizeof (fname), P);
			if (!opt_c)
				(void) core_get_global_content(&content);

			gcore(P, fname, content, &err);

			(void) umask(oldmode);
		}

		Prelease(P, 0);
	}

	return (err != 0);

usage:
	(void) fprintf(stderr, "usage: %s "
	    "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname);
	return (2);
}