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 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 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 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