Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / gcore / gcore.c
blobd9f46494bdbdd346b28e39c535ed8525f5ffd271
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <stdio_ext.h>
29 #include <limits.h>
30 #include <libproc.h>
31 #include <sys/corectl.h>
32 #include <sys/sysmacros.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <zone.h>
40 static char *pname;
42 static void
43 convert_path(const char *path, char *fname, size_t size,
44 struct ps_prochandle *P)
46 char *p, *s;
47 ssize_t len;
48 const psinfo_t *pip = Ppsinfo(P);
49 int got_uts = 0;
50 struct utsname uts;
51 char exec[PATH_MAX];
53 fname[size - 1] = '\0';
54 size--;
56 while ((p = strchr(path, '%')) != NULL && size != 0) {
57 len = MIN(size, p - path);
58 bcopy(path, fname, len);
60 fname += len;
61 if ((size -= len) == 0)
62 break;
64 p++;
65 switch (*p) {
66 case 'p':
67 len = snprintf(fname, size, "%d", (int)pip->pr_pid);
68 break;
69 case 'u':
70 len = snprintf(fname, size, "%d", (int)pip->pr_uid);
71 break;
72 case 'g':
73 len = snprintf(fname, size, "%d", (int)pip->pr_gid);
74 break;
75 case 'f':
76 len = snprintf(fname, size, "%s", pip->pr_fname);
77 break;
78 case 'd':
79 len = 0;
80 if (Pexecname(P, exec, sizeof (exec)) == NULL ||
81 exec[0] != '/' || (s = strrchr(exec, '/')) == NULL)
82 break;
84 *s = '\0';
85 len = snprintf(fname, size, "%s", &exec[1]);
86 break;
87 case 'n':
88 if (got_uts++ == 0)
89 (void) uname(&uts);
90 len = snprintf(fname, size, "%s", uts.nodename);
91 break;
92 case 'm':
93 if (got_uts++ == 0)
94 (void) uname(&uts);
95 len = snprintf(fname, size, "%s", uts.machine);
96 break;
97 case 't':
98 len = snprintf(fname, size, "%ld", (long)time(NULL));
99 break;
100 case 'z':
102 * getzonenamebyid() returns the size including the
103 * terminating null byte so we need to adjust len.
105 if ((len = getzonenamebyid(pip->pr_zoneid, fname,
106 size)) < 0)
107 len = snprintf(fname, size, "%d",
108 (int)pip->pr_zoneid);
109 else
110 len--;
111 break;
112 case '%':
113 *fname = '%';
114 len = 1;
115 break;
116 default:
117 len = snprintf(fname, size, "%%%c", *p);
120 if (len >= size)
121 return;
123 fname += len;
124 size -= len;
126 path = p + 1;
129 (void) strncpy(fname, path, size);
132 static void
133 gcore(struct ps_prochandle *P, const char *fname, core_content_t content,
134 int *errp)
136 if (Pgcore(P, fname, content) == 0) {
137 (void) printf("%s: %s dumped\n", pname, fname);
138 } else {
139 (void) fprintf(stderr, "%s: %s dump failed: %s\n", pname,
140 fname, errno == EBADE ? "unexpected short write" :
141 strerror(errno));
142 (*errp)++;
147 main(int argc, char **argv)
149 struct ps_prochandle *P;
150 int gerr;
151 char *prefix = NULL;
152 int opt;
153 int opt_p = 0, opt_g = 0, opt_c = 0;
154 int oflags = 0;
155 int i;
156 char fname[MAXPATHLEN];
157 char path[MAXPATHLEN];
158 int err = 0;
159 core_content_t content = CC_CONTENT_DEFAULT;
160 struct rlimit rlim;
162 if ((pname = strrchr(argv[0], '/')) == NULL)
163 pname = argv[0];
164 else
165 argv[0] = ++pname; /* for getopt() */
167 while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) {
168 switch (opt) {
169 case 'o':
170 prefix = optarg;
171 break;
172 case 'c':
173 if (proc_str2content(optarg, &content) != 0) {
174 (void) fprintf(stderr, "%s: invalid "
175 "content string '%s'\n", pname, optarg);
176 goto usage;
178 opt_c = 1;
179 break;
180 case 'F':
181 oflags |= PGRAB_FORCE;
182 break;
183 case 'p':
184 opt_p = 1;
185 break;
186 case 'g':
187 opt_g = 1;
188 break;
189 default:
190 goto usage;
194 if ((opt_p | opt_g) == 0) {
195 if (prefix == NULL)
196 prefix = "core";
197 } else {
198 int options;
200 if ((options = core_get_options()) == -1) {
201 perror("core_get_options()");
202 return (1);
205 if (opt_p && !(options & CC_PROCESS_PATH)) {
206 (void) fprintf(stderr, "%s: per-process core dumps "
207 "are disabled (ignoring -p)\n", pname);
208 opt_p = 0;
211 if (opt_g && !(options & CC_GLOBAL_PATH)) {
212 (void) fprintf(stderr, "%s: global core dumps "
213 "are disabled (ignoring -g)\n", pname);
214 opt_g = 0;
217 if ((opt_p | opt_g) == 0 && prefix == NULL)
218 return (1);
221 argc -= optind;
222 argv += optind;
224 if (argc == 0)
225 goto usage;
228 * Make sure we'll have enough file descriptors to handle a target
229 * that has many many mappings.
231 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
232 rlim.rlim_cur = rlim.rlim_max;
233 (void) setrlimit(RLIMIT_NOFILE, &rlim);
234 (void) enable_extended_FILE_stdio(-1, -1);
237 for (i = 0; i < argc; i++) {
238 P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr);
239 if (P == NULL) {
240 (void) fprintf(stderr, "%s: cannot grab %s: %s\n",
241 pname, argv[i], Pgrab_error(gerr));
242 err++;
243 continue;
246 if (prefix != NULL) {
247 (void) snprintf(path, sizeof (path), "%s.%%p", prefix);
248 convert_path(path, fname, sizeof (fname), P);
250 gcore(P, fname, content, &err);
253 if (opt_p) {
254 pid_t pid = Pstatus(P)->pr_pid;
255 (void) core_get_process_path(path, sizeof (path), pid);
256 convert_path(path, fname, sizeof (fname), P);
257 if (!opt_c)
258 (void) core_get_process_content(&content, pid);
260 gcore(P, fname, content, &err);
263 if (opt_g) {
265 * Global core files are always just readable and
266 * writable by their owner so we temporarily change
267 * the umask.
269 mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO);
271 (void) core_get_global_path(path, sizeof (path));
272 convert_path(path, fname, sizeof (fname), P);
273 if (!opt_c)
274 (void) core_get_global_content(&content);
276 gcore(P, fname, content, &err);
278 (void) umask(oldmode);
281 Prelease(P, 0);
284 return (err != 0);
286 usage:
287 (void) fprintf(stderr, "usage: %s "
288 "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname);
289 return (2);