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