1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <limits.h>
32 #include <libproc.h>
33 #include <sys/corectl.h>
34 #include <sys/sysmacros.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <zone.h>
41
42 static char *pname;
43
44 static void
convert_path(const char * path,char * fname,size_t size,struct ps_prochandle * P)45 convert_path(const char *path, char *fname, size_t size,
46 struct ps_prochandle *P)
47 {
48 char *p, *s;
49 ssize_t len;
50 const psinfo_t *pip = Ppsinfo(P);
51 int got_uts = 0;
52 struct utsname uts;
53 char exec[PATH_MAX];
54
55 fname[size - 1] = '\0';
56 size--;
57
58 while ((p = strchr(path, '%')) != NULL && size != 0) {
59 len = MIN(size, p - path);
60 bcopy(path, fname, len);
61
62 fname += len;
63 if ((size -= len) == 0)
64 break;
65
66 p++;
67 switch (*p) {
68 case 'p':
69 len = snprintf(fname, size, "%d", (int)pip->pr_pid);
70 break;
71 case 'u':
72 len = snprintf(fname, size, "%d", (int)pip->pr_uid);
73 break;
74 case 'g':
75 len = snprintf(fname, size, "%d", (int)pip->pr_gid);
76 break;
77 case 'f':
78 len = snprintf(fname, size, "%s", pip->pr_fname);
79 break;
80 case 'd':
81 len = 0;
82 if (Pexecname(P, exec, sizeof (exec)) == NULL ||
83 exec[0] != '/' || (s = strrchr(exec, '/')) == NULL)
84 break;
85
86 *s = '\0';
87 len = snprintf(fname, size, "%s", &exec[1]);
88 break;
89 case 'n':
90 if (got_uts++ == 0)
91 (void) uname(&uts);
92 len = snprintf(fname, size, "%s", uts.nodename);
93 break;
94 case 'm':
95 if (got_uts++ == 0)
96 (void) uname(&uts);
97 len = snprintf(fname, size, "%s", uts.machine);
98 break;
99 case 't':
100 len = snprintf(fname, size, "%ld", (long)time(NULL));
101 break;
102 case 'z':
103 /*
104 * getzonenamebyid() returns the size including the
105 * terminating null byte so we need to adjust len.
106 */
107 if ((len = getzonenamebyid(pip->pr_zoneid, fname,
108 size)) < 0)
109 len = snprintf(fname, size, "%d",
110 (int)pip->pr_zoneid);
111 else
112 len--;
113 break;
114 case '%':
115 *fname = '%';
116 len = 1;
117 break;
118 default:
119 len = snprintf(fname, size, "%%%c", *p);
120 }
121
122 if (len >= size)
123 return;
124
125 fname += len;
126 size -= len;
127
128 path = p + 1;
129 }
130
131 (void) strncpy(fname, path, size);
132 }
133
134 static void
gcore(struct ps_prochandle * P,const char * fname,core_content_t content,int * errp)135 gcore(struct ps_prochandle *P, const char *fname, core_content_t content,
136 int *errp)
137 {
138 if (Pgcore(P, fname, content) == 0) {
139 (void) printf("%s: %s dumped\n", pname, fname);
140 } else {
141 (void) fprintf(stderr, "%s: %s dump failed: %s\n", pname,
142 fname, strerror(errno));
143 (*errp)++;
144 }
145 }
146
147 int
main(int argc,char ** argv)148 main(int argc, char **argv)
149 {
150 struct ps_prochandle *P;
151 int gerr;
152 char *prefix = NULL;
153 int opt;
154 int opt_p = 0, opt_g = 0, opt_c = 0;
155 int oflags = 0;
156 int i;
157 char fname[MAXPATHLEN];
158 char path[MAXPATHLEN];
159 int err = 0;
160 core_content_t content = CC_CONTENT_DEFAULT;
161 struct rlimit rlim;
162
163 if ((pname = strrchr(argv[0], '/')) == NULL)
164 pname = argv[0];
165 else
166 argv[0] = ++pname; /* for getopt() */
167
168 while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) {
169 switch (opt) {
170 case 'o':
171 prefix = optarg;
172 break;
173 case 'c':
174 if (proc_str2content(optarg, &content) != 0) {
175 (void) fprintf(stderr, "%s: invalid "
176 "content string '%s'\n", pname, optarg);
177 goto usage;
178 }
179 opt_c = 1;
180 break;
181 case 'F':
182 oflags |= PGRAB_FORCE;
183 break;
184 case 'p':
185 opt_p = 1;
186 break;
187 case 'g':
188 opt_g = 1;
189 break;
190 default:
191 goto usage;
192 }
193 }
194
195 if ((opt_p | opt_g) == 0) {
196 if (prefix == NULL)
197 prefix = "core";
198 } else {
199 int options;
200
201 if ((options = core_get_options()) == -1) {
202 perror("core_get_options()");
203 return (1);
204 }
205
206 if (opt_p && !(options & CC_PROCESS_PATH)) {
207 (void) fprintf(stderr, "%s: per-process core dumps "
208 "are disabled (ignoring -p)\n", pname);
209 opt_p = 0;
210 }
211
212 if (opt_g && !(options & CC_GLOBAL_PATH)) {
213 (void) fprintf(stderr, "%s: global core dumps "
214 "are disabled (ignoring -g)\n", pname);
215 opt_g = 0;
216 }
217
218 if ((opt_p | opt_g) == 0 && prefix == NULL)
219 return (1);
220 }
221
222 argc -= optind;
223 argv += optind;
224
225 if (argc == 0)
226 goto usage;
227
228 /*
229 * Make sure we'll have enough file descriptors to handle a target
230 * that has many many mappings.
231 */
232 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
233 rlim.rlim_cur = rlim.rlim_max;
234 (void) setrlimit(RLIMIT_NOFILE, &rlim);
235 (void) enable_extended_FILE_stdio(-1, -1);
236 }
237
238 for (i = 0; i < argc; i++) {
239 P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr);
240 if (P == NULL) {
241 (void) fprintf(stderr, "%s: cannot grab %s: %s\n",
242 pname, argv[i], Pgrab_error(gerr));
243 err++;
244 continue;
245 }
246
247 if (prefix != NULL) {
248 (void) snprintf(path, sizeof (path), "%s.%%p", prefix);
249 convert_path(path, fname, sizeof (fname), P);
250
251 gcore(P, fname, content, &err);
252 }
253
254 if (opt_p) {
255 pid_t pid = Pstatus(P)->pr_pid;
256 (void) core_get_process_path(path, sizeof (path), pid);
257 convert_path(path, fname, sizeof (fname), P);
258 if (!opt_c)
259 (void) core_get_process_content(&content, pid);
260
261 gcore(P, fname, content, &err);
262 }
263
264 if (opt_g) {
265 /*
266 * Global core files are always just readable and
267 * writable by their owner so we temporarily change
268 * the umask.
269 */
270 mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO);
271
272 (void) core_get_global_path(path, sizeof (path));
273 convert_path(path, fname, sizeof (fname), P);
274 if (!opt_c)
275 (void) core_get_global_content(&content);
276
277 gcore(P, fname, content, &err);
278
279 (void) umask(oldmode);
280 }
281
282 Prelease(P, 0);
283 }
284
285 return (err != 0);
286
287 usage:
288 (void) fprintf(stderr, "usage: %s "
289 "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname);
290 return (2);
291 }
292