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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2018, Joyent, Inc. 27 * Copyright 2022 Oxide Computer Company 28 */ 29 30 /* 31 * pargs examines and prints the arguments (argv), environment (environ), 32 * and auxiliary vector of another process. 33 * 34 * This utility is made more complex because it must run in internationalized 35 * environments. The two key cases for pargs to manage are: 36 * 37 * 1. pargs and target run in the same locale: pargs must respect the 38 * locale, but this case is straightforward. Care is taken to correctly 39 * use wide characters in order to print results properly. 40 * 41 * 2. pargs and target run in different locales: in this case, pargs examines 42 * the string having assumed the victim's locale. Unprintable (but valid) 43 * characters are escaped. Next, iconv(3c) is used to convert between the 44 * target and pargs codeset. Finally, a second pass to escape unprintable 45 * (but valid) characters is made. 46 * 47 * In any case in which characters are encountered which are not valid in 48 * their purported locale, the string "fails" and is treated as a traditional 49 * 7-bit ASCII encoded string, and escaped accordingly. 50 */ 51 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <locale.h> 55 #include <wchar.h> 56 #include <iconv.h> 57 #include <langinfo.h> 58 #include <unistd.h> 59 #include <ctype.h> 60 #include <fcntl.h> 61 #include <string.h> 62 #include <strings.h> 63 #include <limits.h> 64 #include <pwd.h> 65 #include <grp.h> 66 #include <errno.h> 67 #include <setjmp.h> 68 #include <sys/types.h> 69 #include <sys/auxv.h> 70 #include <sys/archsystm.h> 71 #include <sys/proc.h> 72 #include <sys/elf.h> 73 #include <libproc.h> 74 #include <wctype.h> 75 #include <widec.h> 76 #include <elfcap.h> 77 #include <libgen.h> 78 79 typedef enum pargs_cmd { 80 PARGS_ARGV, 81 PARGS_ENV, 82 PARGS_AUXV 83 } pargs_cmd_t; 84 85 typedef struct pargs_data { 86 struct ps_prochandle *pd_proc; /* target proc handle */ 87 psinfo_t *pd_psinfo; /* target psinfo */ 88 char *pd_locale; /* target process locale */ 89 int pd_conv_flags; /* flags governing string conversion */ 90 iconv_t pd_iconv; /* iconv conversion descriptor */ 91 size_t pd_argc; 92 uintptr_t *pd_argv; 93 char **pd_argv_strs; 94 size_t pd_envc; 95 size_t pd_env_space; 96 uintptr_t *pd_envp; 97 char **pd_envp_strs; 98 size_t pd_auxc; 99 auxv_t *pd_auxv; 100 char **pd_auxv_strs; 101 char *pd_execname; 102 } pargs_data_t; 103 104 #define CONV_USE_ICONV 0x01 105 #define CONV_STRICT_ASCII 0x02 106 107 static char *command; 108 static int dmodel; 109 110 #define EXTRACT_BUFSZ 128 /* extract_string() initial size */ 111 #define ENV_CHUNK 16 /* #env ptrs to read at a time */ 112 113 static jmp_buf env; /* malloc failure handling */ 114 115 static void * 116 safe_zalloc(size_t size) 117 { 118 void *p; 119 120 /* 121 * If the malloc fails we longjmp out to allow the code to Prelease() 122 * a stopped victim if needed. 123 */ 124 if ((p = malloc(size)) == NULL) { 125 longjmp(env, errno); 126 } 127 128 bzero(p, size); 129 return (p); 130 } 131 132 static char * 133 safe_strdup(const char *s1) 134 { 135 char *s2; 136 137 s2 = safe_zalloc(strlen(s1) + 1); 138 (void) strcpy(s2, s1); 139 return (s2); 140 } 141 142 /* 143 * Given a wchar_t which might represent an 'escapable' sequence (see 144 * formats(7)), return the base ascii character needed to print that 145 * sequence. 146 * 147 * The comparisons performed may look suspect at first, but all are valid; 148 * the characters below all appear in the "Portable Character Set." The 149 * Single Unix Spec says: "The wide-character value for each member of the 150 * Portable Character Set will equal its value when used as the lone 151 * character in an integer character constant." 152 */ 153 static uchar_t 154 get_interp_char(wchar_t wc) 155 { 156 switch (wc) { 157 case L'\a': 158 return ('a'); 159 case L'\b': 160 return ('b'); 161 case L'\f': 162 return ('f'); 163 case L'\n': 164 return ('n'); 165 case L'\r': 166 return ('r'); 167 case L'\t': 168 return ('t'); 169 case L'\v': 170 return ('v'); 171 case L'\\': 172 return ('\\'); 173 } 174 return ('\0'); 175 } 176 177 static char * 178 unctrl_str_strict_ascii(const char *src, int escape_slash, int *unprintable) 179 { 180 uchar_t *uc, *ucp, c, ic; 181 uc = ucp = safe_zalloc((strlen(src) * 4) + 1); 182 while ((c = *src++) != '\0') { 183 /* 184 * Call get_interp_char *first*, since \ will otherwise not 185 * be escaped as \\. 186 */ 187 if ((ic = get_interp_char((wchar_t)c)) != '\0') { 188 if (escape_slash || ic != '\\') 189 *ucp++ = '\\'; 190 *ucp++ = ic; 191 } else if (isascii(c) && isprint(c)) { 192 *ucp++ = c; 193 } else { 194 *ucp++ = '\\'; 195 *ucp++ = ((c >> 6) & 7) + '0'; 196 *ucp++ = ((c >> 3) & 7) + '0'; 197 *ucp++ = (c & 7) + '0'; 198 *unprintable = 1; 199 } 200 } 201 *ucp = '\0'; 202 return ((char *)uc); 203 } 204 205 /* 206 * Convert control characters as described in formats(7) to their readable 207 * representation; special care is taken to handle multibyte character sets. 208 * 209 * If escape_slash is true, escaping of '\' occurs. The first time a string 210 * is unctrl'd, this should be '1'. Subsequent iterations over the same 211 * string should set escape_slash to 0. Otherwise you'll wind up with 212 * \ --> \\ --> \\\\. 213 */ 214 static char * 215 unctrl_str(const char *src, int escape_slash, int *unprintable) 216 { 217 wchar_t wc; 218 wchar_t *wide_src, *wide_srcp; 219 wchar_t *wide_dest, *wide_destp; 220 char *uc; 221 size_t srcbufsz = strlen(src) + 1; 222 size_t destbufsz = srcbufsz * 4; 223 size_t srclen, destlen; 224 225 wide_srcp = wide_src = safe_zalloc(srcbufsz * sizeof (wchar_t)); 226 wide_destp = wide_dest = safe_zalloc(destbufsz * sizeof (wchar_t)); 227 228 if ((srclen = mbstowcs(wide_src, src, srcbufsz - 1)) == (size_t)-1) { 229 /* 230 * We can't trust the string, since in the locale in which 231 * this call is operating, the string contains an invalid 232 * multibyte sequence. There isn't much to do here, so 233 * convert the string byte by byte to wide characters, as 234 * if it came from a C locale (char) string. This isn't 235 * perfect, but at least the characters will make it to 236 * the screen. 237 */ 238 free(wide_src); 239 free(wide_dest); 240 return (unctrl_str_strict_ascii(src, escape_slash, 241 unprintable)); 242 } 243 if (srclen == (srcbufsz - 1)) { 244 wide_src[srclen] = L'\0'; 245 } 246 247 while ((wc = *wide_srcp++) != L'\0') { 248 char cvt_buf[MB_LEN_MAX]; 249 int len, i; 250 char c = get_interp_char(wc); 251 252 if ((c != '\0') && (escape_slash || c != '\\')) { 253 /* 254 * Print "interpreted version" (\n, \a, etc). 255 */ 256 *wide_destp++ = L'\\'; 257 *wide_destp++ = (wchar_t)c; 258 continue; 259 } 260 261 if (iswprint(wc)) { 262 *wide_destp++ = wc; 263 continue; 264 } 265 266 /* 267 * Convert the wide char back into (potentially several) 268 * multibyte characters, then escape out each of those bytes. 269 */ 270 bzero(cvt_buf, sizeof (cvt_buf)); 271 if ((len = wctomb(cvt_buf, wc)) == -1) { 272 /* 273 * This is a totally invalid wide char; discard it. 274 */ 275 continue; 276 } 277 for (i = 0; i < len; i++) { 278 uchar_t c = cvt_buf[i]; 279 *wide_destp++ = L'\\'; 280 *wide_destp++ = (wchar_t)('0' + ((c >> 6) & 7)); 281 *wide_destp++ = (wchar_t)('0' + ((c >> 3) & 7)); 282 *wide_destp++ = (wchar_t)('0' + (c & 7)); 283 *unprintable = 1; 284 } 285 } 286 287 *wide_destp = '\0'; 288 destlen = (wide_destp - wide_dest) * MB_CUR_MAX + 1; 289 uc = safe_zalloc(destlen); 290 if (wcstombs(uc, wide_dest, destlen) == (size_t)-1) { 291 /* If we've gotten this far, wcstombs shouldn't fail... */ 292 (void) fprintf(stderr, "%s: wcstombs failed unexpectedly: %s\n", 293 command, strerror(errno)); 294 exit(1); 295 } else { 296 char *tmp; 297 /* 298 * Try to save memory; don't waste 3 * strlen in the 299 * common case. 300 */ 301 tmp = safe_strdup(uc); 302 free(uc); 303 uc = tmp; 304 } 305 free(wide_dest); 306 free(wide_src); 307 return (uc); 308 } 309 310 /* 311 * These functions determine which characters are safe to be left unquoted. 312 * Rather than starting with every printable character and subtracting out the 313 * shell metacharacters, we take the more conservative approach of starting with 314 * a set of safe characters and adding those few common punctuation characters 315 * which are known to be safe. The rules are: 316 * 317 * If this is a printable character (graph), and not punctuation, it is 318 * safe to leave unquoted. 319 * 320 * If it's one of the known hard-coded safe characters, it's also safe to 321 * leave unquoted. 322 * 323 * Otherwise, the entire argument must be quoted. 324 * 325 * This will cause some strings to be unnecessarily quoted, but it is safer than 326 * having a character unintentionally interpreted by the shell. 327 */ 328 static int 329 issafe_ascii(char c) 330 { 331 return (isalnum(c) || strchr("_.-/@:,", c) != NULL); 332 } 333 334 static int 335 issafe(wchar_t wc) 336 { 337 return ((iswgraph(wc) && !iswpunct(wc)) || 338 wschr(L"_.-/@:,", wc) != NULL); 339 } 340 341 /*ARGSUSED*/ 342 static char * 343 quote_string_ascii(pargs_data_t *datap, char *src) 344 { 345 char *dst; 346 int quote_count = 0; 347 int need_quote = 0; 348 char *srcp, *dstp; 349 size_t dstlen; 350 351 for (srcp = src; *srcp != '\0'; srcp++) { 352 if (!issafe_ascii(*srcp)) { 353 need_quote = 1; 354 if (*srcp == '\'') 355 quote_count++; 356 } 357 } 358 359 if (!need_quote) 360 return (src); 361 362 /* 363 * The only character we care about here is a single quote. All the 364 * other unprintable characters (and backslashes) will have been dealt 365 * with by unctrl_str(). We make the following subtitution when we 366 * encounter a single quote: 367 * 368 * ' = '"'"' 369 * 370 * In addition, we put single quotes around the entire argument. For 371 * example: 372 * 373 * foo'bar = 'foo'"'"'bar' 374 */ 375 dstlen = strlen(src) + 3 + 4 * quote_count; 376 dst = safe_zalloc(dstlen); 377 378 dstp = dst; 379 *dstp++ = '\''; 380 for (srcp = src; *srcp != '\0'; srcp++, dstp++) { 381 *dstp = *srcp; 382 383 if (*srcp == '\'') { 384 dstp[1] = '"'; 385 dstp[2] = '\''; 386 dstp[3] = '"'; 387 dstp[4] = '\''; 388 dstp += 4; 389 } 390 } 391 *dstp++ = '\''; 392 *dstp = '\0'; 393 394 free(src); 395 396 return (dst); 397 } 398 399 static char * 400 quote_string(pargs_data_t *datap, char *src) 401 { 402 wchar_t *wide_src, *wide_srcp; 403 wchar_t *wide_dest, *wide_destp; 404 char *uc; 405 size_t srcbufsz = strlen(src) + 1; 406 size_t srclen; 407 size_t destbufsz; 408 size_t destlen; 409 int quote_count = 0; 410 int need_quote = 0; 411 412 if (datap->pd_conv_flags & CONV_STRICT_ASCII) 413 return (quote_string_ascii(datap, src)); 414 415 wide_srcp = wide_src = safe_zalloc(srcbufsz * sizeof (wchar_t)); 416 417 if ((srclen = mbstowcs(wide_src, src, srcbufsz - 1)) == (size_t)-1) { 418 free(wide_src); 419 return (quote_string_ascii(datap, src)); 420 } 421 422 if (srclen == srcbufsz - 1) 423 wide_src[srclen] = L'\0'; 424 425 for (wide_srcp = wide_src; *wide_srcp != '\0'; wide_srcp++) { 426 if (!issafe(*wide_srcp)) { 427 need_quote = 1; 428 if (*wide_srcp == L'\'') 429 quote_count++; 430 } 431 } 432 433 if (!need_quote) { 434 free(wide_src); 435 return (src); 436 } 437 438 /* 439 * See comment for quote_string_ascii(), above. 440 */ 441 destbufsz = srcbufsz + 3 + 4 * quote_count; 442 wide_destp = wide_dest = safe_zalloc(destbufsz * sizeof (wchar_t)); 443 444 *wide_destp++ = L'\''; 445 for (wide_srcp = wide_src; *wide_srcp != L'\0'; 446 wide_srcp++, wide_destp++) { 447 *wide_destp = *wide_srcp; 448 449 if (*wide_srcp == L'\'') { 450 wide_destp[1] = L'"'; 451 wide_destp[2] = L'\''; 452 wide_destp[3] = L'"'; 453 wide_destp[4] = L'\''; 454 wide_destp += 4; 455 } 456 } 457 *wide_destp++ = L'\''; 458 *wide_destp = L'\0'; 459 460 destlen = destbufsz * MB_CUR_MAX + 1; 461 uc = safe_zalloc(destlen); 462 if (wcstombs(uc, wide_dest, destlen) == (size_t)-1) { 463 /* If we've gotten this far, wcstombs shouldn't fail... */ 464 (void) fprintf(stderr, "%s: wcstombs failed unexpectedly: %s\n", 465 command, strerror(errno)); 466 exit(1); 467 } 468 469 free(wide_dest); 470 free(wide_src); 471 472 return (uc); 473 } 474 475 476 /* 477 * Determine the locale of the target process by traversing its environment, 478 * making only one pass for efficiency's sake; stash the result in 479 * datap->pd_locale. 480 * 481 * It's possible that the process has called setlocale() to change its 482 * locale to something different, but we mostly care about making a good 483 * guess as to the locale at exec(2) time. 484 */ 485 static void 486 lookup_locale(pargs_data_t *datap) 487 { 488 int i, j, composite = 0; 489 size_t len = 0; 490 char *pd_locale; 491 char *lc_all = NULL, *lang = NULL; 492 char *lcs[] = { NULL, NULL, NULL, NULL, NULL, NULL }; 493 static const char *cat_names[] = { 494 "LC_CTYPE=", "LC_NUMERIC=", "LC_TIME=", 495 "LC_COLLATE=", "LC_MONETARY=", "LC_MESSAGES=" 496 }; 497 498 for (i = 0; i < datap->pd_envc; i++) { 499 char *s = datap->pd_envp_strs[i]; 500 501 if (s == NULL) 502 continue; 503 504 if (strncmp("LC_ALL=", s, strlen("LC_ALL=")) == 0) { 505 /* 506 * Minor optimization-- if we find LC_ALL we're done. 507 */ 508 lc_all = s + strlen("LC_ALL="); 509 break; 510 } 511 for (j = 0; j <= _LastCategory; j++) { 512 if (strncmp(cat_names[j], s, 513 strlen(cat_names[j])) == 0) { 514 lcs[j] = s + strlen(cat_names[j]); 515 } 516 } 517 if (strncmp("LANG=", s, strlen("LANG=")) == 0) { 518 lang = s + strlen("LANG="); 519 } 520 } 521 522 if (lc_all && (*lc_all == '\0')) 523 lc_all = NULL; 524 if (lang && (*lang == '\0')) 525 lang = NULL; 526 527 for (i = 0; i <= _LastCategory; i++) { 528 if (lc_all != NULL) { 529 lcs[i] = lc_all; 530 } else if (lcs[i] != NULL) { 531 lcs[i] = lcs[i]; 532 } else if (lang != NULL) { 533 lcs[i] = lang; 534 } else { 535 lcs[i] = "C"; 536 } 537 if ((i > 0) && (lcs[i] != lcs[i-1])) 538 composite++; 539 540 len += 1 + strlen(lcs[i]); /* 1 extra byte for '/' */ 541 } 542 543 if (composite == 0) { 544 /* simple locale */ 545 pd_locale = safe_strdup(lcs[0]); 546 } else { 547 /* composite locale */ 548 pd_locale = safe_zalloc(len + 1); 549 (void) snprintf(pd_locale, len + 1, "/%s/%s/%s/%s/%s/%s", 550 lcs[0], lcs[1], lcs[2], lcs[3], lcs[4], lcs[5]); 551 } 552 datap->pd_locale = pd_locale; 553 } 554 555 /* 556 * Pull a string from the victim, regardless of size; this routine allocates 557 * memory for the string which must be freed by the caller. 558 */ 559 static char * 560 extract_string(pargs_data_t *datap, uintptr_t addr) 561 { 562 int size = EXTRACT_BUFSZ; 563 char *result; 564 565 result = safe_zalloc(size); 566 567 for (;;) { 568 if (Pread_string(datap->pd_proc, result, size, addr) < 0) { 569 free(result); 570 return (NULL); 571 } else if (strlen(result) == (size - 1)) { 572 free(result); 573 size *= 2; 574 result = safe_zalloc(size); 575 } else { 576 break; 577 } 578 } 579 return (result); 580 } 581 582 /* 583 * Utility function to read an array of pointers from the victim, adjusting 584 * for victim data model; returns the number of bytes successfully read. 585 */ 586 static ssize_t 587 read_ptr_array(pargs_data_t *datap, uintptr_t offset, uintptr_t *buf, 588 size_t nelems) 589 { 590 ssize_t res; 591 592 if (dmodel == PR_MODEL_NATIVE) { 593 res = Pread(datap->pd_proc, buf, nelems * sizeof (uintptr_t), 594 offset); 595 } else { 596 int i; 597 uint32_t *arr32 = safe_zalloc(nelems * sizeof (uint32_t)); 598 599 res = Pread(datap->pd_proc, arr32, nelems * sizeof (uint32_t), 600 offset); 601 if (res > 0) { 602 for (i = 0; i < nelems; i++) 603 buf[i] = arr32[i]; 604 } 605 free(arr32); 606 } 607 return (res); 608 } 609 610 /* 611 * Extract the argv array from the victim; store the pointer values in 612 * datap->pd_argv and the extracted strings in datap->pd_argv_strs. 613 */ 614 static void 615 get_args(pargs_data_t *datap) 616 { 617 size_t argc = datap->pd_psinfo->pr_argc; 618 uintptr_t argvoff = datap->pd_psinfo->pr_argv; 619 int i; 620 621 datap->pd_argc = argc; 622 datap->pd_argv = safe_zalloc(argc * sizeof (uintptr_t)); 623 624 if (read_ptr_array(datap, argvoff, datap->pd_argv, argc) <= 0) { 625 free(datap->pd_argv); 626 datap->pd_argv = NULL; 627 datap->pd_argc = 0; 628 return; 629 } 630 631 datap->pd_argv_strs = safe_zalloc(argc * sizeof (char *)); 632 for (i = 0; i < argc; i++) { 633 if (datap->pd_argv[i] == 0) 634 continue; 635 datap->pd_argv_strs[i] = extract_string(datap, 636 datap->pd_argv[i]); 637 } 638 } 639 640 /*ARGSUSED*/ 641 static int 642 build_env(void *data, struct ps_prochandle *pr, uintptr_t addr, const char *str) 643 { 644 pargs_data_t *datap = data; 645 646 if (datap->pd_envp != NULL) { 647 if (datap->pd_envc == datap->pd_env_space) { 648 /* 649 * Not enough space for storing the env (it has more 650 * items than before). Try to grow both arrays. 651 */ 652 void *new = realloc(datap->pd_envp, 653 sizeof (uintptr_t) * datap->pd_env_space * 2); 654 if (new == NULL) 655 return (1); 656 datap->pd_envp = new; 657 658 new = realloc(datap->pd_envp_strs, 659 sizeof (char *) * datap->pd_env_space * 2); 660 if (new == NULL) 661 return (1); 662 datap->pd_envp_strs = new; 663 664 datap->pd_env_space *= 2; 665 } 666 667 datap->pd_envp[datap->pd_envc] = addr; 668 if (str == NULL) 669 datap->pd_envp_strs[datap->pd_envc] = NULL; 670 else 671 datap->pd_envp_strs[datap->pd_envc] = strdup(str); 672 } 673 674 datap->pd_envc++; 675 676 return (0); 677 } 678 679 static void 680 get_env(pargs_data_t *datap) 681 { 682 struct ps_prochandle *pr = datap->pd_proc; 683 684 datap->pd_envc = 0; 685 (void) Penv_iter(pr, build_env, datap); 686 687 /* We must allocate space for at least one entry */ 688 datap->pd_env_space = datap->pd_envc != 0 ? datap->pd_envc : 1; 689 datap->pd_envp = safe_zalloc(sizeof (uintptr_t) * datap->pd_env_space); 690 datap->pd_envp_strs = 691 safe_zalloc(sizeof (char *) * datap->pd_env_space); 692 693 datap->pd_envc = 0; 694 (void) Penv_iter(pr, build_env, datap); 695 } 696 697 /* 698 * The following at_* routines are used to decode data from the aux vector. 699 */ 700 701 /*ARGSUSED*/ 702 static void 703 at_null(long val, char *instr, size_t n, char *str) 704 { 705 str[0] = '\0'; 706 } 707 708 /*ARGSUSED*/ 709 static void 710 at_str(long val, char *instr, size_t n, char *str) 711 { 712 str[0] = '\0'; 713 if (instr != NULL) { 714 (void) strlcpy(str, instr, n); 715 } 716 } 717 718 /* 719 * Note: Don't forget to add a corresponding case to isainfo(1). 720 */ 721 722 #define FMT_AV(s, n, hwcap, mask, name) \ 723 if ((hwcap) & (mask)) \ 724 (void) snprintf(s, n, "%s" name " | ", s) 725 726 /*ARGSUSED*/ 727 static void 728 at_hwcap(long val, char *instr, size_t n, char *str) 729 { 730 #if defined(__sparc) || defined(__sparcv9) 731 (void) elfcap_hw1_to_str(ELFCAP_STYLE_UC, val, str, n, 732 ELFCAP_FMT_PIPSPACE, EM_SPARC); 733 734 #elif defined(__i386) || defined(__amd64) 735 (void) elfcap_hw1_to_str(ELFCAP_STYLE_UC, val, str, n, 736 ELFCAP_FMT_PIPSPACE, EM_386); 737 #else 738 #error "port me" 739 #endif 740 } 741 742 /*ARGSUSED*/ 743 static void 744 at_hwcap2(long val, char *instr, size_t n, char *str) 745 { 746 #if defined(__sparc) || defined(__sparcv9) 747 (void) elfcap_hw2_to_str(ELFCAP_STYLE_UC, val, str, n, 748 ELFCAP_FMT_PIPSPACE, EM_SPARC); 749 750 #elif defined(__i386) || defined(__amd64) 751 (void) elfcap_hw2_to_str(ELFCAP_STYLE_UC, val, str, n, 752 ELFCAP_FMT_PIPSPACE, EM_386); 753 #else 754 #error "port me" 755 #endif 756 } 757 758 /*ARGSUSED*/ 759 static void 760 at_hwcap3(long val, char *instr, size_t n, char *str) 761 { 762 #if defined(__i386) || defined(__amd64) 763 (void) elfcap_hw3_to_str(ELFCAP_STYLE_UC, val, str, n, 764 ELFCAP_FMT_PIPSPACE, EM_386); 765 #else 766 #error "port me" 767 #endif 768 } 769 770 /*ARGSUSED*/ 771 static void 772 at_uid(long val, char *instr, size_t n, char *str) 773 { 774 struct passwd *pw = getpwuid((uid_t)val); 775 776 if ((pw == NULL) || (pw->pw_name == NULL)) 777 str[0] = '\0'; 778 else 779 (void) snprintf(str, n, "%lu(%s)", val, pw->pw_name); 780 } 781 782 783 /*ARGSUSED*/ 784 static void 785 at_gid(long val, char *instr, size_t n, char *str) 786 { 787 struct group *gr = getgrgid((gid_t)val); 788 789 if ((gr == NULL) || (gr->gr_name == NULL)) 790 str[0] = '\0'; 791 else 792 (void) snprintf(str, n, "%lu(%s)", val, gr->gr_name); 793 } 794 795 static struct auxfl { 796 int af_flag; 797 const char *af_name; 798 } auxfl[] = { 799 { AF_SUN_SETUGID, "setugid" }, 800 }; 801 802 /*ARGSUSED*/ 803 static void 804 at_flags(long val, char *instr, size_t n, char *str) 805 { 806 int i; 807 808 *str = '\0'; 809 810 for (i = 0; i < sizeof (auxfl)/sizeof (struct auxfl); i++) { 811 if ((val & auxfl[i].af_flag) != 0) { 812 if (*str != '\0') 813 (void) strlcat(str, ",", n); 814 (void) strlcat(str, auxfl[i].af_name, n); 815 } 816 } 817 } 818 819 #define MAX_AT_NAME_LEN 15 820 821 struct aux_id { 822 int aux_type; 823 const char *aux_name; 824 void (*aux_decode)(long, char *, size_t, char *); 825 }; 826 827 static struct aux_id aux_arr[] = { 828 { AT_NULL, "AT_NULL", at_null }, 829 { AT_IGNORE, "AT_IGNORE", at_null }, 830 { AT_EXECFD, "AT_EXECFD", at_null }, 831 { AT_PHDR, "AT_PHDR", at_null }, 832 { AT_PHENT, "AT_PHENT", at_null }, 833 { AT_PHNUM, "AT_PHNUM", at_null }, 834 { AT_PAGESZ, "AT_PAGESZ", at_null }, 835 { AT_BASE, "AT_BASE", at_null }, 836 { AT_FLAGS, "AT_FLAGS", at_null }, 837 { AT_ENTRY, "AT_ENTRY", at_null }, 838 { AT_SUN_UID, "AT_SUN_UID", at_uid }, 839 { AT_SUN_RUID, "AT_SUN_RUID", at_uid }, 840 { AT_SUN_GID, "AT_SUN_GID", at_gid }, 841 { AT_SUN_RGID, "AT_SUN_RGID", at_gid }, 842 { AT_SUN_LDELF, "AT_SUN_LDELF", at_null }, 843 { AT_SUN_LDSHDR, "AT_SUN_LDSHDR", at_null }, 844 { AT_SUN_LDNAME, "AT_SUN_LDNAME", at_null }, 845 { AT_SUN_LPAGESZ, "AT_SUN_LPAGESZ", at_null }, 846 { AT_SUN_PLATFORM, "AT_SUN_PLATFORM", at_str }, 847 { AT_SUN_EXECNAME, "AT_SUN_EXECNAME", at_str }, 848 { AT_SUN_HWCAP, "AT_SUN_HWCAP", at_hwcap }, 849 { AT_SUN_HWCAP2, "AT_SUN_HWCAP2", at_hwcap2 }, 850 { AT_SUN_HWCAP3, "AT_SUN_HWCAP3", at_hwcap3 }, 851 { AT_SUN_IFLUSH, "AT_SUN_IFLUSH", at_null }, 852 { AT_SUN_CPU, "AT_SUN_CPU", at_null }, 853 { AT_SUN_MMU, "AT_SUN_MMU", at_null }, 854 { AT_SUN_LDDATA, "AT_SUN_LDDATA", at_null }, 855 { AT_SUN_AUXFLAGS, "AT_SUN_AUXFLAGS", at_flags }, 856 { AT_SUN_EMULATOR, "AT_SUN_EMULATOR", at_str }, 857 { AT_SUN_BRANDNAME, "AT_SUN_BRANDNAME", at_str }, 858 { AT_SUN_BRAND_AUX1, "AT_SUN_BRAND_AUX1", at_null }, 859 { AT_SUN_BRAND_AUX2, "AT_SUN_BRAND_AUX2", at_null }, 860 { AT_SUN_BRAND_AUX3, "AT_SUN_BRAND_AUX3", at_null }, 861 { AT_SUN_COMMPAGE, "AT_SUN_COMMPAGE", at_null }, 862 { AT_SUN_FPTYPE, "AT_SUN_FPTYPE", at_null }, 863 { AT_SUN_FPSIZE, "AT_SUN_FPSIZE", at_null } 864 }; 865 866 #define N_AT_ENTS (sizeof (aux_arr) / sizeof (struct aux_id)) 867 868 /* 869 * Return the aux_id entry for the given aux type; returns NULL if not found. 870 */ 871 static struct aux_id * 872 aux_find(int type) 873 { 874 int i; 875 876 for (i = 0; i < N_AT_ENTS; i++) { 877 if (type == aux_arr[i].aux_type) 878 return (&aux_arr[i]); 879 } 880 881 return (NULL); 882 } 883 884 static void 885 get_auxv(pargs_data_t *datap) 886 { 887 int i; 888 const auxv_t *auxvp; 889 890 /* 891 * Fetch the aux vector from the target process. 892 */ 893 if (ps_pauxv(datap->pd_proc, &auxvp) != PS_OK) 894 return; 895 896 for (i = 0; auxvp[i].a_type != AT_NULL; i++) 897 continue; 898 899 datap->pd_auxc = i; 900 datap->pd_auxv = safe_zalloc(i * sizeof (auxv_t)); 901 bcopy(auxvp, datap->pd_auxv, i * sizeof (auxv_t)); 902 903 datap->pd_auxv_strs = safe_zalloc(datap->pd_auxc * sizeof (char *)); 904 for (i = 0; i < datap->pd_auxc; i++) { 905 struct aux_id *aux = aux_find(datap->pd_auxv[i].a_type); 906 907 /* 908 * Grab strings for those entries which have a string-decoder. 909 */ 910 if ((aux != NULL) && (aux->aux_decode == at_str)) { 911 datap->pd_auxv_strs[i] = 912 extract_string(datap, datap->pd_auxv[i].a_un.a_val); 913 } 914 } 915 } 916 917 /* 918 * Prepare to convert characters in the victim's character set into user's 919 * character set. 920 */ 921 static void 922 setup_conversions(pargs_data_t *datap, int *diflocale) 923 { 924 char *mylocale = NULL, *mycharset = NULL; 925 char *targetlocale = NULL, *targetcharset = NULL; 926 927 mycharset = safe_strdup(nl_langinfo(CODESET)); 928 929 mylocale = setlocale(LC_CTYPE, NULL); 930 if ((mylocale == NULL) || (strcmp(mylocale, "") == 0)) 931 mylocale = "C"; 932 mylocale = safe_strdup(mylocale); 933 934 if (datap->pd_conv_flags & CONV_STRICT_ASCII) 935 goto done; 936 937 /* 938 * If the target's locale is "C" or "POSIX", go fast. 939 */ 940 if ((strcmp(datap->pd_locale, "C") == 0) || 941 (strcmp(datap->pd_locale, "POSIX") == 0)) { 942 datap->pd_conv_flags |= CONV_STRICT_ASCII; 943 goto done; 944 } 945 946 /* 947 * Switch to the victim's locale, and discover its character set. 948 */ 949 if (setlocale(LC_ALL, datap->pd_locale) == NULL) { 950 (void) fprintf(stderr, 951 "%s: Couldn't determine locale of target process.\n", 952 command); 953 (void) fprintf(stderr, 954 "%s: Some strings may not be displayed properly.\n", 955 command); 956 goto done; 957 } 958 959 /* 960 * Get LC_CTYPE part of target's locale, and its codeset. 961 */ 962 targetlocale = safe_strdup(setlocale(LC_CTYPE, NULL)); 963 targetcharset = safe_strdup(nl_langinfo(CODESET)); 964 965 /* 966 * Now go fully back to the pargs user's locale. 967 */ 968 (void) setlocale(LC_ALL, ""); 969 970 /* 971 * It's safe to bail here if the lc_ctype of the locales are the 972 * same-- we know that their encodings and characters sets are the same. 973 */ 974 if (strcmp(targetlocale, mylocale) == 0) 975 goto done; 976 977 *diflocale = 1; 978 979 /* 980 * If the codeset of the victim matches our codeset then iconv need 981 * not be involved. 982 */ 983 if (strcmp(mycharset, targetcharset) == 0) 984 goto done; 985 986 if ((datap->pd_iconv = iconv_open(mycharset, targetcharset)) 987 == (iconv_t)-1) { 988 /* 989 * EINVAL indicates there was no conversion available 990 * from victim charset to mycharset 991 */ 992 if (errno != EINVAL) { 993 (void) fprintf(stderr, 994 "%s: failed to initialize iconv: %s\n", 995 command, strerror(errno)); 996 exit(1); 997 } 998 datap->pd_conv_flags |= CONV_STRICT_ASCII; 999 } else { 1000 datap->pd_conv_flags |= CONV_USE_ICONV; 1001 } 1002 done: 1003 free(mycharset); 1004 free(mylocale); 1005 free(targetcharset); 1006 free(targetlocale); 1007 } 1008 1009 static void 1010 cleanup_conversions(pargs_data_t *datap) 1011 { 1012 if (datap->pd_conv_flags & CONV_USE_ICONV) { 1013 (void) iconv_close(datap->pd_iconv); 1014 } 1015 } 1016 1017 static char * 1018 convert_run_iconv(pargs_data_t *datap, const char *str) 1019 { 1020 size_t inleft, outleft, bufsz = 64; 1021 char *outstr, *outstrptr; 1022 const char *instrptr; 1023 1024 for (;;) { 1025 outstrptr = outstr = safe_zalloc(bufsz + 1); 1026 outleft = bufsz; 1027 1028 /* 1029 * Generate the "initial shift state" sequence, placing that 1030 * at the head of the string. 1031 */ 1032 inleft = 0; 1033 (void) iconv(datap->pd_iconv, NULL, &inleft, 1034 &outstrptr, &outleft); 1035 1036 inleft = strlen(str); 1037 instrptr = str; 1038 if (iconv(datap->pd_iconv, &instrptr, &inleft, &outstrptr, 1039 &outleft) != (size_t)-1) { 1040 /* 1041 * Outstr must be null terminated upon exit from 1042 * iconv(). 1043 */ 1044 *(outstr + (bufsz - outleft)) = '\0'; 1045 break; 1046 } else if (errno == E2BIG) { 1047 bufsz *= 2; 1048 free(outstr); 1049 } else if ((errno == EILSEQ) || (errno == EINVAL)) { 1050 free(outstr); 1051 return (NULL); 1052 } else { 1053 /* 1054 * iconv() could in theory return EBADF, but that 1055 * shouldn't happen. 1056 */ 1057 (void) fprintf(stderr, 1058 "%s: iconv(3C) failed unexpectedly: %s\n", 1059 command, strerror(errno)); 1060 1061 exit(1); 1062 } 1063 } 1064 return (outstr); 1065 } 1066 1067 /* 1068 * Returns a freshly allocated string converted to the local character set, 1069 * removed of unprintable characters. 1070 */ 1071 static char * 1072 convert_str(pargs_data_t *datap, const char *str, int *unprintable) 1073 { 1074 char *retstr, *tmp; 1075 1076 if (datap->pd_conv_flags & CONV_STRICT_ASCII) { 1077 retstr = unctrl_str_strict_ascii(str, 1, unprintable); 1078 return (retstr); 1079 } 1080 1081 if ((datap->pd_conv_flags & CONV_USE_ICONV) == 0) { 1082 /* 1083 * If we aren't using iconv(), convert control chars in 1084 * the string in pargs' locale, since that is the display 1085 * locale. 1086 */ 1087 retstr = unctrl_str(str, 1, unprintable); 1088 return (retstr); 1089 } 1090 1091 /* 1092 * The logic here is a bit (ahem) tricky. Start by converting 1093 * unprintable characters *in the target's locale*. This should 1094 * eliminate a variety of unprintable or illegal characters-- in 1095 * short, it should leave us with something which iconv() won't 1096 * have trouble with. 1097 * 1098 * After allowing iconv to convert characters as needed, run unctrl 1099 * again in pargs' locale-- This time to make sure that any 1100 * characters which aren't printable according to the *current* 1101 * locale (independent of the current codeset) get taken care of. 1102 * Without this second stage, we might (for example) fail to 1103 * properly handle characters converted into the 646 character set 1104 * (which are 8-bits wide), but which must be displayed in the C 1105 * locale (which uses 646, but whose printable characters are a 1106 * subset of the 7-bit characters). 1107 * 1108 * Note that assuming the victim's locale using LC_ALL will be 1109 * problematic when pargs' messages are internationalized in the 1110 * future (and it calls textdomain(3C)). In this case, any 1111 * error message fprintf'd in unctrl_str() will be in the wrong 1112 * LC_MESSAGES class. We'll cross that bridge when we come to it. 1113 */ 1114 (void) setlocale(LC_ALL, datap->pd_locale); 1115 retstr = unctrl_str(str, 1, unprintable); 1116 (void) setlocale(LC_ALL, ""); 1117 1118 tmp = retstr; 1119 if ((retstr = convert_run_iconv(datap, retstr)) == NULL) { 1120 /* 1121 * In this (rare but real) case, the iconv() failed even 1122 * though we unctrl'd the string. Treat the original string 1123 * (str) as a C locale string and strip it that way. 1124 */ 1125 free(tmp); 1126 return (unctrl_str_strict_ascii(str, 0, unprintable)); 1127 } 1128 1129 free(tmp); 1130 tmp = retstr; 1131 /* 1132 * Run unctrl_str, but make sure not to escape \ characters, which 1133 * may have resulted from the first round of unctrl. 1134 */ 1135 retstr = unctrl_str(retstr, 0, unprintable); 1136 free(tmp); 1137 return (retstr); 1138 } 1139 1140 1141 static void 1142 convert_array(pargs_data_t *datap, char **arr, size_t count, int *unprintable) 1143 { 1144 int i; 1145 char *tmp; 1146 1147 if (arr == NULL) 1148 return; 1149 1150 for (i = 0; i < count; i++) { 1151 if ((tmp = arr[i]) == NULL) 1152 continue; 1153 arr[i] = convert_str(datap, arr[i], unprintable); 1154 free(tmp); 1155 } 1156 } 1157 1158 /* 1159 * Free data allocated during the gathering phase. 1160 */ 1161 static void 1162 free_data(pargs_data_t *datap) 1163 { 1164 int i; 1165 1166 for (i = 0; i < datap->pd_argc; i++) 1167 free(datap->pd_argv_strs[i]); 1168 free(datap->pd_argv); 1169 free(datap->pd_argv_strs); 1170 1171 for (i = 0; i < datap->pd_envc; i++) 1172 free(datap->pd_envp_strs[i]); 1173 free(datap->pd_envp); 1174 free(datap->pd_envp_strs); 1175 1176 for (i = 0; i < datap->pd_auxc; i++) 1177 free(datap->pd_auxv_strs[i]); 1178 free(datap->pd_auxv); 1179 free(datap->pd_auxv_strs); 1180 } 1181 1182 static void 1183 print_args(pargs_data_t *datap) 1184 { 1185 int i; 1186 1187 if (datap->pd_argv == NULL) { 1188 (void) fprintf(stderr, "%s: failed to read argv[]\n", command); 1189 return; 1190 } 1191 1192 for (i = 0; i < datap->pd_argc; i++) { 1193 (void) printf("argv[%d]: ", i); 1194 if (datap->pd_argv[i] == (uintptr_t)NULL) { 1195 (void) printf("<NULL>\n"); 1196 } else if (datap->pd_argv_strs[i] == NULL) { 1197 (void) printf("<0x%0*lx>\n", 1198 (dmodel == PR_MODEL_LP64)? 16 : 8, 1199 (long)datap->pd_argv[i]); 1200 } else { 1201 (void) printf("%s\n", datap->pd_argv_strs[i]); 1202 } 1203 } 1204 } 1205 1206 static void 1207 print_env(pargs_data_t *datap) 1208 { 1209 int i; 1210 1211 if (datap->pd_envp == NULL) { 1212 (void) fprintf(stderr, "%s: failed to read envp[]\n", command); 1213 return; 1214 } 1215 1216 for (i = 0; i < datap->pd_envc; i++) { 1217 (void) printf("envp[%d]: ", i); 1218 if (datap->pd_envp[i] == 0) { 1219 break; 1220 } else if (datap->pd_envp_strs[i] == NULL) { 1221 (void) printf("<0x%0*lx>\n", 1222 (dmodel == PR_MODEL_LP64)? 16 : 8, 1223 (long)datap->pd_envp[i]); 1224 } else { 1225 (void) printf("%s\n", datap->pd_envp_strs[i]); 1226 } 1227 } 1228 } 1229 1230 static int 1231 print_cmdline(pargs_data_t *datap) 1232 { 1233 int i; 1234 1235 /* 1236 * Go through and check to see if we have valid data. If not, print 1237 * an error message and bail. 1238 */ 1239 for (i = 0; i < datap->pd_argc; i++) { 1240 if (datap->pd_argv == NULL || 1241 datap->pd_argv[i] == (uintptr_t)NULL || 1242 datap->pd_argv_strs[i] == NULL) { 1243 (void) fprintf(stderr, "%s: target has corrupted " 1244 "argument list\n", command); 1245 return (1); 1246 } 1247 1248 datap->pd_argv_strs[i] = 1249 quote_string(datap, datap->pd_argv_strs[i]); 1250 } 1251 1252 if (datap->pd_execname == NULL) { 1253 (void) fprintf(stderr, "%s: cannot determine name of " 1254 "executable\n", command); 1255 return (1); 1256 } 1257 1258 (void) printf("%s ", datap->pd_execname); 1259 1260 for (i = 1; i < datap->pd_argc; i++) 1261 (void) printf("%s ", datap->pd_argv_strs[i]); 1262 1263 (void) printf("\n"); 1264 1265 return (0); 1266 } 1267 1268 static void 1269 print_auxv(pargs_data_t *datap) 1270 { 1271 int i; 1272 const auxv_t *pa; 1273 1274 /* 1275 * Print the names and values of all the aux vector entries. 1276 */ 1277 for (i = 0; i < datap->pd_auxc; i++) { 1278 char type[32]; 1279 char decode[PATH_MAX]; 1280 struct aux_id *aux; 1281 long v; 1282 pa = &datap->pd_auxv[i]; 1283 1284 aux = aux_find(pa->a_type); 1285 v = (long)pa->a_un.a_val; 1286 1287 if (aux != NULL) { 1288 /* 1289 * Fetch aux vector type string and decoded 1290 * representation of the value. 1291 */ 1292 (void) strlcpy(type, aux->aux_name, sizeof (type)); 1293 aux->aux_decode(v, datap->pd_auxv_strs[i], 1294 sizeof (decode), decode); 1295 } else { 1296 (void) snprintf(type, sizeof (type), "%d", pa->a_type); 1297 decode[0] = '\0'; 1298 } 1299 1300 (void) printf("%-*s 0x%0*lx %s\n", MAX_AT_NAME_LEN, type, 1301 (dmodel == PR_MODEL_LP64)? 16 : 8, v, decode); 1302 } 1303 } 1304 1305 int 1306 main(int argc, char *argv[]) 1307 { 1308 int aflag = 0, cflag = 0, eflag = 0, xflag = 0, lflag = 0; 1309 int errflg = 0, retc = 0; 1310 int opt; 1311 int error = 1; 1312 core_content_t content = 0; 1313 pargs_cmd_t cmd = PARGS_ARGV; 1314 1315 (void) setlocale(LC_ALL, ""); 1316 1317 command = basename(argv[0]); 1318 1319 if (strcmp(command, "penv") == 0) 1320 cmd = PARGS_ENV; 1321 else if (strcmp(command, "pauxv") == 0) 1322 cmd = PARGS_AUXV; 1323 1324 while ((opt = getopt(argc, argv, "acelxF")) != EOF) { 1325 switch (opt) { 1326 case 'a': /* show process arguments */ 1327 content |= CC_CONTENT_STACK; 1328 aflag++; 1329 if (cmd != PARGS_ARGV) 1330 errflg++; 1331 break; 1332 case 'c': /* force 7-bit ascii */ 1333 cflag++; 1334 break; 1335 case 'e': /* show environment variables */ 1336 content |= CC_CONTENT_STACK; 1337 eflag++; 1338 if (cmd != PARGS_ARGV) 1339 errflg++; 1340 break; 1341 case 'l': 1342 lflag++; 1343 aflag++; /* -l implies -a */ 1344 if (cmd != PARGS_ARGV) 1345 errflg++; 1346 break; 1347 case 'x': /* show aux vector entries */ 1348 xflag++; 1349 if (cmd != PARGS_ARGV) 1350 errflg++; 1351 break; 1352 case 'F': 1353 /* 1354 * Since we open the process read-only, there is no need 1355 * for the -F flag. It's a documented flag, so we 1356 * consume it silently. 1357 */ 1358 break; 1359 default: 1360 errflg++; 1361 break; 1362 } 1363 } 1364 1365 /* -a is the default if no options are specified */ 1366 if ((aflag + eflag + xflag + lflag) == 0) { 1367 switch (cmd) { 1368 case PARGS_ARGV: 1369 aflag++; 1370 content |= CC_CONTENT_STACK; 1371 break; 1372 case PARGS_ENV: 1373 content |= CC_CONTENT_STACK; 1374 eflag++; 1375 break; 1376 case PARGS_AUXV: 1377 xflag++; 1378 break; 1379 } 1380 } 1381 1382 /* -l cannot be used with the -x or -e flags */ 1383 if (lflag && (xflag || eflag)) { 1384 (void) fprintf(stderr, "-l is incompatible with -x and -e\n"); 1385 errflg++; 1386 } 1387 1388 argc -= optind; 1389 argv += optind; 1390 1391 if (errflg || argc <= 0) { 1392 (void) fprintf(stderr, 1393 "usage: %s [-aceFlx] { pid | core } ...\n" 1394 " (show process arguments and environment)\n" 1395 " -a: show process arguments (default)\n" 1396 " -c: interpret characters as 7-bit ascii regardless of " 1397 "locale\n" 1398 " -e: show environment variables\n" 1399 " -F: force grabbing of the target process\n" 1400 " -l: display arguments as command line\n" 1401 " -x: show aux vector entries\n", command); 1402 return (2); 1403 } 1404 1405 while (argc-- > 0) { 1406 char *arg; 1407 int gret, r; 1408 psinfo_t psinfo; 1409 char *psargs_conv; 1410 struct ps_prochandle *Pr; 1411 pargs_data_t datap; 1412 char *info; 1413 size_t info_sz; 1414 int pstate; 1415 char execname[PATH_MAX]; 1416 int unprintable; 1417 int diflocale; 1418 1419 (void) fflush(stdout); 1420 arg = *argv++; 1421 1422 /* 1423 * Suppress extra blanks lines if we've encountered processes 1424 * which can't be opened. 1425 */ 1426 if (error == 0) { 1427 (void) printf("\n"); 1428 } 1429 error = 0; 1430 1431 /* 1432 * First grab just the psinfo information, in case this 1433 * process is a zombie (in which case proc_arg_grab() will 1434 * fail). If so, print a nice message and continue. 1435 */ 1436 if (proc_arg_psinfo(arg, PR_ARG_ANY, &psinfo, 1437 &gret) == -1) { 1438 (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 1439 command, arg, Pgrab_error(gret)); 1440 retc++; 1441 error = 1; 1442 continue; 1443 } 1444 1445 if (psinfo.pr_nlwp == 0) { 1446 (void) printf("%d: <defunct>\n", (int)psinfo.pr_pid); 1447 continue; 1448 } 1449 1450 /* 1451 * If process is a "system" process (like pageout), just 1452 * print its psargs and continue on. 1453 */ 1454 if (psinfo.pr_size == 0 && psinfo.pr_rssize == 0) { 1455 proc_unctrl_psinfo(&psinfo); 1456 if (!lflag) 1457 (void) printf("%d: ", (int)psinfo.pr_pid); 1458 (void) printf("%s\n", psinfo.pr_psargs); 1459 continue; 1460 } 1461 1462 /* 1463 * Open the process readonly, since we do not need to write to 1464 * the control file. 1465 */ 1466 if ((Pr = proc_arg_grab(arg, PR_ARG_ANY, PGRAB_RDONLY, 1467 &gret)) == NULL) { 1468 (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 1469 command, arg, Pgrab_error(gret)); 1470 retc++; 1471 error = 1; 1472 continue; 1473 } 1474 1475 pstate = Pstate(Pr); 1476 1477 if (pstate == PS_DEAD && 1478 (Pcontent(Pr) & content) != content) { 1479 (void) fprintf(stderr, "%s: core '%s' has " 1480 "insufficient content\n", command, arg); 1481 retc++; 1482 continue; 1483 } 1484 1485 /* 1486 * If malloc() fails, we return here so that we can let go 1487 * of the victim, restore our locale, print a message, 1488 * then exit. 1489 */ 1490 if ((r = setjmp(env)) != 0) { 1491 Prelease(Pr, 0); 1492 (void) setlocale(LC_ALL, ""); 1493 (void) fprintf(stderr, "%s: out of memory: %s\n", 1494 command, strerror(r)); 1495 return (1); 1496 } 1497 1498 dmodel = Pstatus(Pr)->pr_dmodel; 1499 bzero(&datap, sizeof (datap)); 1500 bcopy(Ppsinfo(Pr), &psinfo, sizeof (psinfo_t)); 1501 datap.pd_proc = Pr; 1502 datap.pd_psinfo = &psinfo; 1503 1504 if (cflag) 1505 datap.pd_conv_flags |= CONV_STRICT_ASCII; 1506 1507 /* 1508 * Strip control characters, then record process summary in 1509 * a buffer, since we don't want to print anything out until 1510 * after we release the process. 1511 */ 1512 1513 /* 1514 * The process is neither a system process nor defunct. 1515 * 1516 * Do printing and post-processing (like name lookups) after 1517 * gathering the raw data from the process and releasing it. 1518 * This way, we don't deadlock on (for example) name lookup 1519 * if we grabbed the nscd and do 'pargs -x'. 1520 * 1521 * We always fetch the environment of the target, so that we 1522 * can make an educated guess about its locale. 1523 */ 1524 get_env(&datap); 1525 if (aflag != 0) 1526 get_args(&datap); 1527 if (xflag != 0) 1528 get_auxv(&datap); 1529 1530 /* 1531 * If malloc() fails after this poiint, we return here to 1532 * restore our locale and print a message. If we don't 1533 * reset this, we might erroneously try to Prelease a process 1534 * twice. 1535 */ 1536 if ((r = setjmp(env)) != 0) { 1537 (void) setlocale(LC_ALL, ""); 1538 (void) fprintf(stderr, "%s: out of memory: %s\n", 1539 command, strerror(r)); 1540 return (1); 1541 } 1542 1543 /* 1544 * For the -l option, we need a proper name for this executable 1545 * before we release it. 1546 */ 1547 if (lflag) 1548 datap.pd_execname = Pexecname(Pr, execname, 1549 sizeof (execname)); 1550 1551 Prelease(Pr, 0); 1552 1553 /* 1554 * Crawl through the environment to determine the locale of 1555 * the target. 1556 */ 1557 lookup_locale(&datap); 1558 diflocale = 0; 1559 setup_conversions(&datap, &diflocale); 1560 1561 if (lflag != 0) { 1562 unprintable = 0; 1563 convert_array(&datap, datap.pd_argv_strs, 1564 datap.pd_argc, &unprintable); 1565 if (diflocale) 1566 (void) fprintf(stderr, "%s: Warning, target " 1567 "locale differs from current locale\n", 1568 command); 1569 else if (unprintable) 1570 (void) fprintf(stderr, "%s: Warning, command " 1571 "line contains unprintable characters\n", 1572 command); 1573 1574 retc += print_cmdline(&datap); 1575 } else { 1576 psargs_conv = convert_str(&datap, psinfo.pr_psargs, 1577 &unprintable); 1578 info_sz = strlen(psargs_conv) + MAXPATHLEN + 32 + 1; 1579 info = malloc(info_sz); 1580 if (pstate == PS_DEAD) { 1581 (void) snprintf(info, info_sz, 1582 "core '%s' of %d:\t%s\n", 1583 arg, (int)psinfo.pr_pid, psargs_conv); 1584 } else { 1585 (void) snprintf(info, info_sz, "%d:\t%s\n", 1586 (int)psinfo.pr_pid, psargs_conv); 1587 } 1588 (void) printf("%s", info); 1589 free(info); 1590 free(psargs_conv); 1591 1592 if (aflag != 0) { 1593 convert_array(&datap, datap.pd_argv_strs, 1594 datap.pd_argc, &unprintable); 1595 print_args(&datap); 1596 if (eflag || xflag) 1597 (void) printf("\n"); 1598 } 1599 1600 if (eflag != 0) { 1601 convert_array(&datap, datap.pd_envp_strs, 1602 datap.pd_envc, &unprintable); 1603 print_env(&datap); 1604 if (xflag) 1605 (void) printf("\n"); 1606 } 1607 1608 if (xflag != 0) { 1609 convert_array(&datap, datap.pd_auxv_strs, 1610 datap.pd_auxc, &unprintable); 1611 print_auxv(&datap); 1612 } 1613 } 1614 1615 cleanup_conversions(&datap); 1616 free_data(&datap); 1617 } 1618 1619 return (retc != 0 ? 1 : 0); 1620 } 1621