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
grabTimes(markptr)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
pfloat(dest,number,sep)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
reportConn()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
reportFile(breakmsg)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
reportTimes(dest,diffptr,sep)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
subTimes(diff,minuend,subtra)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 *
gmt()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
writeLog(string,logfile,logname,collecting)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
closeLog(logfile)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
copyText(tptr,size,string)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
pfConnected(remote,device)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
pfEndfile(breakmsg)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
pfEndXfer()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
pfFindFile()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
pfFound(jobid,flags,intoQue)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
pfInit()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
pfStrtConn(role)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
pfStrtXfer(role,direction)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
pfPtcl(str)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
openLog(logfile,logname)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
scale60(tvp)1041 scale60(tvp)
1042 register struct timeval *tvp;
1043 {
1044 return (tvp->tv_sec * 60 + tvp->tv_usec / 16667);
1045 }
1046
1047 clock_t
times(tmsp)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