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 53static int 54alldigits(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 69int 70atoiwi(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 109char * 110itoa(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 139char * 140itoa_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 172char * 173itoa7(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 185int 186digits(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 210char * 211printable(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 234char * 235strcpyend(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 250char *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 275int 276string_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 301char *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 340char ** 341argparse(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 423long 424percentages(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 482extern char *sys_errlist[]; 483#endif 484 485extern int sys_nerr; 486#endif 487 488const char * 489errmsg(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 514char * 515format_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 554char * 555format_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 610char * 611format_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 642static struct timeval lasttime = { 0, 0 }; 643static unsigned int elapsed_msecs = 0; 644 645void 646time_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 658void 659time_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 698unsigned int 699time_elapsed() 700 701{ 702 return elapsed_msecs; 703} 704 705unsigned int 706diff_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 712void 713double2tv(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 722static int debug_on = 0; 723 724#ifdef DEBUG 725FILE *debugfile; 726#endif 727 728void 729debug_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 739void 740xdprintf(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