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