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 *
safe_zalloc(size_t size)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 *
safe_strdup(const char * s1)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
get_interp_char(wchar_t wc)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 *
unctrl_str_strict_ascii(const char * src,int escape_slash,int * unprintable)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 *
unctrl_str(const char * src,int escape_slash,int * unprintable)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
issafe_ascii(char c)319 issafe_ascii(char c)
320 {
321 return (isalnum(c) || strchr("_.-/@:,", c) != NULL);
322 }
323
324 static int
issafe(wchar_t wc)325 issafe(wchar_t wc)
326 {
327 return ((iswgraph(wc) && !iswpunct(wc)) ||
328 wschr(L"_.-/@:,", wc) != NULL);
329 }
330
331 /*ARGSUSED*/
332 static char *
quote_string_ascii(pargs_data_t * datap,char * src)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 *
quote_string(pargs_data_t * datap,char * src)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
lookup_locale(pargs_data_t * datap)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 *
extract_string(pargs_data_t * datap,uintptr_t addr)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
read_ptr_array(pargs_data_t * datap,uintptr_t offset,uintptr_t * buf,size_t nelems)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
get_args(pargs_data_t * datap)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
build_env(void * data,struct ps_prochandle * pr,uintptr_t addr,const char * str)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
get_env(pargs_data_t * datap)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
at_null(long val,char * instr,size_t n,char * str)669 at_null(long val, char *instr, size_t n, char *str)
670 {
671 str[0] = '\0';
672 }
673
674 /*ARGSUSED*/
675 static void
at_str(long val,char * instr,size_t n,char * str)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
at_hwcap(long val,char * instr,size_t n,char * str)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
at_uid(long val,char * instr,size_t n,char * str)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
at_gid(long val,char * instr,size_t n,char * str)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
at_flags(long val,char * instr,size_t n,char * str)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 *
aux_find(int type)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
get_auxv(pargs_data_t * datap)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
setup_conversions(pargs_data_t * datap,int * diflocale)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
cleanup_conversions(pargs_data_t * datap)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 *
convert_run_iconv(pargs_data_t * datap,const char * str)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 *
convert_str(pargs_data_t * datap,const char * str,int * unprintable)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
convert_array(pargs_data_t * datap,char ** arr,size_t count,int * unprintable)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
free_data(pargs_data_t * datap)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
print_args(pargs_data_t * datap)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
print_env(pargs_data_t * datap)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
print_cmdline(pargs_data_t * datap)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
print_auxv(pargs_data_t * datap)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
main(int argc,char * argv[])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