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