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