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 #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>
39
40 static char *pname;
41
42 static void
convert_path(const char * path,char * fname,size_t size,struct ps_prochandle * P)43 convert_path(const char *path, char *fname, size_t size,
44 struct ps_prochandle *P)
45 {
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];
52
53 fname[size - 1] = '\0';
54 size--;
55
56 while ((p = strchr(path, '%')) != NULL && size != 0) {
57 len = MIN(size, p - path);
58 bcopy(path, fname, len);
59
60 fname += len;
61 if ((size -= len) == 0)
62 break;
63
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;
83
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':
101 /*
102 * getzonenamebyid() returns the size including the
103 * terminating null byte so we need to adjust len.
104 */
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);
118 }
119
120 if (len >= size)
121 return;
122
123 fname += len;
124 size -= len;
125
126 path = p + 1;
127 }
128
129 (void) strncpy(fname, path, size);
130 }
131
132 static void
gcore(struct ps_prochandle * P,const char * fname,core_content_t content,int * errp)133 gcore(struct ps_prochandle *P, const char *fname, core_content_t content,
134 int *errp)
135 {
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)++;
143 }
144 }
145
146 int
main(int argc,char ** argv)147 main(int argc, char **argv)
148 {
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;
161
162 if ((pname = strrchr(argv[0], '/')) == NULL)
163 pname = argv[0];
164 else
165 argv[0] = ++pname; /* for getopt() */
166
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;
177 }
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;
191 }
192 }
193
194 if ((opt_p | opt_g) == 0) {
195 if (prefix == NULL)
196 prefix = "core";
197 } else {
198 int options;
199
200 if ((options = core_get_options()) == -1) {
201 perror("core_get_options()");
202 return (1);
203 }
204
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;
209 }
210
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;
215 }
216
217 if ((opt_p | opt_g) == 0 && prefix == NULL)
218 return (1);
219 }
220
221 argc -= optind;
222 argv += optind;
223
224 if (argc == 0)
225 goto usage;
226
227 /*
228 * Make sure we'll have enough file descriptors to handle a target
229 * that has many many mappings.
230 */
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);
235 }
236
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;
244 }
245
246 if (prefix != NULL) {
247 (void) snprintf(path, sizeof (path), "%s.%%p", prefix);
248 convert_path(path, fname, sizeof (fname), P);
249
250 gcore(P, fname, content, &err);
251 }
252
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);
259
260 gcore(P, fname, content, &err);
261 }
262
263 if (opt_g) {
264 /*
265 * Global core files are always just readable and
266 * writable by their owner so we temporarily change
267 * the umask.
268 */
269 mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO);
270
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);
275
276 gcore(P, fname, content, &err);
277
278 (void) umask(oldmode);
279 }
280
281 Prelease(P, 0);
282 }
283
284 return (err != 0);
285
286 usage:
287 (void) fprintf(stderr, "usage: %s "
288 "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname);
289 return (2);
290 }
291