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