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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2016 Joyent, Inc.
30 * pargs examines and prints the arguments (argv), environment (environ),
31 * and auxiliary vector of another process.
33 * This utility is made more complex because it must run in internationalized
34 * environments. The two key cases for pargs to manage are:
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.
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.
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.
67 #include <sys/types.h>
69 #include <sys/archsystm.h>
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 */
96 #define CONV_USE_ICONV 0x01
97 #define CONV_STRICT_ASCII 0x02
102 #define EXTRACT_BUFSZ 128 /* extract_string() initial size */
103 #define ENV_CHUNK 16 /* #env ptrs to read at a time */
105 static jmp_buf env
; /* malloc failure handling */
108 safe_zalloc(size_t size
)
113 * If the malloc fails we longjmp out to allow the code to Prelease()
114 * a stopped victim if needed.
116 if ((p
= malloc(size
)) == NULL
) {
125 safe_strdup(const char *s1
)
129 s2
= safe_zalloc(strlen(s1
) + 1);
130 (void) strcpy(s2
, s1
);
135 * Given a wchar_t which might represent an 'escapable' sequence (see
136 * formats(5)), return the base ascii character needed to print that
139 * The comparisons performed may look suspect at first, but all are valid;
140 * the characters below all appear in the "Portable Character Set." The
141 * Single Unix Spec says: "The wide-character value for each member of the
142 * Portable Character Set will equal its value when used as the lone
143 * character in an integer character constant."
146 get_interp_char(wchar_t wc
)
170 unctrl_str_strict_ascii(const char *src
, int escape_slash
, int *unprintable
)
172 uchar_t
*uc
, *ucp
, c
, ic
;
173 uc
= ucp
= safe_zalloc((strlen(src
) * 4) + 1);
174 while ((c
= *src
++) != '\0') {
176 * Call get_interp_char *first*, since \ will otherwise not
179 if ((ic
= get_interp_char((wchar_t)c
)) != '\0') {
180 if (escape_slash
|| ic
!= '\\')
183 } else if (isascii(c
) && isprint(c
)) {
187 *ucp
++ = ((c
>> 6) & 7) + '0';
188 *ucp
++ = ((c
>> 3) & 7) + '0';
189 *ucp
++ = (c
& 7) + '0';
198 * Convert control characters as described in format(5) to their readable
199 * representation; special care is taken to handle multibyte character sets.
201 * If escape_slash is true, escaping of '\' occurs. The first time a string
202 * is unctrl'd, this should be '1'. Subsequent iterations over the same
203 * string should set escape_slash to 0. Otherwise you'll wind up with
207 unctrl_str(const char *src
, int escape_slash
, int *unprintable
)
210 wchar_t *wide_src
, *wide_srcp
;
211 wchar_t *wide_dest
, *wide_destp
;
213 size_t srcbufsz
= strlen(src
) + 1;
214 size_t destbufsz
= srcbufsz
* 4;
215 size_t srclen
, destlen
;
217 wide_srcp
= wide_src
= safe_zalloc(srcbufsz
* sizeof (wchar_t));
218 wide_destp
= wide_dest
= safe_zalloc(destbufsz
* sizeof (wchar_t));
220 if ((srclen
= mbstowcs(wide_src
, src
, srcbufsz
- 1)) == (size_t)-1) {
222 * We can't trust the string, since in the locale in which
223 * this call is operating, the string contains an invalid
224 * multibyte sequence. There isn't much to do here, so
225 * convert the string byte by byte to wide characters, as
226 * if it came from a C locale (char) string. This isn't
227 * perfect, but at least the characters will make it to
232 return (unctrl_str_strict_ascii(src
, escape_slash
,
235 if (srclen
== (srcbufsz
- 1)) {
236 wide_src
[srclen
] = L
'\0';
239 while ((wc
= *wide_srcp
++) != L
'\0') {
240 char cvt_buf
[MB_LEN_MAX
];
242 char c
= get_interp_char(wc
);
244 if ((c
!= '\0') && (escape_slash
|| c
!= '\\')) {
246 * Print "interpreted version" (\n, \a, etc).
248 *wide_destp
++ = L
'\\';
249 *wide_destp
++ = (wchar_t)c
;
259 * Convert the wide char back into (potentially several)
260 * multibyte characters, then escape out each of those bytes.
262 bzero(cvt_buf
, sizeof (cvt_buf
));
263 if ((len
= wctomb(cvt_buf
, wc
)) == -1) {
265 * This is a totally invalid wide char; discard it.
269 for (i
= 0; i
< len
; i
++) {
270 uchar_t c
= cvt_buf
[i
];
271 *wide_destp
++ = L
'\\';
272 *wide_destp
++ = (wchar_t)('0' + ((c
>> 6) & 7));
273 *wide_destp
++ = (wchar_t)('0' + ((c
>> 3) & 7));
274 *wide_destp
++ = (wchar_t)('0' + (c
& 7));
280 destlen
= (wide_destp
- wide_dest
) * MB_CUR_MAX
+ 1;
281 uc
= safe_zalloc(destlen
);
282 if (wcstombs(uc
, wide_dest
, destlen
) == (size_t)-1) {
283 /* If we've gotten this far, wcstombs shouldn't fail... */
284 (void) fprintf(stderr
, "%s: wcstombs failed unexpectedly: %s\n",
285 command
, strerror(errno
));
290 * Try to save memory; don't waste 3 * strlen in the
293 tmp
= safe_strdup(uc
);
303 * These functions determine which characters are safe to be left unquoted.
304 * Rather than starting with every printable character and subtracting out the
305 * shell metacharacters, we take the more conservative approach of starting with
306 * a set of safe characters and adding those few common punctuation characters
307 * which are known to be safe. The rules are:
309 * If this is a printable character (graph), and not punctuation, it is
310 * safe to leave unquoted.
312 * If it's one of known hard-coded safe characters, it's also safe to leave
315 * Otherwise, the entire argument must be quoted.
317 * This will cause some strings to be unecessarily quoted, but it is safer than
318 * having a character unintentionally interpreted by the shell.
323 return (isalnum(c
) || strchr("_.-/@:,", c
) != NULL
);
329 return ((iswgraph(wc
) && !iswpunct(wc
)) ||
330 wschr(L
"_.-/@:,", wc
) != NULL
);
335 quote_string_ascii(pargs_data_t
*datap
, char *src
)
343 for (srcp
= src
; *srcp
!= '\0'; srcp
++) {
344 if (!issafe_ascii(*srcp
)) {
355 * The only character we care about here is a single quote. All the
356 * other unprintable characters (and backslashes) will have been dealt
357 * with by unctrl_str(). We make the following subtitution when we
358 * encounter a single quote:
362 * In addition, we put single quotes around the entire argument. For
365 * foo'bar = 'foo'"'"'bar'
367 dstlen
= strlen(src
) + 3 + 4 * quote_count
;
368 dst
= safe_zalloc(dstlen
);
372 for (srcp
= src
; *srcp
!= '\0'; srcp
++, dstp
++) {
392 quote_string(pargs_data_t
*datap
, char *src
)
394 wchar_t *wide_src
, *wide_srcp
;
395 wchar_t *wide_dest
, *wide_destp
;
397 size_t srcbufsz
= strlen(src
) + 1;
404 if (datap
->pd_conv_flags
& CONV_STRICT_ASCII
)
405 return (quote_string_ascii(datap
, src
));
407 wide_srcp
= wide_src
= safe_zalloc(srcbufsz
* sizeof (wchar_t));
409 if ((srclen
= mbstowcs(wide_src
, src
, srcbufsz
- 1)) == (size_t)-1) {
411 return (quote_string_ascii(datap
, src
));
414 if (srclen
== srcbufsz
- 1)
415 wide_src
[srclen
] = L
'\0';
417 for (wide_srcp
= wide_src
; *wide_srcp
!= '\0'; wide_srcp
++) {
418 if (!issafe(*wide_srcp
)) {
420 if (*wide_srcp
== L
'\'')
431 * See comment for quote_string_ascii(), above.
433 destbufsz
= srcbufsz
+ 3 + 4 * quote_count
;
434 wide_destp
= wide_dest
= safe_zalloc(destbufsz
* sizeof (wchar_t));
436 *wide_destp
++ = L
'\'';
437 for (wide_srcp
= wide_src
; *wide_srcp
!= L
'\0';
438 wide_srcp
++, wide_destp
++) {
439 *wide_destp
= *wide_srcp
;
441 if (*wide_srcp
== L
'\'') {
442 wide_destp
[1] = L
'"';
443 wide_destp
[2] = L
'\'';
444 wide_destp
[3] = L
'"';
445 wide_destp
[4] = L
'\'';
449 *wide_destp
++ = L
'\'';
452 destlen
= destbufsz
* MB_CUR_MAX
+ 1;
453 uc
= safe_zalloc(destlen
);
454 if (wcstombs(uc
, wide_dest
, destlen
) == (size_t)-1) {
455 /* If we've gotten this far, wcstombs shouldn't fail... */
456 (void) fprintf(stderr
, "%s: wcstombs failed unexpectedly: %s\n",
457 command
, strerror(errno
));
469 * Determine the locale of the target process by traversing its environment,
470 * making only one pass for efficiency's sake; stash the result in
473 * It's possible that the process has called setlocale() to change its
474 * locale to something different, but we mostly care about making a good
475 * guess as to the locale at exec(2) time.
478 lookup_locale(pargs_data_t
*datap
)
480 int i
, j
, composite
= 0;
483 char *lc_all
= NULL
, *lang
= NULL
;
484 char *lcs
[] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
485 static const char *cat_names
[] = {
486 "LC_CTYPE=", "LC_NUMERIC=", "LC_TIME=",
487 "LC_COLLATE=", "LC_MONETARY=", "LC_MESSAGES="
490 for (i
= 0; i
< datap
->pd_envc
; i
++) {
491 char *s
= datap
->pd_envp_strs
[i
];
496 if (strncmp("LC_ALL=", s
, strlen("LC_ALL=")) == 0) {
498 * Minor optimization-- if we find LC_ALL we're done.
500 lc_all
= s
+ strlen("LC_ALL=");
503 for (j
= 0; j
<= _LastCategory
; j
++) {
504 if (strncmp(cat_names
[j
], s
,
505 strlen(cat_names
[j
])) == 0) {
506 lcs
[j
] = s
+ strlen(cat_names
[j
]);
509 if (strncmp("LANG=", s
, strlen("LANG=")) == 0) {
510 lang
= s
+ strlen("LANG=");
514 if (lc_all
&& (*lc_all
== '\0'))
516 if (lang
&& (*lang
== '\0'))
519 for (i
= 0; i
<= _LastCategory
; i
++) {
520 if (lc_all
!= NULL
) {
522 } else if (lcs
[i
] != NULL
) {
524 } else if (lang
!= NULL
) {
529 if ((i
> 0) && (lcs
[i
] != lcs
[i
-1]))
532 len
+= 1 + strlen(lcs
[i
]); /* 1 extra byte for '/' */
535 if (composite
== 0) {
537 pd_locale
= safe_strdup(lcs
[0]);
539 /* composite locale */
540 pd_locale
= safe_zalloc(len
+ 1);
541 (void) snprintf(pd_locale
, len
+ 1, "%s/%s/%s/%s/%s/%s",
542 lcs
[0], lcs
[1], lcs
[2], lcs
[3], lcs
[4], lcs
[5]);
544 datap
->pd_locale
= pd_locale
;
548 * Pull a string from the victim, regardless of size; this routine allocates
549 * memory for the string which must be freed by the caller.
552 extract_string(pargs_data_t
*datap
, uintptr_t addr
)
554 int size
= EXTRACT_BUFSZ
;
557 result
= safe_zalloc(size
);
560 if (Pread_string(datap
->pd_proc
, result
, size
, addr
) < 0) {
563 } else if (strlen(result
) == (size
- 1)) {
566 result
= safe_zalloc(size
);
575 * Utility function to read an array of pointers from the victim, adjusting
576 * for victim data model; returns the number of bytes successfully read.
579 read_ptr_array(pargs_data_t
*datap
, uintptr_t offset
, uintptr_t *buf
,
584 if (dmodel
== PR_MODEL_NATIVE
) {
585 res
= Pread(datap
->pd_proc
, buf
, nelems
* sizeof (uintptr_t),
589 uint32_t *arr32
= safe_zalloc(nelems
* sizeof (uint32_t));
591 res
= Pread(datap
->pd_proc
, arr32
, nelems
* sizeof (uint32_t),
594 for (i
= 0; i
< nelems
; i
++)
603 * Extract the argv array from the victim; store the pointer values in
604 * datap->pd_argv and the extracted strings in datap->pd_argv_strs.
607 get_args(pargs_data_t
*datap
)
609 size_t argc
= datap
->pd_psinfo
->pr_argc
;
610 uintptr_t argvoff
= datap
->pd_psinfo
->pr_argv
;
613 datap
->pd_argc
= argc
;
614 datap
->pd_argv
= safe_zalloc(argc
* sizeof (uintptr_t));
616 if (read_ptr_array(datap
, argvoff
, datap
->pd_argv
, argc
) <= 0) {
617 free(datap
->pd_argv
);
618 datap
->pd_argv
= NULL
;
622 datap
->pd_argv_strs
= safe_zalloc(argc
* sizeof (char *));
623 for (i
= 0; i
< argc
; i
++) {
624 if (datap
->pd_argv
[i
] == 0)
626 datap
->pd_argv_strs
[i
] = extract_string(datap
,
633 build_env(void *data
, struct ps_prochandle
*pr
, uintptr_t addr
, const char *str
)
635 pargs_data_t
*datap
= data
;
637 if (datap
->pd_envp
!= NULL
) {
638 if (datap
->pd_envc
== datap
->pd_env_space
) {
640 * Not enough space for storing the env (it has more
641 * items than before). Try to grow both arrays.
643 void *new = realloc(datap
->pd_envp
,
644 sizeof (uintptr_t) * datap
->pd_env_space
* 2);
647 datap
->pd_envp
= new;
649 new = realloc(datap
->pd_envp_strs
,
650 sizeof (char *) * datap
->pd_env_space
* 2);
653 datap
->pd_envp_strs
= new;
655 datap
->pd_env_space
*= 2;
658 datap
->pd_envp
[datap
->pd_envc
] = addr
;
660 datap
->pd_envp_strs
[datap
->pd_envc
] = NULL
;
662 datap
->pd_envp_strs
[datap
->pd_envc
] = strdup(str
);
671 get_env(pargs_data_t
*datap
)
673 struct ps_prochandle
*pr
= datap
->pd_proc
;
676 (void) Penv_iter(pr
, build_env
, datap
);
678 /* We must allocate space for at least one entry */
679 datap
->pd_env_space
= datap
->pd_envc
!= 0 ? datap
->pd_envc
: 1;
680 datap
->pd_envp
= safe_zalloc(sizeof (uintptr_t) * datap
->pd_env_space
);
681 datap
->pd_envp_strs
=
682 safe_zalloc(sizeof (char *) * datap
->pd_env_space
);
685 (void) Penv_iter(pr
, build_env
, datap
);
689 * The following at_* routines are used to decode data from the aux vector.
694 at_null(long val
, char *instr
, size_t n
, char *str
)
701 at_str(long val
, char *instr
, size_t n
, char *str
)
705 (void) strlcpy(str
, instr
, n
);
710 * Note: Don't forget to add a corresponding case to isainfo(1).
713 #define FMT_AV(s, n, hwcap, mask, name) \
714 if ((hwcap) & (mask)) \
715 (void) snprintf(s, n, "%s" name " | ", s)
719 at_hwcap(long val
, char *instr
, size_t n
, char *str
)
721 #if defined(__sparc) || defined(__sparcv9)
722 (void) elfcap_hw1_to_str(ELFCAP_STYLE_UC
, val
, str
, n
,
723 ELFCAP_FMT_PIPSPACE
, EM_SPARC
);
725 #elif defined(__i386) || defined(__amd64)
726 (void) elfcap_hw1_to_str(ELFCAP_STYLE_UC
, val
, str
, n
,
727 ELFCAP_FMT_PIPSPACE
, EM_386
);
735 at_hwcap2(long val
, char *instr
, size_t n
, char *str
)
737 #if defined(__sparc) || defined(__sparcv9)
738 (void) elfcap_hw2_to_str(ELFCAP_STYLE_UC
, val
, str
, n
,
739 ELFCAP_FMT_PIPSPACE
, EM_SPARC
);
741 #elif defined(__i386) || defined(__amd64)
742 (void) elfcap_hw2_to_str(ELFCAP_STYLE_UC
, val
, str
, n
,
743 ELFCAP_FMT_PIPSPACE
, EM_386
);
752 at_uid(long val
, char *instr
, size_t n
, char *str
)
754 struct passwd
*pw
= getpwuid((uid_t
)val
);
756 if ((pw
== NULL
) || (pw
->pw_name
== NULL
))
759 (void) snprintf(str
, n
, "%lu(%s)", val
, pw
->pw_name
);
765 at_gid(long val
, char *instr
, size_t n
, char *str
)
767 struct group
*gr
= getgrgid((gid_t
)val
);
769 if ((gr
== NULL
) || (gr
->gr_name
== NULL
))
772 (void) snprintf(str
, n
, "%lu(%s)", val
, gr
->gr_name
);
775 static struct auxfl
{
779 { AF_SUN_SETUGID
, "setugid" },
784 at_flags(long val
, char *instr
, size_t n
, char *str
)
790 for (i
= 0; i
< sizeof (auxfl
)/sizeof (struct auxfl
); i
++) {
791 if ((val
& auxfl
[i
].af_flag
) != 0) {
793 (void) strlcat(str
, ",", n
);
794 (void) strlcat(str
, auxfl
[i
].af_name
, n
);
799 #define MAX_AT_NAME_LEN 15
803 const char *aux_name
;
804 void (*aux_decode
)(long, char *, size_t, char *);
807 static struct aux_id aux_arr
[] = {
808 { AT_NULL
, "AT_NULL", at_null
},
809 { AT_IGNORE
, "AT_IGNORE", at_null
},
810 { AT_EXECFD
, "AT_EXECFD", at_null
},
811 { AT_PHDR
, "AT_PHDR", at_null
},
812 { AT_PHENT
, "AT_PHENT", at_null
},
813 { AT_PHNUM
, "AT_PHNUM", at_null
},
814 { AT_PAGESZ
, "AT_PAGESZ", at_null
},
815 { AT_BASE
, "AT_BASE", at_null
},
816 { AT_FLAGS
, "AT_FLAGS", at_null
},
817 { AT_ENTRY
, "AT_ENTRY", at_null
},
818 { AT_SUN_UID
, "AT_SUN_UID", at_uid
},
819 { AT_SUN_RUID
, "AT_SUN_RUID", at_uid
},
820 { AT_SUN_GID
, "AT_SUN_GID", at_gid
},
821 { AT_SUN_RGID
, "AT_SUN_RGID", at_gid
},
822 { AT_SUN_LDELF
, "AT_SUN_LDELF", at_null
},
823 { AT_SUN_LDSHDR
, "AT_SUN_LDSHDR", at_null
},
824 { AT_SUN_LDNAME
, "AT_SUN_LDNAME", at_null
},
825 { AT_SUN_LPAGESZ
, "AT_SUN_LPAGESZ", at_null
},
826 { AT_SUN_PLATFORM
, "AT_SUN_PLATFORM", at_str
},
827 { AT_SUN_EXECNAME
, "AT_SUN_EXECNAME", at_str
},
828 { AT_SUN_HWCAP
, "AT_SUN_HWCAP", at_hwcap
},
829 { AT_SUN_HWCAP2
, "AT_SUN_HWCAP2", at_hwcap2
},
830 { AT_SUN_IFLUSH
, "AT_SUN_IFLUSH", at_null
},
831 { AT_SUN_CPU
, "AT_SUN_CPU", at_null
},
832 { AT_SUN_MMU
, "AT_SUN_MMU", at_null
},
833 { AT_SUN_LDDATA
, "AT_SUN_LDDATA", at_null
},
834 { AT_SUN_AUXFLAGS
, "AT_SUN_AUXFLAGS", at_flags
},
835 { AT_SUN_EMULATOR
, "AT_SUN_EMULATOR", at_str
},
836 { AT_SUN_BRANDNAME
, "AT_SUN_BRANDNAME", at_str
},
837 { AT_SUN_BRAND_AUX1
, "AT_SUN_BRAND_AUX1", at_null
},
838 { AT_SUN_BRAND_AUX2
, "AT_SUN_BRAND_AUX2", at_null
},
839 { AT_SUN_BRAND_AUX3
, "AT_SUN_BRAND_AUX3", at_null
},
840 { AT_SUN_COMMPAGE
, "AT_SUN_COMMPAGE", at_null
}
843 #define N_AT_ENTS (sizeof (aux_arr) / sizeof (struct aux_id))
846 * Return the aux_id entry for the given aux type; returns NULL if not found.
848 static struct aux_id
*
853 for (i
= 0; i
< N_AT_ENTS
; i
++) {
854 if (type
== aux_arr
[i
].aux_type
)
855 return (&aux_arr
[i
]);
862 get_auxv(pargs_data_t
*datap
)
868 * Fetch the aux vector from the target process.
870 if (ps_pauxv(datap
->pd_proc
, &auxvp
) != PS_OK
)
873 for (i
= 0; auxvp
[i
].a_type
!= AT_NULL
; i
++)
877 datap
->pd_auxv
= safe_zalloc(i
* sizeof (auxv_t
));
878 bcopy(auxvp
, datap
->pd_auxv
, i
* sizeof (auxv_t
));
880 datap
->pd_auxv_strs
= safe_zalloc(datap
->pd_auxc
* sizeof (char *));
881 for (i
= 0; i
< datap
->pd_auxc
; i
++) {
882 struct aux_id
*aux
= aux_find(datap
->pd_auxv
[i
].a_type
);
885 * Grab strings for those entries which have a string-decoder.
887 if ((aux
!= NULL
) && (aux
->aux_decode
== at_str
)) {
888 datap
->pd_auxv_strs
[i
] =
889 extract_string(datap
, datap
->pd_auxv
[i
].a_un
.a_val
);
895 * Prepare to convert characters in the victim's character set into user's
899 setup_conversions(pargs_data_t
*datap
, int *diflocale
)
901 char *mylocale
= NULL
, *mycharset
= NULL
;
902 char *targetlocale
= NULL
, *targetcharset
= NULL
;
904 mycharset
= safe_strdup(nl_langinfo(CODESET
));
906 mylocale
= setlocale(LC_CTYPE
, NULL
);
907 if ((mylocale
== NULL
) || (strcmp(mylocale
, "") == 0))
909 mylocale
= safe_strdup(mylocale
);
911 if (datap
->pd_conv_flags
& CONV_STRICT_ASCII
)
915 * If the target's locale is "C" or "POSIX", go fast.
917 if ((strcmp(datap
->pd_locale
, "C") == 0) ||
918 (strcmp(datap
->pd_locale
, "POSIX") == 0)) {
919 datap
->pd_conv_flags
|= CONV_STRICT_ASCII
;
924 * Switch to the victim's locale, and discover its character set.
926 if (setlocale(LC_ALL
, datap
->pd_locale
) == NULL
) {
927 (void) fprintf(stderr
,
928 "%s: Couldn't determine locale of target process.\n",
930 (void) fprintf(stderr
,
931 "%s: Some strings may not be displayed properly.\n",
937 * Get LC_CTYPE part of target's locale, and its codeset.
939 targetlocale
= safe_strdup(setlocale(LC_CTYPE
, NULL
));
940 targetcharset
= safe_strdup(nl_langinfo(CODESET
));
943 * Now go fully back to the pargs user's locale.
945 (void) setlocale(LC_ALL
, "");
948 * It's safe to bail here if the lc_ctype of the locales are the
949 * same-- we know that their encodings and characters sets are the same.
951 if (strcmp(targetlocale
, mylocale
) == 0)
957 * If the codeset of the victim matches our codeset then iconv need
960 if (strcmp(mycharset
, targetcharset
) == 0)
963 if ((datap
->pd_iconv
= iconv_open(mycharset
, targetcharset
))
966 * EINVAL indicates there was no conversion available
967 * from victim charset to mycharset
969 if (errno
!= EINVAL
) {
970 (void) fprintf(stderr
,
971 "%s: failed to initialize iconv: %s\n",
972 command
, strerror(errno
));
975 datap
->pd_conv_flags
|= CONV_STRICT_ASCII
;
977 datap
->pd_conv_flags
|= CONV_USE_ICONV
;
987 cleanup_conversions(pargs_data_t
*datap
)
989 if (datap
->pd_conv_flags
& CONV_USE_ICONV
) {
990 (void) iconv_close(datap
->pd_iconv
);
995 convert_run_iconv(pargs_data_t
*datap
, const char *str
)
997 size_t inleft
, outleft
, bufsz
= 64;
998 char *outstr
, *outstrptr
;
999 const char *instrptr
;
1002 outstrptr
= outstr
= safe_zalloc(bufsz
+ 1);
1006 * Generate the "initial shift state" sequence, placing that
1007 * at the head of the string.
1010 (void) iconv(datap
->pd_iconv
, NULL
, &inleft
,
1011 &outstrptr
, &outleft
);
1013 inleft
= strlen(str
);
1015 if (iconv(datap
->pd_iconv
, &instrptr
, &inleft
, &outstrptr
,
1016 &outleft
) != (size_t)-1) {
1018 * Outstr must be null terminated upon exit from
1021 *(outstr
+ (bufsz
- outleft
)) = '\0';
1023 } else if (errno
== E2BIG
) {
1026 } else if ((errno
== EILSEQ
) || (errno
== EINVAL
)) {
1031 * iconv() could in theory return EBADF, but that
1034 (void) fprintf(stderr
,
1035 "%s: iconv(3C) failed unexpectedly: %s\n",
1036 command
, strerror(errno
));
1045 * Returns a freshly allocated string converted to the local character set,
1046 * removed of unprintable characters.
1049 convert_str(pargs_data_t
*datap
, const char *str
, int *unprintable
)
1053 if (datap
->pd_conv_flags
& CONV_STRICT_ASCII
) {
1054 retstr
= unctrl_str_strict_ascii(str
, 1, unprintable
);
1058 if ((datap
->pd_conv_flags
& CONV_USE_ICONV
) == 0) {
1060 * If we aren't using iconv(), convert control chars in
1061 * the string in pargs' locale, since that is the display
1064 retstr
= unctrl_str(str
, 1, unprintable
);
1069 * The logic here is a bit (ahem) tricky. Start by converting
1070 * unprintable characters *in the target's locale*. This should
1071 * eliminate a variety of unprintable or illegal characters-- in
1072 * short, it should leave us with something which iconv() won't
1073 * have trouble with.
1075 * After allowing iconv to convert characters as needed, run unctrl
1076 * again in pargs' locale-- This time to make sure that any
1077 * characters which aren't printable according to the *current*
1078 * locale (independent of the current codeset) get taken care of.
1079 * Without this second stage, we might (for example) fail to
1080 * properly handle characters converted into the ASCII character set
1081 * (which are 8-bits wide), but which must be displayed in the C
1082 * locale (which uses ASCII, but whose printable characters are a
1083 * subset of the 7-bit characters).
1085 * Note that assuming the victim's locale using LC_ALL will be
1086 * problematic when pargs' messages are internationalized in the
1087 * future (and it calls textdomain(3C)). In this case, any
1088 * error message fprintf'd in unctrl_str() will be in the wrong
1089 * LC_MESSAGES class. We'll cross that bridge when we come to it.
1091 (void) setlocale(LC_ALL
, datap
->pd_locale
);
1092 retstr
= unctrl_str(str
, 1, unprintable
);
1093 (void) setlocale(LC_ALL
, "");
1096 if ((retstr
= convert_run_iconv(datap
, retstr
)) == NULL
) {
1098 * In this (rare but real) case, the iconv() failed even
1099 * though we unctrl'd the string. Treat the original string
1100 * (str) as a C locale string and strip it that way.
1103 return (unctrl_str_strict_ascii(str
, 0, unprintable
));
1109 * Run unctrl_str, but make sure not to escape \ characters, which
1110 * may have resulted from the first round of unctrl.
1112 retstr
= unctrl_str(retstr
, 0, unprintable
);
1119 convert_array(pargs_data_t
*datap
, char **arr
, size_t count
, int *unprintable
)
1127 for (i
= 0; i
< count
; i
++) {
1128 if ((tmp
= arr
[i
]) == NULL
)
1130 arr
[i
] = convert_str(datap
, arr
[i
], unprintable
);
1136 * Free data allocated during the gathering phase.
1139 free_data(pargs_data_t
*datap
)
1143 for (i
= 0; i
< datap
->pd_argc
; i
++)
1144 free(datap
->pd_argv_strs
[i
]);
1145 free(datap
->pd_argv
);
1146 free(datap
->pd_argv_strs
);
1148 for (i
= 0; i
< datap
->pd_envc
; i
++)
1149 free(datap
->pd_envp_strs
[i
]);
1150 free(datap
->pd_envp
);
1151 free(datap
->pd_envp_strs
);
1153 for (i
= 0; i
< datap
->pd_auxc
; i
++)
1154 free(datap
->pd_auxv_strs
[i
]);
1155 free(datap
->pd_auxv
);
1156 free(datap
->pd_auxv_strs
);
1160 print_args(pargs_data_t
*datap
)
1164 if (datap
->pd_argv
== NULL
) {
1165 (void) fprintf(stderr
, "%s: failed to read argv[]\n", command
);
1169 for (i
= 0; i
< datap
->pd_argc
; i
++) {
1170 (void) printf("argv[%d]: ", i
);
1171 if (datap
->pd_argv
[i
] == (uintptr_t)NULL
) {
1172 (void) printf("<NULL>\n");
1173 } else if (datap
->pd_argv_strs
[i
] == NULL
) {
1174 (void) printf("<0x%0*lx>\n",
1175 (dmodel
== PR_MODEL_LP64
)? 16 : 8,
1176 (long)datap
->pd_argv
[i
]);
1178 (void) printf("%s\n", datap
->pd_argv_strs
[i
]);
1184 print_env(pargs_data_t
*datap
)
1188 if (datap
->pd_envp
== NULL
) {
1189 (void) fprintf(stderr
, "%s: failed to read envp[]\n", command
);
1193 for (i
= 0; i
< datap
->pd_envc
; i
++) {
1194 (void) printf("envp[%d]: ", i
);
1195 if (datap
->pd_envp
[i
] == 0) {
1197 } else if (datap
->pd_envp_strs
[i
] == NULL
) {
1198 (void) printf("<0x%0*lx>\n",
1199 (dmodel
== PR_MODEL_LP64
)? 16 : 8,
1200 (long)datap
->pd_envp
[i
]);
1202 (void) printf("%s\n", datap
->pd_envp_strs
[i
]);
1208 print_cmdline(pargs_data_t
*datap
)
1213 * Go through and check to see if we have valid data. If not, print
1214 * an error message and bail.
1216 for (i
= 0; i
< datap
->pd_argc
; i
++) {
1217 if (datap
->pd_argv
== NULL
||
1218 datap
->pd_argv
[i
] == (uintptr_t)NULL
||
1219 datap
->pd_argv_strs
[i
] == NULL
) {
1220 (void) fprintf(stderr
, "%s: target has corrupted "
1221 "argument list\n", command
);
1225 datap
->pd_argv_strs
[i
] =
1226 quote_string(datap
, datap
->pd_argv_strs
[i
]);
1229 if (datap
->pd_execname
== NULL
) {
1230 (void) fprintf(stderr
, "%s: cannot determine name of "
1231 "executable\n", command
);
1235 (void) printf("%s ", datap
->pd_execname
);
1237 for (i
= 1; i
< datap
->pd_argc
; i
++)
1238 (void) printf("%s ", datap
->pd_argv_strs
[i
]);
1240 (void) printf("\n");
1246 print_auxv(pargs_data_t
*datap
)
1252 * Print the names and values of all the aux vector entries.
1254 for (i
= 0; i
< datap
->pd_auxc
; i
++) {
1256 char decode
[PATH_MAX
];
1259 pa
= &datap
->pd_auxv
[i
];
1261 aux
= aux_find(pa
->a_type
);
1262 v
= (long)pa
->a_un
.a_val
;
1266 * Fetch aux vector type string and decoded
1267 * representation of the value.
1269 (void) strlcpy(type
, aux
->aux_name
, sizeof (type
));
1270 aux
->aux_decode(v
, datap
->pd_auxv_strs
[i
],
1271 sizeof (decode
), decode
);
1273 (void) snprintf(type
, sizeof (type
), "%d", pa
->a_type
);
1277 (void) printf("%-*s 0x%0*lx %s\n", MAX_AT_NAME_LEN
, type
,
1278 (dmodel
== PR_MODEL_LP64
)? 16 : 8, v
, decode
);
1283 main(int argc
, char *argv
[])
1285 int aflag
= 0, cflag
= 0, eflag
= 0, xflag
= 0, lflag
= 0;
1286 int errflg
= 0, retc
= 0;
1289 core_content_t content
= 0;
1291 (void) setlocale(LC_ALL
, "");
1293 if ((command
= strrchr(argv
[0], '/')) != NULL
)
1298 while ((opt
= getopt(argc
, argv
, "acelxF")) != EOF
) {
1300 case 'a': /* show process arguments */
1301 content
|= CC_CONTENT_STACK
;
1304 case 'c': /* force 7-bit ascii */
1307 case 'e': /* show environment variables */
1308 content
|= CC_CONTENT_STACK
;
1313 aflag
++; /* -l implies -a */
1315 case 'x': /* show aux vector entries */
1320 * Since we open the process read-only, there is no need
1321 * for the -F flag. It's a documented flag, so we
1322 * consume it silently.
1331 /* -a is the default if no options are specified */
1332 if ((aflag
+ eflag
+ xflag
+ lflag
) == 0) {
1334 content
|= CC_CONTENT_STACK
;
1337 /* -l cannot be used with the -x or -e flags */
1338 if (lflag
&& (xflag
|| eflag
)) {
1339 (void) fprintf(stderr
, "-l is incompatible with -x and -e\n");
1346 if (errflg
|| argc
<= 0) {
1347 (void) fprintf(stderr
,
1348 "usage: %s [-aceFlx] { pid | core } ...\n"
1349 " (show process arguments and environment)\n"
1350 " -a: show process arguments (default)\n"
1351 " -c: interpret characters as 7-bit ascii regardless of "
1353 " -e: show environment variables\n"
1354 " -F: force grabbing of the target process\n"
1355 " -l: display arguments as command line\n"
1356 " -x: show aux vector entries\n", command
);
1360 while (argc
-- > 0) {
1365 struct ps_prochandle
*Pr
;
1370 char execname
[PATH_MAX
];
1374 (void) fflush(stdout
);
1378 * Suppress extra blanks lines if we've encountered processes
1379 * which can't be opened.
1382 (void) printf("\n");
1387 * First grab just the psinfo information, in case this
1388 * process is a zombie (in which case proc_arg_grab() will
1389 * fail). If so, print a nice message and continue.
1391 if (proc_arg_psinfo(arg
, PR_ARG_ANY
, &psinfo
,
1393 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
1394 command
, arg
, Pgrab_error(gret
));
1400 if (psinfo
.pr_nlwp
== 0) {
1401 (void) printf("%d: <defunct>\n", (int)psinfo
.pr_pid
);
1406 * If process is a "system" process (like pageout), just
1407 * print its psargs and continue on.
1409 if (psinfo
.pr_size
== 0 && psinfo
.pr_rssize
== 0) {
1410 proc_unctrl_psinfo(&psinfo
);
1412 (void) printf("%d: ", (int)psinfo
.pr_pid
);
1413 (void) printf("%s\n", psinfo
.pr_psargs
);
1418 * Open the process readonly, since we do not need to write to
1421 if ((Pr
= proc_arg_grab(arg
, PR_ARG_ANY
, PGRAB_RDONLY
,
1423 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
1424 command
, arg
, Pgrab_error(gret
));
1430 pstate
= Pstate(Pr
);
1432 if (pstate
== PS_DEAD
&&
1433 (Pcontent(Pr
) & content
) != content
) {
1434 (void) fprintf(stderr
, "%s: core '%s' has "
1435 "insufficient content\n", command
, arg
);
1441 * If malloc() fails, we return here so that we can let go
1442 * of the victim, restore our locale, print a message,
1445 if ((r
= setjmp(env
)) != 0) {
1447 (void) setlocale(LC_ALL
, "");
1448 (void) fprintf(stderr
, "%s: out of memory: %s\n",
1449 command
, strerror(r
));
1453 dmodel
= Pstatus(Pr
)->pr_dmodel
;
1454 bzero(&datap
, sizeof (datap
));
1455 bcopy(Ppsinfo(Pr
), &psinfo
, sizeof (psinfo_t
));
1457 datap
.pd_psinfo
= &psinfo
;
1460 datap
.pd_conv_flags
|= CONV_STRICT_ASCII
;
1463 * Strip control characters, then record process summary in
1464 * a buffer, since we don't want to print anything out until
1465 * after we release the process.
1469 * The process is neither a system process nor defunct.
1471 * Do printing and post-processing (like name lookups) after
1472 * gathering the raw data from the process and releasing it.
1473 * This way, we don't deadlock on (for example) name lookup
1474 * if we grabbed the nscd and do 'pargs -x'.
1476 * We always fetch the environment of the target, so that we
1477 * can make an educated guess about its locale.
1486 * If malloc() fails after this poiint, we return here to
1487 * restore our locale and print a message. If we don't
1488 * reset this, we might erroneously try to Prelease a process
1491 if ((r
= setjmp(env
)) != 0) {
1492 (void) setlocale(LC_ALL
, "");
1493 (void) fprintf(stderr
, "%s: out of memory: %s\n",
1494 command
, strerror(r
));
1499 * For the -l option, we need a proper name for this executable
1500 * before we release it.
1503 datap
.pd_execname
= Pexecname(Pr
, execname
,
1509 * Crawl through the environment to determine the locale of
1512 lookup_locale(&datap
);
1514 setup_conversions(&datap
, &diflocale
);
1518 convert_array(&datap
, datap
.pd_argv_strs
,
1519 datap
.pd_argc
, &unprintable
);
1521 (void) fprintf(stderr
, "%s: Warning, target "
1522 "locale differs from current locale\n",
1524 else if (unprintable
)
1525 (void) fprintf(stderr
, "%s: Warning, command "
1526 "line contains unprintable characters\n",
1529 retc
+= print_cmdline(&datap
);
1531 psargs_conv
= convert_str(&datap
, psinfo
.pr_psargs
,
1533 info_sz
= strlen(psargs_conv
) + MAXPATHLEN
+ 32 + 1;
1534 info
= malloc(info_sz
);
1535 if (pstate
== PS_DEAD
) {
1536 (void) snprintf(info
, info_sz
,
1537 "core '%s' of %d:\t%s\n",
1538 arg
, (int)psinfo
.pr_pid
, psargs_conv
);
1540 (void) snprintf(info
, info_sz
, "%d:\t%s\n",
1541 (int)psinfo
.pr_pid
, psargs_conv
);
1543 (void) printf("%s", info
);
1548 convert_array(&datap
, datap
.pd_argv_strs
,
1549 datap
.pd_argc
, &unprintable
);
1552 (void) printf("\n");
1556 convert_array(&datap
, datap
.pd_envp_strs
,
1557 datap
.pd_envc
, &unprintable
);
1560 (void) printf("\n");
1564 convert_array(&datap
, datap
.pd_auxv_strs
,
1565 datap
.pd_auxc
, &unprintable
);
1570 cleanup_conversions(&datap
);
1574 return (retc
!= 0 ? 1 : 0);