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