1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * This module is intended to collect performance statistics about the 32 * operation of uucico. All instances of uucico will write their log 33 * entries to the files who's path is defined by PERFLOG. Statistics 34 * will only be collected if PERFLOG exists when uucico starts, it will 35 * not be created automatically. This gives the SA an easy way to turn 36 * statistics collection on or off at run time. Three types 37 * of records will be written to the file, and each record will be 38 * identified by a mnemonic type at the begining of the record. The record 39 * types are as follows: 40 * 41 * conn - Contains statistics about the establishment of 42 * a connection. 43 * 44 * xfer - Contains statistics about a file transfer. 45 * 46 * The intention is to use grep to select the conn and xfer records and put 47 * them in two Unity data bases. No attempt will be made to process the 48 * error records with Unity. 49 * 50 * Both the conn and the xfer records will contain a time stamp field. 51 * This field will be written in case there is a desire to do time of 52 * day traffic studies. The time that will be written will be GMT 53 * to avoid the vagaries of time zone setting for uucico. The time 54 * stamp will contain 12 digits of the form YYMMDDhhmmss. This allows 55 * proper sorting by time, and the fixed length field type of Unity 56 * can be used to pick it apart if necessary. The time stamp is the 57 * time that the record is written. 58 * 59 * Statistics will be collected on the wall clock (real) time to perform 60 * an action and CPU consumption to perform an action. These times will 61 * be written in seconds and fractions of a second to two decimal places. 62 * 63 * The conn and xfer records will be written so that they can be processed 64 * with the following Unity schema (D files). For those not familiar with 65 * Unity, the columns are: 66 * 67 * column 1 - field name 68 * column 2 - field type (t=variable width) and field separator. 69 * column 3 - number of columns to use when printing the field 70 * with uprint. 71 * column 4 - a user friendly field name. 72 * 73 * Conn: 74 * 75 * type t| 4 record type (always conn) 76 * ts t| 12 time stamp 77 * procid t| 5 uucico's process id 78 * myname t| 6 name of the machine where the record is written 79 * role t| 1 M = master, S = slave 80 * remote t| 6 name of remote system 81 * device t| 6 name of device used for connection 82 * protocol t| 1 the protocal that is used for communication 83 * netid t| 6 physical network ID 84 * real t| 6 real time to connect 85 * user t| 6 user time to connect 86 * sys t\n 6 system (kernal) time to connect 87 * 88 * The timer for connection processing starts immediately after the 89 * command line processing is complete, and it is stopped after the 90 * protocol has been selected. 91 * 92 * Xfer: 93 * 94 * type t| 4 record type (always xfer) 95 * jobgrade t| 1 job grade ID 96 * ts t| 12 time stamp 97 * procid t| 5 uucico's process id 98 * myname t| 6 name of the machine where the record is written 99 * role t| 1 M = master, S = slave 100 * remote t| 6 name of remote system 101 * device t| 6 name of device used for connection 102 * protocol t| 1 the protocal that is used for communication 103 * netid t| 6 physical network ID 104 * job t| 7 name of the job. (Master only). 105 * inqueue t| 6 time in seconds that file was in queue (Master 106 * only). 107 * tat t| 6 turn around time in sec. (Master only). 108 * bytes t| 6 size of the file that was transferred 109 * flags t| 3 m = mail to requester on completion, 110 * n = notify remote user, s = write status 111 * file. (Master only). 112 * streal t| 6 real time to start up transfer (master only). 113 * stuser t| 6 114 * stsys t| 6 115 * xfrreal t| 6 real time to transfer file 116 * xfruser t| 6 117 * xfrsys t| 6 118 * trmreal t| 6 real time to terminate the transfer 119 * trmuser t| 6 120 * trmsys t| 6 121 * text t| 12 "PARTIAL FILE" if the data is being transmitted 122 * before breaking the transmission; blank if the 123 * partial file after the breakpoint or the whole 124 * file is being transmitted completely. 125 * 126 * Start up time includes the time for the master to search the queues 127 * for the next file, for the master and slave to exchange work vectors, 128 * and time to open files. It is only recorded on the master. 129 * Xfer times is the time to transfer the data, close the file, and 130 * exchange confirmation messages. Termination time is the time to send 131 * mail notifications and write status files. Turn around time is the 132 * difference between the time that the file was queued and the time that 133 * the final notification was sent. 134 */ 135 136 #include "uucp.h" 137 #include "log.h" 138 139 /* 140 * SYMBOL DEFINITIONS 141 */ 142 143 #define FS '|' /* Field seperator for output records. */ 144 #define LOGCHECK {if ((Initialized == FALSE) || \ 145 (Collecting == FALSE)) return; } 146 147 /* Subscripts for connection time marks: */ 148 149 #define CT_START 0 /* Start connection establishment. */ 150 #define CT_CONNECTED 1 /* Connection completed. */ 151 #define CT_SIZE 2 /* Number of elements in array. */ 152 153 /* Subscripts for xfer time marks: */ 154 155 #define XT_LOOK 0 /* Start looking for a file (master only). */ 156 #define XT_FOUND 1 /* File found (master only). */ 157 #define XT_BEGXFER 2 /* Start of xfer of data. */ 158 #define XT_ENDXFER 3 /* Data xfer complete. */ 159 #define XT_ENDFILE 4 /* Done mailing and notifying. */ 160 #define XT_SIZE 5 /* Number of elements in array. */ 161 162 /* 163 * STRUCTURE DEFINITIONS 164 */ 165 166 typedef struct timeUsed /* Time consummed between events. */ 167 { 168 float tu_real; /* Real time used. */ 169 float tu_user; /* User time used. */ 170 float tu_sys; /* System time used. */ 171 } TUSED; 172 173 typedef struct timeMark /* Holds times for an event. */ 174 { 175 int tm_valid; /* True if data present. */ 176 long tm_real; /* Relative wall clock. */ 177 struct tms tm_cycles; /* CPU consumption. */ 178 } TMARK; 179 180 struct connData /* Data for construction of conn record. */ 181 { 182 char cn_role; /* Master/slave indicator. */ 183 TMARK cn_times[CT_SIZE]; /* Event data. */ 184 }; 185 186 struct xferData /* Data for construction of xfer record. */ 187 { 188 char xf_role; /* Master/slave indicator. */ 189 char xf_direction; /* Send/receive indicator. */ 190 time_t xf_intoque; /* Time that file was placed 191 * in the queue. (master 192 * only). */ 193 long xf_deque; /* Time that file was 194 * dequeued. (master only)*/ 195 long xf_filedone; /* Time that file was 196 * completed. */ 197 char xf_jobname[MODSTR]; /* C. file (master only)*/ 198 char xf_jobgrade[MODSTR]; /* job grade id */ 199 off_t xf_bytes; /* Bytes transferred. */ 200 char xf_flags[MODSTR]; /* Notification flags. */ 201 TMARK xf_times[XT_SIZE]; /* Event data. */ 202 }; 203 204 /* 205 * LOCAL DATA 206 */ 207 208 static int Collecting = FALSE; /* True if we are collecting 209 * data. */ 210 static struct connData Conn = {0}; /* Connection data. */ 211 static char Device[MODSTR] = ""; /* Type of communication 212 * device. */ 213 static int Initialized = FALSE; /* True if we have been 214 * initialized. */ 215 static int LogFile = CLOSED; /* Log file file destriptor. */ 216 static char LogName[] = PERFLOG; /* Name of our log file. */ 217 static pid_t Procid = {0}; /* Our processid. */ 218 static char Record[LOGSIZE]; /* Place to build log records. */ 219 static char Remote[MODSTR] = ""; /* Name of the remote system. */ 220 static char myname[MAXBASENAME+1] = ""; /* Name of the source system 221 . */ 222 static char Protocol[MODSTR]; /* Protocol in use */ 223 static char Netid[MODSTR] = NOTAVAIL; /* Network ID in use */ 224 static struct xferData Xfer = {0}; /* Transfer data. */ 225 226 /* Messages: */ 227 228 static char Msg_badopen[] = "failed to open %s. Errno=%%d\n"; 229 static char Msg_opening[] = "attempting to open %s\n"; 230 static char Msg_write[] = "error in writing to %s. Errno=%%d.\n"; 231 232 /* 233 * LOCAL FUNCTIONS 234 */ 235 236 /* Declarations of functions: */ 237 238 STATIC_FUNC void grabTimes(); 239 STATIC_FUNC void pfloat(); 240 STATIC_FUNC void reportConn(); 241 STATIC_FUNC void reportFile(); 242 STATIC_FUNC void reportTimes(); 243 STATIC_FUNC void subTimes(); 244 245 246 /* 247 * Local Function: grabTimes - Get Real and CPU Times 248 * 249 * This function uses times(2) to obtain the current real time and CPU 250 * consumption. The time mark is also marked as valid. 251 * 252 * Parameters: 253 * 254 * markptr - Address of structure to save times. 255 * 256 * Return: 257 * 258 * none. 259 */ 260 261 STATIC_FUNC void 262 grabTimes (markptr) 263 264 register TMARK * markptr; 265 266 { 267 markptr->tm_real = times(&markptr->tm_cycles); 268 if (markptr->tm_real != FAIL) 269 markptr->tm_valid = TRUE; 270 return; 271 } 272 273 274 /* 275 * Local Function: pfloat - Print a Floating Number 276 * 277 * Format a floating point number for output to the Unity data base. 278 * If the number is NOTIME, "na" will be displayed instead. 279 * 280 * Parameters: 281 * 282 * dest - The result will be concatenated to this string. 283 * 284 * number - The number to be formated. 285 * 286 * sep - Field separator character. 287 */ 288 289 STATIC_FUNC void 290 pfloat (dest, number, sep) 291 292 char * dest; 293 double number; /* float is promoted to double for args. */ 294 char sep; 295 296 { 297 static char rformat[] = "%c%.2f"; 298 static char naformat[] = "%c%s"; 299 300 register char * cp; 301 302 cp = dest + strlen(dest); 303 if (number == (float) NOTIME) 304 sprintf(cp, naformat, sep, NOTAVAIL); 305 else 306 sprintf(cp, rformat, sep, number); 307 return; 308 } 309 310 /* 311 * Local Function: reportConn - Write Out Conn Record 312 * 313 * This function writes a conn record to the logfile. 314 * 315 * Parameters: 316 * 317 * None. 318 * 319 * Returns: 320 * 321 * None. 322 */ 323 324 STATIC_FUNC void 325 reportConn () 326 327 { 328 TUSED contimes; /* Times to make connection. */ 329 static char format[] = "%s%c%s%c%ld%c%s%c%c%c%s%c%s%c%s%c%s"; 330 331 sprintf(Record, format, 332 "conn", FS, /* record type. */ 333 gmt(), FS, /* current time. */ 334 (long) Procid, FS, /* our process id. */ 335 myname, FS, /* name of local system */ 336 Conn.cn_role, FS, /* slave or master. */ 337 Remote, FS, /* name of remote system. */ 338 Device, FS, /* device used for communication. */ 339 Protocol, FS, /* protocol used for comm. */ 340 Netid /* Network ID */ 341 ); 342 subTimes(&contimes, &Conn.cn_times[CT_CONNECTED], 343 &Conn.cn_times[CT_START]); 344 reportTimes(Record, &contimes, FS); 345 strcat(Record, EOR); 346 writeLog(Record,&LogFile,LogName,&Collecting); 347 return; 348 } 349 350 /* 351 * Local Function: reportFile - Write File Statistics to Log 352 * 353 * This function writes statistics about the current file to the log 354 * file. 355 * 356 * Parameters: 357 * 358 * none. 359 */ 360 361 STATIC_FUNC void 362 reportFile (breakmsg) 363 char * breakmsg; 364 365 { 366 /* minuend, subtrahand */ 367 static int drvtab[] = { 368 XT_FOUND, XT_LOOK, /* startup */ 369 XT_ENDXFER, XT_BEGXFER, /* xfer */ 370 XT_ENDFILE, XT_ENDXFER /* term. */ 371 }; 372 static char format1[] = "%s%c%s%c%s%c%ld%c%s%c%c%c%s%c%s%c%s%c%s%c%s"; 373 static char format2[] = "%c%ld%c%s"; /* Bytes & flags. */ 374 375 register struct xferData * xdptr; 376 register TMARK * tdptr; 377 register int i; 378 379 TUSED diff; /* time difference between events. */ 380 float inque; /* time in queue. */ 381 int lastbyte; /* Offset to last byte in Record. */ 382 char * na = NOTAVAIL; /* String to show data not available*/ 383 char role; /* Current master/slave status. */ 384 float tat; /* Turn around time. */ 385 386 xdptr = &Xfer; /* Point to Xfer data. */ 387 role = xdptr->xf_role; 388 sprintf(Record, format1, 389 "xfer", FS, /* Record type. */ 390 (role == MCHAR) ? xdptr->xf_jobgrade : na ,FS, /* job grade */ 391 gmt(), FS, /* Current time. */ 392 (long) Procid, FS, /* Our process id. */ 393 myname, FS, /* name of local system */ 394 role, FS, /* master/slave. */ 395 Remote, FS, /* remote. */ 396 Device, FS, /* communications device. */ 397 Protocol, FS, /* protocol used for comm. */ 398 Netid, FS, /* Network ID */ 399 (role == MCHAR) ? xdptr->xf_jobname : na 400 ); 401 402 /* Do time in queue and turn around time. */ 403 404 if (role == MCHAR) 405 { 406 inque = (float) (xdptr->xf_deque - xdptr->xf_intoque); 407 tat = (float) (xdptr->xf_filedone - xdptr->xf_intoque); 408 } else 409 { 410 inque = (float) NOTIME; /* Not app. if not master. */ 411 tat = (float) NOTIME; 412 } 413 pfloat(Record, inque, FS); 414 pfloat(Record, tat, FS); 415 416 /* 417 * Report bytes transferred and notification flags. 418 */ 419 420 lastbyte = strlen(Record); 421 (void) sprintf(Record+lastbyte, format2, 422 FS, getfilesize(),FS, 423 (role == MCHAR) ? xdptr->xf_flags : na 424 ); 425 426 /* 427 * Report resource consumption for file startup, file transfer, 428 * and file termination. This means reporting the differences 429 * between pairs of elements in the xf_times array of Xfer. This 430 * will be controled by drvtab which contains pairs of subscripts 431 * to designate the xf_times elements. 432 */ 433 434 tdptr = &xdptr->xf_times[0]; 435 for (i = 0; i < sizeof(drvtab)/(sizeof(int)); i += 2) 436 { 437 subTimes(&diff, (tdptr + drvtab[i]), (tdptr + drvtab[i+1])); 438 reportTimes(Record, &diff, FS); 439 } 440 441 /* 442 * write file status 443 */ 444 445 lastbyte = strlen(Record); 446 (void) sprintf(Record+lastbyte, "%c%s%c", 447 FS, (*breakmsg == NULLCHAR) ? NOTAVAIL : breakmsg, FS); 448 449 /* Terminate the record and write it out. */ 450 451 (void) strcat(Record, EOR); 452 writeLog(Record,&LogFile,LogName,&Collecting); 453 return; 454 } 455 456 /* 457 * Local Function: reportTimes - Print Real, User, and Sys Times 458 * 459 * This function is used to convert the real, user, and system times from 460 * a TUSED structure to Ascii strings. The results are concatenated to 461 * the dest string. If any of the times are NOTIME, they will be reported 462 * as "na". The fields will be seperated by the sep character and the 463 * sep character will be the first character concatenated to the buffer. No 464 * seperator character will be placed at the end. Thus, the output string 465 * will be of the form: 466 * 467 * |real|user|sys 468 * 469 * Parameters: 470 * 471 * dest - String to receive Ascii times. 472 * 473 * diffptr - Address of the time data. 474 * 475 * sep - The field seperator character. 476 */ 477 478 STATIC_FUNC void 479 reportTimes (dest, diffptr, sep) 480 481 register char * dest; 482 register TUSED * diffptr; 483 char sep; 484 485 { 486 pfloat(dest, diffptr->tu_real, sep); 487 pfloat(dest, diffptr->tu_user, sep); 488 pfloat(dest, diffptr->tu_sys, sep); 489 return; 490 } 491 492 /* 493 * Local Function: subTimes - Subtract Times Between Events 494 * 495 * This function takes the output from two calls to times(2) in the form 496 * of two TMARK structures, and determines the amount of time consummed 497 * for various categories. The result is stored in the specified 498 * TUSED structure. 499 * 500 * Parameters: 501 * 502 * diff - Place to store the result of the subtraction. 503 * minuend - The second time event. 504 * subtra - The subtrahend in the subtraction. This should 505 * be the first of two time events. 506 * 507 * On the large scale this function does the following: 508 * 509 * diff = minuend - subtra 510 */ 511 512 STATIC_FUNC void 513 subTimes (diff, minuend, subtra) 514 515 register TUSED * diff; 516 register TMARK * minuend; 517 register TMARK * subtra; 518 519 { 520 register struct tms * mintms; 521 register struct tms * subtms; 522 523 long ltemp; /* Temporary storage for long arith. */ 524 float ticks; /* Clock interrupts per second. */ 525 526 if ((minuend->tm_valid != TRUE) || (subtra->tm_valid != TRUE)) 527 { /* If data has not been collected. */ 528 diff->tu_real = NOTIME; 529 diff->tu_user = NOTIME; 530 diff->tu_sys = NOTIME; 531 } else 532 { 533 ticks = (float) HZ; /* HZ defined in <sys/param.h>. */ 534 mintms = &minuend->tm_cycles; 535 subtms = &subtra->tm_cycles; 536 537 /* Calculate real time. */ 538 539 ltemp = minuend->tm_real - subtra->tm_real; 540 diff->tu_real = ((float) ltemp)/ticks; 541 542 /* Calculate user time. */ 543 544 ltemp = mintms->tms_utime 545 - subtms->tms_utime 546 + mintms->tms_cutime 547 - subtms->tms_cutime; 548 diff->tu_user = ((float) ltemp)/ticks; 549 550 /* Calculate user time. */ 551 552 ltemp = mintms->tms_stime 553 - subtms->tms_stime 554 + mintms->tms_cstime 555 - subtms->tms_cstime; 556 diff->tu_sys = ((float) ltemp)/ticks; 557 } 558 return; 559 } 560 561 /* 562 * EXTERNAL FUNCTIONS 563 */ 564 565 /* 566 * Function: gmt - Generate Current Time String 567 * 568 * This function returns the address a string containing the current 569 * GMT in the form YYMMDDhhmmss. 570 * 571 * Parameters: 572 * 573 * none 574 * 575 * Return: 576 * 577 * An address of a static character array containing the date. 578 */ 579 580 char * 581 gmt() 582 583 { 584 static char date[] = "YYMMDDhhmmss"; 585 586 register struct tm * td; 587 time_t now; /* Current time. */ 588 589 now = time((time_t *) 0); 590 td = gmtime(&now); 591 (void) sprintf(date, "%02d%02d%02d%02d%02d%02d", 592 (td->tm_year % 100), 593 td->tm_mon + 1, 594 td->tm_mday, 595 td->tm_hour, 596 td->tm_min, 597 td->tm_sec 598 ); 599 return date; 600 } 601 602 603 /* 604 * Function: writeLog - Write String to Log File 605 * 606 * After insuring that the log file is open, this function will write 607 * the specified string to the log file. If a write error occurs, 608 * statistics collection will be disabled. 609 * 610 * Parameters: 611 * 612 * string - Null terminated string to be written out. 613 * logfile - file descripter 614 * logname - name of log file. 615 * collecting - log enable/disable 616 */ 617 618 void 619 writeLog (string, logfile, logname, collecting) 620 621 char * string; 622 int * logfile; 623 char * logname; 624 int * collecting; 625 626 { 627 register int length; /* Length of the string. */ 628 register int rv; /* Return value from write. */ 629 630 char errmsg[BUFSIZ]; /* Place for error messages. */ 631 632 if (openLog(logfile,logname) != SUCCESS){ 633 *collecting = FALSE; 634 return; 635 } 636 length = strlen(string); 637 do 638 { 639 rv = write(*logfile, string, (unsigned) length); 640 } while ((rv < 0) && (errno == EINTR)); /* Retry if interrupted. */ 641 if (rv < length) 642 { /* Error or incomplete output. */ 643 (void) sprintf(errmsg, Msg_write, logname); 644 DEBUG(DB_IMPORTANT, errmsg, errno); 645 646 /* If we had a write error, lets give up on loggine. */ 647 648 closeLog(logfile); 649 *collecting = FALSE; 650 } 651 return; 652 } 653 654 /* 655 * Function: closeLog - Close the Log File 656 * 657 * This function allows uucico to close the log file in preparation for 658 * forking. 659 * 660 * Parameters: 661 * 662 * log file descriptor 663 */ 664 665 void 666 closeLog (logfile) 667 int *logfile; 668 669 { 670 if (*logfile != CLOSED) 671 { 672 (void) close(*logfile); 673 *logfile = CLOSED; 674 } 675 return; 676 } 677 678 679 /* 680 * Function: copyText - Copy String to Dynamic Memory 681 * 682 * This function copies a string to a buffer. It insures that there is 683 * no overflow of the buffer and that the result is null terminated. 684 * 685 * Parameters: 686 * 687 * tptr - address of the buffer where the string is to 688 * be stored. 689 * 690 * size - number of bytes in the buffer. 691 * 692 * string - string to be saved. 693 * 694 * Returns: 695 * 696 * none. 697 */ 698 699 void 700 copyText (tptr, size, string) 701 702 register char * tptr; 703 register int size; 704 char * string; 705 706 { 707 (void) strncpy(tptr, string, size); 708 *(tptr + size - 1) = NULLCHAR; 709 return; 710 } 711 712 /* 713 * Function: pfConnected - Report Connection Completion 714 * 715 * Uucico uses pfConnected to tell this performance package that a connection 716 * has been established with the remote system. 717 * 718 * Parameters: 719 * 720 * remote - name of the remote system. 721 * 722 * device - the type of device being used for communicaitons. 723 */ 724 725 void 726 pfConnected (remote, device) 727 728 char * remote; 729 char * device; 730 731 { 732 register int i; 733 register TMARK * tptr; 734 735 LOGCHECK; 736 grabTimes(&Conn.cn_times[CT_CONNECTED]); 737 copyText(Remote, sizeof(Remote), remote); 738 copyText(Device, sizeof(Device), device); 739 reportConn(); 740 tptr = &Conn.cn_times[0]; 741 742 /* 743 * Mark connection times as invalid. This is really unnecessary 744 * since there should only be one connection per invocation of uucico. 745 * We do it for consistency with use of the transfer data. 746 */ 747 748 for (i = 0; i < CT_SIZE; i++, tptr++) 749 tptr->tm_valid = FALSE; 750 return; 751 } 752 753 754 /* 755 * Function: pfEndFile - Report End of File 756 * 757 * Uucico uses pfEndFile to tell our statistics collection package that 758 * all processing has been finished on the current file. PfEndfile should 759 * be called after all notifications have been done and after the status 760 * file has been written. PfEndfile writes out a xfer record for the 761 * file that just completed. 762 * 763 * Parameters: 764 * 765 * none 766 */ 767 768 void 769 pfEndfile (breakmsg) 770 char * breakmsg; 771 { 772 register int i; 773 register TMARK * tdptr; 774 register struct xferData * xptr = &Xfer; 775 776 LOGCHECK; 777 grabTimes(&Xfer.xf_times[XT_ENDFILE]); 778 Xfer.xf_filedone = time((time_t *) 0); 779 reportFile(breakmsg); 780 781 /* Now that we have reported them, mark all times as invalid. */ 782 783 copyText(xptr->xf_flags, sizeof(xptr->xf_flags), NOTAVAIL); 784 tdptr = &Xfer.xf_times[0]; 785 for (i = 0; i < XT_SIZE; i++, tdptr++) 786 tdptr->tm_valid = FALSE; 787 return; 788 } 789 790 /* 791 * Function: pfEndXfer - File Transfer Complete 792 * 793 * Calling pfEndXfer tells the performance package that a file transfer 794 * has been completed. It should be called after the destination site 795 * closes the file and confirms receipt, but before notifications are done. 796 * 797 * Parameters: 798 * 799 * none 800 */ 801 802 void 803 pfEndXfer () 804 805 { 806 LOGCHECK; 807 grabTimes(&Xfer.xf_times[XT_ENDXFER]); 808 return; 809 } 810 811 /* 812 * Function: pfFindFile - Looking for Another File 813 * 814 * Uucico uses pfFindFile to announce that it is going to explore the 815 * queues for another file transfer to do. PfFindFile is only called 816 * when uucico is in the role of master. 817 * 818 * Parameters: 819 * 820 * none 821 */ 822 823 void 824 pfFindFile () 825 826 { 827 LOGCHECK; 828 grabTimes(&Xfer.xf_times[XT_LOOK]); 829 return; 830 } 831 832 /* 833 * Function: pfFound - Found Another File 834 * 835 * PfFound is a counterpart of pfFindFile. It is called when a new file 836 * has been found. Like pfFindFile it is called only by a master uucico. 837 * 838 * Parameters: 839 * 840 * jobid - The name of the job that was found. 841 * 842 * flags - Options flags that were stored in the queue. 843 * These flags are originally set by uucp. 844 * 845 * intoQue - The time that the C. file was placed in the queue. 846 */ 847 848 void 849 pfFound (jobid, flags, intoQue) 850 851 char * jobid; 852 char * flags; 853 time_t intoQue; 854 855 { 856 register struct xferData * xptr = &Xfer; 857 858 LOGCHECK; 859 grabTimes(&xptr->xf_times[XT_FOUND]); 860 copyText(xptr->xf_jobname, sizeof(xptr->xf_jobname), jobid); 861 xptr->xf_jobgrade[0] = jobid[strlen(jobid)-5]; 862 xptr->xf_jobgrade[1] = NULLCHAR;/* get job grade from jobid */ 863 copyText(xptr->xf_flags, sizeof(xptr->xf_flags), flags); 864 865 /* Save time that file was placed in queue and current time. */ 866 867 xptr->xf_intoque = intoQue; 868 xptr->xf_deque = time((time_t *) 0); 869 return; 870 } 871 872 /* 873 * Function: pfInit - Initialize Performance Package 874 * 875 * This function allows the performance package to initialize its internal 876 * data structures. It should be called one time only when uucico starts 877 * running. 878 * 879 * Parameters: 880 * 881 * none 882 */ 883 884 void 885 pfInit () 886 887 { 888 register struct xferData * xptr = &Xfer; 889 890 if (Initialized == TRUE) 891 return; 892 Procid = getpid(); 893 myName(myname); 894 copyText(xptr->xf_flags, sizeof(xptr->xf_flags), NOTAVAIL); 895 896 /* 897 * Attempt to open the log file. If we can't do it, then we 898 * won't collect statistics. 899 */ 900 901 if (openLog(&LogFile,LogName) == SUCCESS) 902 Collecting = TRUE; 903 else 904 Collecting = FALSE; 905 Initialized = TRUE; 906 return; 907 } 908 909 /* 910 * Function: pfStrtConn - Going to Establish Connection 911 * 912 * Uucico uses pfStrtConn to announce that it is going to attempt 913 * to establish a connection. 914 * 915 * Parameters: 916 * 917 * role - An indication of whether uucico is currently 918 * running in master or slave mode. M = master, 919 * S = slave. 920 */ 921 922 void 923 pfStrtConn (role) 924 925 char role; 926 { 927 LOGCHECK; 928 grabTimes(&Conn.cn_times[CT_START]); 929 Conn.cn_role = role; 930 return; 931 } 932 933 /* 934 * Function: pfStrtXfer - Starting File Transfer 935 * 936 * This function should be called just as the first byte of data is 937 * about to be transferred. 938 * 939 * Parameters: 940 * 941 * role - An indication of whether uucico is currently 942 * running in master or slave mode. M = master, 943 * S = slave. 944 * 945 * direction - Direction of file transfer. S = sending to 946 * remote, R = receiving from remote. 947 */ 948 949 void 950 pfStrtXfer(role, direction) 951 952 char role; 953 char direction; 954 955 { 956 register struct xferData * xptr = &Xfer; 957 958 LOGCHECK; 959 grabTimes(&xptr->xf_times[XT_BEGXFER]); 960 xptr->xf_role = role; 961 xptr->xf_direction = direction; 962 return; 963 } 964 965 /* 966 A protocol which both master and slave sides agree on 967 */ 968 969 void 970 pfPtcl(str) 971 char *str; 972 { 973 strcpy(Protocol,str); 974 return; 975 } 976 977 /* 978 * Function: openLog - Open the Log File 979 * 980 * If the log file is already open this function immediately returns 981 * success. Otherwise, an attempt is made to open the logfile in append 982 * mode. 983 * 984 * Parameters: 985 * 986 * logfile - file descripter 987 * logname - name of log file. 988 * 989 * Returns: 990 * 991 * SUCCESS - The log file is open. 992 * FAIL - Unable to open logfile. 993 */ 994 995 int 996 openLog (logfile,logname) 997 int *logfile; 998 char *logname; 999 { 1000 register int fd; /* File descriptor of log file. */ 1001 1002 int level; /* Level for debug message. */ 1003 char msgbuf[BUFSIZ]; 1004 1005 /* See if file already open. */ 1006 1007 if (*logfile != CLOSED) 1008 return (SUCCESS); 1009 1010 /* Attempt to open the file. */ 1011 1012 DEBUG(DB_TRACE, Msg_opening, logname); 1013 do 1014 { 1015 fd = open(logname, O_WRONLY | O_APPEND); 1016 } while ((fd < 0) && (errno == EINTR)); /* Retry if interrupted. */ 1017 if (fd < 0) { /* Error on open. */ 1018 (void) sprintf(msgbuf, Msg_badopen, logname); 1019 if (errno == ENOENT) 1020 level = DB_DETAIL; /* If the file is not there 1021 * it will usually mean 1022 * that the SA doesn't 1023 * want to collect 1024 * statisitcs. */ 1025 else 1026 level = DB_IMPORTANT; /* Unexpected error */ 1027 DEBUG(level, msgbuf, errno); /* No log file. */ 1028 return FAIL; 1029 } else { 1030 *logfile = fd; 1031 return SUCCESS; 1032 } 1033 } 1034 1035 #ifdef BSD4_2 1036 #include <sys/time.h> 1037 #include <sys/times.h> 1038 #include <sys/resource.h> 1039 1040 static clock_t 1041 scale60(tvp) 1042 register struct timeval *tvp; 1043 { 1044 return (tvp->tv_sec * 60 + tvp->tv_usec / 16667); 1045 } 1046 1047 clock_t 1048 times(tmsp) 1049 register struct tms *tmsp; 1050 { 1051 struct rusage ru; 1052 struct timeval now; 1053 static time_t epoch; 1054 1055 if (getrusage(RUSAGE_SELF, &ru) < 0) 1056 return (clock_t)(-1); 1057 tmsp->tms_utime = scale60(&ru.ru_utime); 1058 tmsp->tms_stime = scale60(&ru.ru_stime); 1059 if (getrusage(RUSAGE_CHILDREN, &ru) < 0) 1060 return (clock_t)(-1); 1061 tmsp->tms_cutime = scale60(&ru.ru_utime); 1062 tmsp->tms_cstime = scale60(&ru.ru_stime); 1063 if (gettimeofday(&now, (struct timezone *)0) < 0) 1064 return (clock_t)(-1); 1065 if (epoch == 0) 1066 epoch = now.tv_sec; 1067 now.tv_sec -= epoch; 1068 return (scale60(&now)); 1069 } 1070 #endif /* BSD4_2 */ 1071