1 /* 2 * Copyright (c) 1984 through 2008, William LeFebvre 3 * 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 are met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * * Neither the name of William LeFebvre nor the names of other 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Top users/processes display for Unix 35 * Version 3 36 */ 37 38 /* 39 * This file contains various handy utilities used by top. 40 */ 41 42 #include "os.h" 43 #include <ctype.h> 44 #ifdef HAVE_STDARG_H 45 #include <stdarg.h> 46 #else 47 #undef DEBUG 48 #endif 49 #include "top.h" 50 #include "utils.h" 51 52 static int 53 alldigits(char *s) 54 55 { 56 int ch; 57 58 while ((ch = *s++) != '\0') 59 { 60 if (!isdigit(ch)) 61 { 62 return 0; 63 } 64 } 65 return 1; 66 } 67 68 int 69 atoiwi(char *str) 70 71 { 72 register int len; 73 74 len = strlen(str); 75 if (len != 0) 76 { 77 if (strncmp(str, "infinity", len) == 0 || 78 strncmp(str, "all", len) == 0 || 79 strncmp(str, "maximum", len) == 0) 80 { 81 return(Infinity); 82 } 83 else if (alldigits(str)) 84 { 85 return(atoi(str)); 86 } 87 else 88 { 89 return(Invalid); 90 } 91 } 92 return(0); 93 } 94 95 /* 96 * itoa - convert integer (decimal) to ascii string for positive numbers 97 * only (we don't bother with negative numbers since we know we 98 * don't use them). 99 */ 100 101 /* 102 * How do we know that 16 will suffice? 103 * Because the biggest number that we will 104 * ever convert will be 2^32-1, which is 10 105 * digits. 106 */ 107 108 char * 109 itoa(int val) 110 111 { 112 register char *ptr; 113 static char buffer[16]; /* result is built here */ 114 /* 16 is sufficient since the largest number 115 we will ever convert will be 2^32-1, 116 which is 10 digits. */ 117 118 ptr = buffer + sizeof(buffer); 119 *--ptr = '\0'; 120 if (val == 0) 121 { 122 *--ptr = '0'; 123 } 124 else while (val != 0) 125 { 126 *--ptr = (val % 10) + '0'; 127 val /= 10; 128 } 129 return(ptr); 130 } 131 132 /* 133 * itoa7(val) - like itoa, except the number is right justified in a 7 134 * character field. This code is a duplication of itoa instead of 135 * a front end to a more general routine for efficiency. 136 */ 137 138 char * 139 itoa_w(int val, int w) 140 141 { 142 char *ptr; 143 char *eptr; 144 static char buffer[16]; /* result is built here */ 145 /* 16 is sufficient since the largest number 146 we will ever convert will be 2^32-1, 147 which is 10 digits. */ 148 149 if (w > 15) 150 { 151 w = 15; 152 } 153 eptr = ptr = buffer + sizeof(buffer); 154 *--ptr = '\0'; 155 if (val == 0) 156 { 157 *--ptr = '0'; 158 } 159 else while (val != 0) 160 { 161 *--ptr = (val % 10) + '0'; 162 val /= 10; 163 } 164 while (ptr >= eptr - w) 165 { 166 *--ptr = ' '; 167 } 168 return(ptr); 169 } 170 171 char * 172 itoa7(int val) 173 174 { 175 return itoa_w(val, 7); 176 } 177 178 /* 179 * digits(val) - return number of decimal digits in val. Only works for 180 * positive numbers. If val < 0 then digits(val) == 0, but 181 * digits(0) == 1. 182 */ 183 184 int 185 digits(int val) 186 187 { 188 register int cnt = 0; 189 190 if (val == 0) 191 { 192 return 1; 193 } 194 while (val > 0) 195 { 196 cnt++; 197 val /= 10; 198 } 199 return(cnt); 200 } 201 202 /* 203 * printable(char *str) - make the string pointed to by "str" into one that is 204 * printable (i.e.: all ascii), by converting all non-printable 205 * characters into '?'. Replacements are done in place and a pointer 206 * to the original buffer is returned. 207 */ 208 209 char * 210 printable(char *str) 211 212 { 213 register char *ptr; 214 register int ch; 215 216 ptr = str; 217 while ((ch = *ptr) != '\0') 218 { 219 if (!isprint(ch)) 220 { 221 *ptr = '?'; 222 } 223 ptr++; 224 } 225 return(str); 226 } 227 228 /* 229 * strcpyend(to, from) - copy string "from" into "to" and return a pointer 230 * to the END of the string "to". 231 */ 232 233 char * 234 strcpyend(char *to, const char *from) 235 236 { 237 while ((*to++ = *from++) != '\0'); 238 return(--to); 239 } 240 241 /* 242 * char * 243 * homogenize(const char *str) 244 * 245 * Remove unwanted characters from "str" and make everything lower case. 246 * Newly allocated string is returned: the original is not altered. 247 */ 248 249 char *homogenize(const char *str) 250 251 { 252 char *ans; 253 char *fr; 254 char *to; 255 int ch; 256 257 to = fr = ans = estrdup(str); 258 while ((ch = *fr++) != '\0') 259 { 260 if (isalnum(ch)) 261 { 262 *to++ = tolower(ch); 263 } 264 } 265 266 *to = '\0'; 267 return ans; 268 } 269 270 /* 271 * string_index(string, array) - find string in array and return index 272 */ 273 274 int 275 string_index(const char *string, const char **array) 276 277 { 278 register int i = 0; 279 280 while (*array != NULL) 281 { 282 if (strcmp(string, *array) == 0) 283 { 284 return(i); 285 } 286 array++; 287 i++; 288 } 289 return(-1); 290 } 291 292 /* 293 * char *string_list(char **strings) 294 * 295 * Create a comma-separated list of the strings in the NULL-terminated 296 * "strings". Returned string is malloc-ed and should be freed when the 297 * caller is done. Note that this is not an efficient function. 298 */ 299 300 char *string_list(const char **strings) 301 302 { 303 int cnt = 0; 304 const char **pp; 305 const char *p; 306 char *result = NULL; 307 char *resp = NULL; 308 309 pp = strings; 310 while ((p = *pp++) != NULL) 311 { 312 cnt += strlen(p) + 2; 313 } 314 315 if (cnt > 0) 316 { 317 resp = result = emalloc(cnt); 318 pp = strings; 319 while ((p = *pp++) != NULL) 320 { 321 resp = strcpyend(resp, p); 322 if (*pp != NULL) 323 { 324 resp = strcpyend(resp, ", "); 325 } 326 } 327 } 328 329 return result; 330 } 331 332 /* 333 * argparse(line, cntp) - parse arguments in string "line", separating them 334 * out into an argv-like array, and setting *cntp to the number of 335 * arguments encountered. This is a simple parser that doesn't understand 336 * squat about quotes. 337 */ 338 339 char ** 340 argparse(char *line, int *cntp) 341 342 { 343 register char *from; 344 register char *to; 345 register int cnt; 346 register int ch; 347 int length; 348 int lastch; 349 register char **argv; 350 char **argarray; 351 char *args; 352 353 /* unfortunately, the only real way to do this is to go thru the 354 input string twice. */ 355 356 /* step thru the string counting the white space sections */ 357 from = line; 358 lastch = cnt = length = 0; 359 while ((ch = *from++) != '\0') 360 { 361 length++; 362 if (ch == ' ' && lastch != ' ') 363 { 364 cnt++; 365 } 366 lastch = ch; 367 } 368 369 /* add three to the count: one for the initial "dummy" argument, 370 one for the last argument and one for NULL */ 371 cnt += 3; 372 373 /* allocate a char * array to hold the pointers */ 374 argarray = emalloc(cnt * sizeof(char *)); 375 376 /* allocate another array to hold the strings themselves */ 377 args = emalloc(length+2); 378 379 /* initialization for main loop */ 380 from = line; 381 to = args; 382 argv = argarray; 383 lastch = '\0'; 384 385 /* create a dummy argument to keep getopt happy */ 386 *argv++ = to; 387 *to++ = '\0'; 388 cnt = 2; 389 390 /* now build argv while copying characters */ 391 *argv++ = to; 392 while ((ch = *from++) != '\0') 393 { 394 if (ch != ' ') 395 { 396 if (lastch == ' ') 397 { 398 *to++ = '\0'; 399 *argv++ = to; 400 cnt++; 401 } 402 *to++ = ch; 403 } 404 lastch = ch; 405 } 406 *to++ = '\0'; 407 408 /* set cntp and return the allocated array */ 409 *cntp = cnt; 410 return(argarray); 411 } 412 413 /* 414 * percentages(cnt, out, new, old, diffs) - calculate percentage change 415 * between array "old" and "new", putting the percentages i "out". 416 * "cnt" is size of each array and "diffs" is used for scratch space. 417 * The array "old" is updated on each call. 418 * The routine assumes modulo arithmetic. This function is especially 419 * useful on BSD mchines for calculating cpu state percentages. 420 */ 421 422 long 423 percentages(int cnt, int *out, long *new, long *old, long *diffs) 424 425 { 426 register int i; 427 register long change; 428 register long total_change; 429 register long *dp; 430 long half_total; 431 432 /* initialization */ 433 total_change = 0; 434 dp = diffs; 435 436 /* calculate changes for each state and the overall change */ 437 for (i = 0; i < cnt; i++) 438 { 439 if ((change = *new - *old) < 0) 440 { 441 /* this only happens when the counter wraps */ 442 change = (int) 443 ((unsigned long)*new-(unsigned long)*old); 444 } 445 total_change += (*dp++ = change); 446 *old++ = *new++; 447 } 448 449 /* avoid divide by zero potential */ 450 if (total_change == 0) 451 { 452 total_change = 1; 453 } 454 455 /* calculate percentages based on overall change, rounding up */ 456 half_total = total_change / 2l; 457 for (i = 0; i < cnt; i++) 458 { 459 *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); 460 } 461 462 /* return the total in case the caller wants to use it */ 463 return(total_change); 464 } 465 466 /* 467 * errmsg(errnum) - return an error message string appropriate to the 468 * error number "errnum". This is a substitute for the System V 469 * function "strerror". There appears to be no reliable way to 470 * determine if "strerror" exists at compile time, so I make do 471 * by providing something of similar functionality. For those 472 * systems that have strerror and NOT errlist, define 473 * -DHAVE_STRERROR in the module file and this function will 474 * use strerror. 475 */ 476 477 /* externs referenced by errmsg */ 478 479 #ifndef HAVE_STRERROR 480 #if !HAVE_DECL_SYS_ERRLIST 481 extern char *sys_errlist[]; 482 #endif 483 484 extern int sys_nerr; 485 #endif 486 487 const char * 488 errmsg(int errnum) 489 490 { 491 #ifdef HAVE_STRERROR 492 char *msg = strerror(errnum); 493 if (msg != NULL) 494 { 495 return msg; 496 } 497 #else 498 if (errnum > 0 && errnum < sys_nerr) 499 { 500 return((char *)(sys_errlist[errnum])); 501 } 502 #endif 503 return("No error"); 504 } 505 506 /* format_percent(v) - format a double as a percentage in a manner that 507 * does not exceed 5 characters (excluding any trailing 508 * percent sign). Since it is possible for the value 509 * to exceed 100%, we format such values with no fractional 510 * component to fit within the 5 characters. 511 */ 512 513 char * 514 format_percent(double v) 515 516 { 517 static char result[10]; 518 519 /* enumerate the possibilities */ 520 if (v < 0 || v >= 100000.) 521 { 522 /* we dont want to try extreme values */ 523 strcpy(result, " ???"); 524 } 525 else if (v > 99.99) 526 { 527 sprintf(result, "%5.0f", v); 528 } 529 else 530 { 531 sprintf(result, "%5.2f", v); 532 } 533 534 return result; 535 } 536 537 /* format_time(seconds) - format number of seconds into a suitable 538 * display that will fit within 6 characters. Note that this 539 * routine builds its string in a static area. If it needs 540 * to be called more than once without overwriting previous data, 541 * then we will need to adopt a technique similar to the 542 * one used for format_k. 543 */ 544 545 /* Explanation: 546 We want to keep the output within 6 characters. For low values we use 547 the format mm:ss. For values that exceed 999:59, we switch to a format 548 that displays hours and fractions: hhh.tH. For values that exceed 549 999.9, we use hhhh.t and drop the "H" designator. For values that 550 exceed 9999.9, we use "???". 551 */ 552 553 char * 554 format_time(long seconds) 555 556 { 557 static char result[10]; 558 559 /* sanity protection */ 560 if (seconds < 0 || seconds > (99999l * 360l)) 561 { 562 strcpy(result, " ???"); 563 } 564 else if (seconds >= (1000l * 60l)) 565 { 566 /* alternate (slow) method displaying hours and tenths */ 567 sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l)); 568 569 /* It is possible that the sprintf took more than 6 characters. 570 If so, then the "H" appears as result[6]. If not, then there 571 is a \0 in result[6]. Either way, it is safe to step on. 572 */ 573 result[6] = '\0'; 574 } 575 else 576 { 577 /* standard method produces MMM:SS */ 578 /* we avoid printf as must as possible to make this quick */ 579 sprintf(result, "%3ld:%02ld", seconds / 60l, seconds % 60l); 580 } 581 return(result); 582 } 583 584 /* 585 * format_k(amt) - format a kilobyte memory value, returning a string 586 * suitable for display. Returns a pointer to a static 587 * area that changes each call. "amt" is converted to a 588 * string with a trailing "K". If "amt" is 10000 or greater, 589 * then it is formatted as megabytes (rounded) with a 590 * trailing "M". 591 */ 592 593 /* 594 * Compromise time. We need to return a string, but we don't want the 595 * caller to have to worry about freeing a dynamically allocated string. 596 * Unfortunately, we can't just return a pointer to a static area as one 597 * of the common uses of this function is in a large call to sprintf where 598 * it might get invoked several times. Our compromise is to maintain an 599 * array of strings and cycle thru them with each invocation. We make the 600 * array large enough to handle the above mentioned case. The constant 601 * NUM_STRINGS defines the number of strings in this array: we can tolerate 602 * up to NUM_STRINGS calls before we start overwriting old information. 603 * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer 604 * to convert the modulo operation into something quicker. What a hack! 605 */ 606 607 #define NUM_STRINGS 8 608 609 char * 610 format_k(long amt) 611 612 { 613 static char retarray[NUM_STRINGS][16]; 614 static int idx = 0; 615 register char *ret; 616 register char tag = 'K'; 617 618 ret = retarray[idx]; 619 idx = (idx + 1) % NUM_STRINGS; 620 621 if (amt >= 10000) 622 { 623 amt = (amt + 512) / 1024; 624 tag = 'M'; 625 if (amt >= 10000) 626 { 627 amt = (amt + 512) / 1024; 628 tag = 'G'; 629 } 630 } 631 632 snprintf(ret, sizeof(retarray[idx])-1, "%ld%c", amt, tag); 633 634 return(ret); 635 } 636 637 /* 638 * Time keeping functions. 639 */ 640 641 static struct timeval lasttime = { 0, 0 }; 642 static unsigned int elapsed_msecs = 0; 643 644 void 645 time_get(struct timeval *tv) 646 647 { 648 /* get the current time */ 649 #ifdef HAVE_GETTIMEOFDAY 650 gettimeofday(tv, NULL); 651 #else 652 tv->tv_sec = (long)time(NULL); 653 tv->tv_usec = 0; 654 #endif 655 } 656 657 void 658 time_mark(struct timeval *tv) 659 660 { 661 struct timeval thistime; 662 struct timeval timediff; 663 664 /* if the caller didnt provide one then use our own */ 665 if (tv == NULL) 666 { 667 tv = &thistime; 668 } 669 670 /* get the current time */ 671 #ifdef HAVE_GETTIMEOFDAY 672 gettimeofday(tv, NULL); 673 #else 674 tv->tv_sec = (long)time(NULL); 675 tv->tv_usec = 0; 676 #endif 677 678 /* calculate the difference */ 679 timediff.tv_sec = tv->tv_sec - lasttime.tv_sec; 680 timediff.tv_usec = tv->tv_usec - lasttime.tv_usec; 681 if (timediff.tv_usec < 0) { 682 timediff.tv_sec--; 683 timediff.tv_usec += 1000000; 684 } 685 686 /* convert to milliseconds */ 687 elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000; 688 if (elapsed_msecs == 0) 689 { 690 elapsed_msecs = 1; 691 } 692 693 /* save for next time */ 694 lasttime = *tv; 695 } 696 697 unsigned int 698 time_elapsed() 699 700 { 701 return elapsed_msecs; 702 } 703 704 unsigned int 705 diff_per_second(unsigned int x, unsigned int y) 706 707 { 708 return (y > x ? UINT_MAX - y + x + 1 : x - y) * 1000 / elapsed_msecs; 709 } 710 711 void 712 double2tv(struct timeval *tv, double d) 713 { 714 tv->tv_sec = (int)d; 715 tv->tv_usec = (d - tv->tv_sec) * 1000000; 716 } 717 718 static int debug_on = 0; 719 720 #ifdef DEBUG 721 FILE *debugfile; 722 #endif 723 724 void 725 debug_set(int i) 726 727 { 728 debug_on = i; 729 #ifdef DEBUG 730 debugfile = fopen("/tmp/top.debug", "w"); 731 #endif 732 } 733 734 #ifdef DEBUG 735 void 736 xdprintf(char *fmt, ...) 737 738 { 739 va_list argp; 740 741 va_start(argp, fmt); 742 743 if (debug_on) 744 { 745 vfprintf(debugfile, fmt, argp); 746 fflush(debugfile); 747 } 748 749 va_end(argp); 750 } 751 #endif 752 753