Home | History | Annotate | Download | only in bnu
      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