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