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