1 /*- 2 * Copyright (c) 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)print.c 8.6 (Berkeley) 4/16/94 34 * $FreeBSD: src/bin/ps/print.c,v 1.36.2.4 2002/11/30 13:00:14 tjr Exp $ 35 * $DragonFly: src/bin/ps/print.c,v 1.34 2008/11/10 14:56:33 swildner Exp $ 36 */ 37 38 #include <sys/user.h> 39 #include <sys/param.h> 40 #include <sys/time.h> 41 #include <sys/resource.h> 42 #include <sys/stat.h> 43 44 #include <sys/ucred.h> 45 #include <sys/sysctl.h> 46 #include <sys/rtprio.h> 47 #include <vm/vm.h> 48 49 #include <err.h> 50 #include <langinfo.h> 51 #include <locale.h> 52 #include <math.h> 53 #include <nlist.h> 54 #include <pwd.h> 55 #include <stddef.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <unistd.h> 59 #include <string.h> 60 #include <vis.h> 61 62 #include "ps.h" 63 64 static const char *make_printable(const char *str); 65 static void put64(u_int64_t n, int w, int type); 66 67 void 68 printheader(void) 69 { 70 const VAR *v; 71 struct varent *vent; 72 int allempty; 73 74 allempty = 1; 75 STAILQ_FOREACH(vent, &var_head, link) { 76 if (*vent->header != '\0') { 77 allempty = 0; 78 break; 79 } 80 } 81 if (allempty) 82 return; 83 STAILQ_FOREACH(vent, &var_head, link) { 84 v = vent->var; 85 if (v->flag & LJUST) { 86 if (STAILQ_NEXT(vent, link) == NULL) /* last one */ 87 printf("%s", vent->header); 88 else 89 printf("%-*s", vent->width, vent->header); 90 } else 91 printf("%*s", vent->width, vent->header); 92 if (STAILQ_NEXT(vent, link) != NULL) 93 putchar(' '); 94 } 95 putchar('\n'); 96 } 97 98 void 99 command(const KINFO *k, const struct varent *vent) 100 { 101 int left; 102 int indent; 103 char *cp, *vis_env, *vis_args; 104 105 if (cflag) { 106 /* Don't pad the last field. */ 107 if (STAILQ_NEXT(vent, link) == NULL) 108 printf("%s", make_printable(KI_PROC(k, comm))); 109 else 110 printf("%-*s", vent->width, 111 make_printable(KI_PROC(k, comm))); 112 return; 113 } 114 115 if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL) 116 err(1, NULL); 117 strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH); 118 if (k->ki_env) { 119 if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL) 120 err(1, NULL); 121 strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH); 122 } else { 123 vis_env = NULL; 124 } 125 126 indent = k->ki_indent; 127 if (indent < 0) 128 indent = 0; 129 130 if (STAILQ_NEXT(vent, link) == NULL) { 131 /* last field */ 132 if (termwidth == UNLIMITED) { 133 if (vis_env) 134 printf("%s ", vis_env); 135 while (indent) { 136 putchar(' '); 137 --indent; 138 } 139 printf("%s", vis_args); 140 } else { 141 left = termwidth - (totwidth - vent->width); 142 if (left < 1) /* already wrapped, just use std width */ 143 left = vent->width; 144 while (indent && left > 1) { 145 putchar(' '); 146 --indent; 147 --left; 148 } 149 if ((cp = vis_env) != NULL) { 150 while (--left >= 0 && *cp) 151 putchar(*cp++); 152 if (--left >= 0) 153 putchar(' '); 154 } 155 for (cp = vis_args; --left >= 0 && *cp != '\0';) 156 putchar(*cp++); 157 } 158 } else 159 /* XXX env? */ 160 printf("%-*.*s", vent->width, vent->width, vis_args); 161 free(vis_args); 162 if (vis_env != NULL) 163 free(vis_env); 164 } 165 166 void 167 ucomm(const KINFO *k, const struct varent *vent) 168 { 169 /* Do not pad the last field */ 170 if (STAILQ_NEXT(vent, link) == NULL) 171 printf("%s", make_printable(KI_PROC(k, comm))); 172 else 173 printf("%-*s", vent->width, make_printable(KI_PROC(k, comm))); 174 } 175 176 void 177 logname(const KINFO *k, const struct varent *vent) 178 { 179 const char *s = KI_PROC(k, login); 180 181 printf("%-*s", vent->width, *s != '\0' ? s : "-"); 182 } 183 184 void 185 state(const KINFO *k, const struct varent *vent) 186 { 187 int flag; 188 char *cp; 189 char buf[16]; 190 191 flag = KI_PROC(k, flags); 192 cp = buf; 193 194 switch (KI_PROC(k, stat)) { 195 196 case SSTOP: 197 *cp = 'T'; 198 break; 199 200 case SACTIVE: 201 switch (KI_LWP(k, stat)) { 202 case LSSLEEP: 203 if (KI_LWP(k, flags) & LWP_SINTR) { 204 /* interruptable wait short/long */ 205 *cp = KI_LWP(k, slptime) >= MAXSLP ? 'I' : 'S'; 206 } 207 else if (KI_LWP(k, tdflags) & TDF_SINTR) 208 *cp = 'S'; /* interruptable lwkt wait */ 209 else if (KI_PROC(k, paddr)) 210 *cp = 'D'; /* uninterruptable wait */ 211 else 212 *cp = 'B'; /* uninterruptable lwkt wait */ 213 /*break;*/ 214 215 case LSRUN: 216 if (KI_LWP(k, stat) == LSRUN) { 217 *cp = 'R'; 218 if (!(KI_LWP(k, tdflags) & 219 (TDF_RUNNING | TDF_RUNQ))) 220 *++cp = 'Q'; 221 } 222 /*if (KI_LWP(k, tdflags) & (TDF_RUNNING | TDF_RUNQ))*/ { 223 ++cp; 224 sprintf(cp, "%d", KI_LWP(k, cpuid)); 225 while (cp[1]) 226 ++cp; 227 } 228 break; 229 230 case LSSTOP: 231 /* shouldn't happen anyways */ 232 *cp = 'T'; 233 break; 234 } 235 break; 236 237 case SZOMB: 238 *cp = 'Z'; 239 break; 240 241 default: 242 *cp = '?'; 243 } 244 245 cp++; 246 if (flag & P_SWAPPEDOUT) 247 *cp++ = 'W'; 248 if (KI_PROC(k, nice) < NZERO) 249 *cp++ = '<'; 250 else if (KI_PROC(k, nice) > NZERO) 251 *cp++ = 'N'; 252 if (flag & P_TRACED) 253 *cp++ = 'X'; 254 if (flag & P_WEXIT && KI_PROC(k, stat) != SZOMB) 255 *cp++ = 'E'; 256 if (flag & P_PPWAIT) 257 *cp++ = 'V'; 258 if ((flag & P_SYSTEM) || KI_PROC(k, lock) > 0) 259 *cp++ = 'L'; 260 if (numcpus > 1 && KI_LWP(k, mpcount) == 0) 261 *cp++ = 'M'; 262 if (flag & P_JAILED) 263 *cp++ = 'J'; 264 if (KI_PROC(k, auxflags) & KI_SLEADER) 265 *cp++ = 's'; 266 if ((flag & P_CONTROLT) && KI_PROC(k, pgid) == KI_PROC(k, tpgid)) 267 *cp++ = '+'; 268 *cp = '\0'; 269 printf("%-*s", vent->width, buf); 270 } 271 272 /* 273 * Normalized priority (lower is better). For pure threads 274 * output a negated LWKT priority (so lower still means better). 275 * 276 * XXX bsd4 scheduler specific. 277 */ 278 void 279 pri(const KINFO *k, const struct varent *vent) 280 { 281 if (KI_LWP(k, pid) != -1) 282 printf("%*d", vent->width, KI_LWP(k, prio)); 283 else 284 printf("%*d", vent->width, -(KI_LWP(k, tdprio))); 285 } 286 287 void 288 tdpri(const KINFO *k, const struct varent *vent) 289 { 290 char buf[32]; 291 int val = KI_LWP(k, tdprio); 292 293 snprintf(buf, sizeof(buf), "%2d", val); 294 printf("%*s", vent->width, buf); 295 } 296 297 void 298 uname(const KINFO *k, const struct varent *vent) 299 { 300 printf("%-*s", vent->width, 301 user_from_uid(KI_PROC(k, uid), 0)); 302 } 303 304 int 305 s_uname(const KINFO *k) 306 { 307 return (strlen(user_from_uid(KI_PROC(k, uid), 0))); 308 } 309 310 void 311 runame(const KINFO *k, const struct varent *vent) 312 { 313 printf("%-*s", vent->width, 314 user_from_uid(KI_PROC(k, ruid), 0)); 315 } 316 317 int 318 s_runame(const KINFO *k) 319 { 320 return (strlen(user_from_uid(KI_PROC(k, ruid), 0))); 321 } 322 323 void 324 tdev(const KINFO *k, const struct varent *vent) 325 { 326 dev_t dev; 327 char buff[16]; 328 329 dev = KI_PROC(k, tdev); 330 if (dev == NODEV) 331 printf("%*s", vent->width, "??"); 332 else { 333 snprintf(buff, sizeof(buff), "%d/%d", major(dev), minor(dev)); 334 printf("%*s", vent->width, buff); 335 } 336 } 337 338 void 339 tname(const KINFO *k, const struct varent *vent) 340 { 341 dev_t dev; 342 const char *ttname; 343 344 dev = KI_PROC(k, tdev); 345 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 346 printf("%*s ", vent->width-1, "??"); 347 else { 348 if (strncmp(ttname, "tty", 3) == 0 || 349 strncmp(ttname, "cua", 3) == 0) 350 ttname += 3; 351 if (strncmp(ttname, "pts/", 4) == 0) 352 ttname += 4; 353 printf("%*.*s%c", vent->width-1, vent->width-1, ttname, 354 KI_PROC(k, auxflags) & KI_CTTY ? ' ' : '-'); 355 } 356 } 357 358 void 359 longtname(const KINFO *k, const struct varent *vent) 360 { 361 dev_t dev; 362 const char *ttname; 363 364 dev = KI_PROC(k, tdev); 365 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 366 printf("%-*s", vent->width, "??"); 367 else 368 printf("%-*s", vent->width, ttname); 369 } 370 371 void 372 started(const KINFO *k, const struct varent *vent) 373 { 374 static time_t now; 375 time_t then; 376 struct tm *tp; 377 char buf[100]; 378 static int use_ampm = -1; 379 380 if (use_ampm < 0) 381 use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0'); 382 383 then = KI_PROC(k, start).tv_sec; 384 if (then < btime.tv_sec) { 385 then = btime.tv_sec; 386 } 387 388 tp = localtime(&then); 389 if (!now) 390 time(&now); 391 if (now - then < 24 * 3600) { 392 strftime(buf, sizeof(buf) - 1, 393 use_ampm ? "%l:%M%p" : "%k:%M ", tp); 394 } else if (now - then < 7 * 86400) { 395 strftime(buf, sizeof(buf) - 1, 396 use_ampm ? "%a%I%p" : "%a%H ", tp); 397 } else 398 strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 399 printf("%-*s", vent->width, buf); 400 } 401 402 void 403 lstarted(const KINFO *k, const struct varent *vent) 404 { 405 time_t then; 406 char buf[100]; 407 408 then = KI_PROC(k, start).tv_sec; 409 strftime(buf, sizeof(buf) -1, "%c", localtime(&then)); 410 printf("%-*s", vent->width, buf); 411 } 412 413 void 414 wchan(const KINFO *k, const struct varent *vent) 415 { 416 if (*KI_LWP(k, wmesg)) { 417 printf("%-*.*s", vent->width, vent->width, 418 KI_LWP(k, wmesg)); 419 } else { 420 printf("%-*s", vent->width, "-"); 421 } 422 } 423 424 static u_int64_t 425 pgtob(u_int64_t pg) 426 { 427 static size_t pgsize; 428 429 if (pgsize == 0) 430 pgsize = getpagesize(); 431 return(pg * pgsize); 432 } 433 434 void 435 vsize(const KINFO *k, const struct varent *vent) 436 { 437 put64((uintmax_t)KI_PROC(k, vm_map_size)/1024, vent->width, 'k'); 438 } 439 440 void 441 rssize(const KINFO *k, const struct varent *vent) 442 { 443 /* XXX don't have info about shared */ 444 put64(pgtob(KI_PROC(k, vm_rssize))/1024, vent->width, 'k'); 445 } 446 447 /* doesn't account for text */ 448 void 449 p_rssize(const KINFO *k, const struct varent *vent) 450 { 451 put64(pgtob(KI_PROC(k, vm_rssize))/1024, vent->width, 'k'); 452 } 453 454 void 455 cputime(const KINFO *k, const struct varent *vent) 456 { 457 long secs; 458 long psecs; /* "parts" of a second. first micro, then centi */ 459 u_int64_t timeus; 460 char obuff[128]; 461 static char decimal_point = '\0'; 462 463 if (decimal_point == '\0') 464 decimal_point = localeconv()->decimal_point[0]; 465 466 /* 467 * This counts time spent handling interrupts. We could 468 * fix this, but it is not 100% trivial (and interrupt 469 * time fractions only work on the sparc anyway). XXX 470 */ 471 timeus = KI_LWP(k, uticks) + KI_LWP(k, sticks) + 472 KI_LWP(k, iticks); 473 secs = timeus / 1000000; 474 psecs = timeus % 1000000; 475 if (sumrusage) { 476 secs += KI_PROC(k, cru).ru_utime.tv_sec + 477 KI_PROC(k, cru).ru_stime.tv_sec; 478 psecs += KI_PROC(k, cru).ru_utime.tv_usec + 479 KI_PROC(k, cru).ru_stime.tv_usec; 480 } 481 /* 482 * round and scale to 100's 483 */ 484 psecs = (psecs + 5000) / 10000; 485 secs += psecs / 100; 486 psecs = psecs % 100; 487 #if 1 488 if (secs >= 86400) { 489 snprintf(obuff, sizeof(obuff), "%3ldd%02ld:%02ld", 490 secs / 86400, secs / (60 * 60) % 24, secs / 60 % 60); 491 } else if (secs >= 100 * 60) { 492 snprintf(obuff, sizeof(obuff), "%2ld:%02ld:%02ld", 493 secs / 60 / 60, secs / 60 % 60, secs % 60); 494 } else 495 #endif 496 { 497 snprintf(obuff, sizeof(obuff), "%3ld:%02ld%c%02ld", 498 secs / 60, secs % 60, 499 decimal_point, psecs); 500 } 501 printf("%*s", vent->width, obuff); 502 } 503 504 double 505 getpcpu(const KINFO *k) 506 { 507 static int failure; 508 509 if (!nlistread) 510 failure = donlist(); 511 if (failure) 512 return (0.0); 513 514 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 515 516 /* XXX - I don't like this */ 517 if (KI_PROC(k, swtime) == 0 || (KI_PROC(k, flags) & P_SWAPPEDOUT)) 518 return (0.0); 519 return (100.0 * fxtofl(KI_LWP(k, pctcpu))); 520 } 521 522 void 523 pcpu(const KINFO *k, const struct varent *vent) 524 { 525 printf("%*.1f", vent->width, getpcpu(k)); 526 } 527 528 void 529 pnice(const KINFO *k, const struct varent *vent) 530 { 531 int niceval; 532 533 switch (KI_LWP(k, rtprio).type) { 534 case RTP_PRIO_REALTIME: 535 niceval = PRIO_MIN - 1 - RTP_PRIO_MAX + KI_LWP(k, rtprio).prio; 536 break; 537 case RTP_PRIO_IDLE: 538 niceval = PRIO_MAX + 1 + KI_LWP(k, rtprio).prio; 539 break; 540 case RTP_PRIO_THREAD: 541 niceval = PRIO_MIN - 1 - RTP_PRIO_MAX - KI_LWP(k, rtprio).prio; 542 break; 543 default: 544 niceval = KI_PROC(k, nice) - NZERO; 545 break; 546 } 547 printf("%*d", vent->width, niceval); 548 } 549 550 551 double 552 getpmem(const KINFO *k) 553 { 554 static int failure; 555 double fracmem; 556 int szptudot; 557 558 if (!nlistread) 559 failure = donlist(); 560 if (failure) 561 return (0.0); 562 563 if (KI_PROC(k, flags) & P_SWAPPEDOUT) 564 return (0.0); 565 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 566 szptudot = UPAGES; 567 /* XXX don't have info about shared */ 568 fracmem = ((float)KI_PROC(k, vm_rssize) + szptudot)/mempages; 569 return (100.0 * fracmem); 570 } 571 572 void 573 pmem(const KINFO *k, const struct varent *vent) 574 { 575 printf("%*.1f", vent->width, getpmem(k)); 576 } 577 578 void 579 pagein(const KINFO *k, const struct varent *vent) 580 { 581 printf("%*ld", vent->width, KI_LWP(k, ru).ru_majflt); 582 } 583 584 /* ARGSUSED */ 585 void 586 maxrss(const KINFO *k __unused, const struct varent *vent) 587 { 588 printf("%*ld", vent->width, KI_PROC(k, ru).ru_maxrss); 589 } 590 591 void 592 tsize(const KINFO *k, const struct varent *vent) 593 { 594 put64(pgtob(KI_PROC(k, vm_tsize))/1024, vent->width, 'k'); 595 } 596 597 void 598 rtprior(const KINFO *k, const struct varent *vent) 599 { 600 struct rtprio *prtp; 601 char str[8]; 602 unsigned prio, type; 603 604 prtp = &KI_LWP(k, rtprio); 605 prio = prtp->prio; 606 type = prtp->type; 607 switch (type) { 608 case RTP_PRIO_REALTIME: 609 snprintf(str, sizeof(str), "real:%u", prio); 610 break; 611 case RTP_PRIO_NORMAL: 612 strncpy(str, "normal", sizeof(str)); 613 break; 614 case RTP_PRIO_IDLE: 615 snprintf(str, sizeof(str), "idle:%u", prio); 616 break; 617 default: 618 snprintf(str, sizeof(str), "%u:%u", type, prio); 619 break; 620 } 621 str[sizeof(str) - 1] = '\0'; 622 printf("%*s", vent->width, str); 623 } 624 625 /* 626 * Generic output routines. Print fields from various prototype 627 * structures. 628 */ 629 static void 630 printval(const char *bp, const struct varent *vent) 631 { 632 static char ofmt[32] = "%"; 633 const char *fcp; 634 char *cp; 635 636 cp = ofmt + 1; 637 fcp = vent->var->fmt; 638 if (vent->var->flag & LJUST) 639 *cp++ = '-'; 640 *cp++ = '*'; 641 while ((*cp++ = *fcp++)); 642 643 switch (vent->var->type) { 644 case CHAR: 645 printf(ofmt, vent->width, *(const char *)bp); 646 break; 647 case UCHAR: 648 printf(ofmt, vent->width, *(const u_char *)bp); 649 break; 650 case SHORT: 651 printf(ofmt, vent->width, *(const short *)bp); 652 break; 653 case USHORT: 654 printf(ofmt, vent->width, *(const u_short *)bp); 655 break; 656 case INT: 657 printf(ofmt, vent->width, *(const int *)bp); 658 break; 659 case UINT: 660 printf(ofmt, vent->width, *(const u_int *)bp); 661 break; 662 case LONG: 663 printf(ofmt, vent->width, *(const long *)bp); 664 break; 665 case ULONG: 666 printf(ofmt, vent->width, *(const u_long *)bp); 667 break; 668 case KPTR: 669 printf(ofmt, vent->width, *(const u_long *)bp); 670 break; 671 default: 672 errx(1, "unknown type %d", vent->var->type); 673 } 674 } 675 676 void 677 pvar(const KINFO *k, const struct varent *vent) 678 { 679 printval((char *)((char *)k->ki_proc + vent->var->off), vent); 680 } 681 682 void 683 lpest(const KINFO *k, const struct varent *vent) 684 { 685 int val; 686 687 val = *(int *)((char *)&k->ki_proc->kp_lwp + vent->var->off); 688 val = val / 128; 689 printval((char *)&val, vent); 690 } 691 692 693 void 694 lpvar(const KINFO *k, const struct varent *vent) 695 { 696 printval((char *)((char *)&k->ki_proc->kp_lwp + vent->var->off), vent); 697 } 698 699 void 700 rvar(const KINFO *k, const struct varent *vent) 701 { 702 printval(((const char *)&KI_LWP(k, ru) + vent->var->off), vent); 703 } 704 705 static const char * 706 make_printable(const char *str) 707 { 708 static char *cpy; 709 int len; 710 711 if (cpy) 712 free(cpy); 713 len = strlen(str); 714 if ((cpy = malloc(len * 4 + 1)) == NULL) 715 err(1, NULL); 716 strvis(cpy, str, VIS_TAB | VIS_NL | VIS_NOSLASH); 717 return(cpy); 718 } 719 720 /* 721 * Output a number, divide down as needed to fit within the 722 * field. This function differs from the code used by systat 723 * in that it tries to differentiate the display by always 724 * using a decimal point for excessively large numbers so 725 * the human eye naturally notices the difference. 726 */ 727 static void 728 put64(u_int64_t n, int w, int type) 729 { 730 char b[128]; 731 u_int64_t d; 732 u_int64_t u; 733 size_t len; 734 int ntype; 735 736 snprintf(b, sizeof(b), "%*jd", w, (uintmax_t)n); 737 len = strlen(b); 738 if (len <= (size_t)w) { 739 fwrite(b, len, 1, stdout); 740 return; 741 } 742 743 if (type == 'D') 744 u = 1000; 745 else 746 u = 1024; 747 748 ntype = 0; 749 for (d = 1; n / d >= 100000; d *= u) { 750 switch(type) { 751 case 'D': 752 case 0: 753 type = 'k'; 754 ntype = 'M'; 755 break; 756 case 'k': 757 type = 'M'; 758 ntype = 'G'; 759 break; 760 case 'M': 761 type = 'G'; 762 ntype = 'T'; 763 break; 764 case 'G': 765 type = 'T'; 766 ntype = 'X'; 767 break; 768 case 'T': 769 type = 'X'; 770 ntype = '?'; 771 break; 772 default: 773 type = '?'; 774 break; 775 } 776 } 777 if (w > 4 && n / d >= u) { 778 snprintf(b, sizeof(b), "%*ju.%02u%c", 779 w - 4, 780 (uintmax_t)(n / (d * u)), 781 (u_int)(n / (d * u / 100) % 100), 782 ntype); 783 } else { 784 snprintf(b, sizeof(b), "%*jd%c", 785 w - 1, (uintmax_t)n / d, type); 786 } 787 len = strlen(b); 788 fwrite(b, len, 1, stdout); 789 } 790