





























#include <stdio.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ctype.h>
#include "debug.h"
#include "except.h"
#include "trace.h"
#include "expr.h"
#include "sched.h"
#include "manager.h"
#include "clib.h"

#ifdef  AIX31
#include <time.h>
#else AIX31
#include <sys/time.h>
#endif AIX31

#include <sys/types.h>
#include <sys/resource.h>
#include "proc.h"
#include <sys/param.h>
#include <strings.h>

#define ARCHOSLEN 28

static char *_FileName_ = __FILE__;		/* Used by EXCEPT (see except.h)     */

char	*param(), *strdup();
XDR		*xdr_Init();
CONTEXT	*create_context();

extern int	Terse;
extern int	Silent;

char *CollectorHost;
char *MyName;

typedef struct procmem PROCMEM;
struct procmem {
	PROC proc;
	PROCMEM *next;
};

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif MAXHOSTNAMELEN
typedef struct {
	char hostname[MAXHOSTNAMELEN];
	PROCMEM *proclist;
} 
MACHINFO;

MACHINFO	MachineInfo[1000];
int	MachineIndex = 0;

int Long = 0;
int Prioritized = 0;
char *MatchingArch_Os = NULL;
char *MatchingUser = NULL;
char *MatchingHost = NULL;

usage()
{
	fprintf( stderr, 
		"Usage: %s [-l] [-p] [-a arch_os] [-u user] [-h hostname] name ...\n", 
			MyName );
	exit( 1 );
}

main( argc, argv )
int		argc;
char	*argv[];
{
	int			sock = -1;
	XDR			xdr, *xdrs = NULL;
	int i;
	char *arg;

	MyName = argv[0];

	for( argv++; arg = *argv; argv++ ) {
		if( arg[0] == '-' && arg[1] == 'p' ) {
			Prioritized++;
		} 
		else if( arg[0] == '-' && arg[1] == 'l' ) {
			Long++;
		} 
		else if( arg[0] == '-' && arg[1] == 'a' ) {
			arg = *(++argv);
			if( arg ) {
				MatchingArch_Os = arg;
			} else {
				usage();
			}
		} 
		else if( arg[0] == '-' && arg[1] == 'u' ) {
			arg = *(++argv);
			if( arg ) {
				MatchingUser = arg;
			} else {
				usage();
			}
		} 
		else if( arg[0] == '-' && arg[1] == 'h' ) {
			arg = *(++argv);
			if( arg ) {
				MatchingHost = arg;
			} else {
				usage();
			}
		} 
		else if( arg[0] == '-') {
			usage();
		}
	}

	config( MyName, (CONTEXT *)0 );
	init_params();
	Terse = TRUE;
	Silent = TRUE;

	/* Connect to the collector */
	if( (sock = do_connect(CollectorHost, "condor_collector",
													COLLECTOR_PORT)) < 0 ) {
		dprintf( D_ALWAYS, "Can't connect to Condor Collector\n" );
		exit( 1 );
	}
	xdrs = xdr_Init( &sock, &xdr );
	xdrs->x_op = XDR_ENCODE;

	build_list( xdrs );

	/*for (i=0; i<MachineIndex; i++)
	      printf("Host %s has jobs on it\n",MachineInfo[i].hostname);*/

	build_global_q();

	display_all();

	xdr_destroy( xdrs );
	(void) close( sock );
}

compare_hosts(host1, host2)
char *host1;
char *host2;
{
	char *dot1, *dot2;
	int len1, len2;
	int cmplen;

	dot1 = index(host1, '.');
	if(dot1)
		len1 = dot1 - host1;
	else	
		len1 = strlen(host1);
	dot2 = index(host2, '.');
	if(dot2)
		len2 = dot2 - host2;
	else
		len2 = strlen(host2);

	if( len1 != len2 )
		return (!MATCH);

	return( strncmp(host1, host2, len1) );
}

build_global_q()
{
	/* For each machine in MachineList, connect to the schedd on that machine */
	/* and get job info for it */
	int i;
	int schedSocket;
	char hostname[MAXHOSTNAMELEN];
	XDR xdr, *xdrs = NULL;

	for( i=0; i<MachineIndex ; i++ ) {
		strcpy(hostname,MachineInfo[i].hostname);
		if( MatchingHost ) {
			if( compare_hosts(MatchingHost, hostname) != MATCH )
				continue;
		}
		if( (schedSocket = do_connect( hostname, "condor_schedd", 
													SCHED_PORT)) < 0 ) {
			dprintf( D_ALWAYS, "Can't connect to schedd on %s\n", hostname);
			continue;
		}

		xdrs = xdr_Init( &schedSocket, &xdr );

		if( !Prioritized ) {
			if( !snd_int(xdrs, SEND_ALL_JOBS, TRUE) ) {
				dprintf( D_ALWAYS, 
						"Can't send SEND_ALL_JOBS command to schedd\n");
				xdr_destroy( xdrs );
				(void)close( schedSocket );
				continue;
			}
		} 
		else {
			if( !snd_int(xdrs, SEND_ALL_JOBS_PRIO, TRUE) ) {
				dprintf( D_ALWAYS, 
						"Can't send SEND_ALL_JOBS_PRIO command to schedd\n");
				xdr_destroy( xdrs );
				(void)close( schedSocket );
				continue;
			}
		}

		if (!get_all_procs( xdrs, i)) {
			dprintf(D_ALWAYS, "Couldn't get all procs for host %s\n",
				MachineInfo[i].hostname);
			xdr_destroy( xdrs );
			(void)close( schedSocket );
			continue;
		}

		xdr_destroy( xdrs );
		(void)close( schedSocket );
	}
}

/* get the proc structs from the schedd */
get_all_procs( xdrs, mach_index )
XDR *xdrs;
int mach_index;
{
	PROC proc;

	xdrs->x_op = XDR_DECODE;

	for (;;) {
		bzero(&proc,sizeof(proc));
		if( !xdr_proc( xdrs, &proc ) ) {
			dprintf( D_ALWAYS, "Couldn't get proc\n");
			return FALSE;
		}

		if (proc.id.cluster == 0 && proc.id.proc == 0) {
			break;
		}

		if (!add_proc_to_info( proc, mach_index )) {
			dprintf( D_ALWAYS, 
				"Couldn't add a proc to hostname %s\n",MachineInfo[mach_index]);
			return FALSE;
		}

	}

	if( !xdrrec_skiprecord(xdrs) ) {
		dprintf( D_ALWAYS, "xdrrec_skiprecord(xdrs) failed");
		return FALSE;
	}
	return TRUE;
}

add_proc_to_info( proc, mach_index )
PROC proc;
int mach_index;
{
	int index;
	PROCMEM *memptr;
	PROCMEM *tmpmem;
	int noMatch = TRUE;

	if( MatchingUser ) {
		if( strcmp(MatchingUser, proc.owner) != MATCH )
			return TRUE;
	}

	/* add the proc to the end of the proclist */
	tmpmem = (PROCMEM *) MALLOC( sizeof(PROCMEM) );
	if( tmpmem == NULL ) {
		EXCEPT("Couldn't MALLOC a PROCMEM\n");
		return FALSE;
	}

	memptr = MachineInfo[mach_index].proclist;

	tmpmem->next = NULL;
	bcopy( &proc, &tmpmem->proc, sizeof(PROC) );

	if( memptr == NULL ) {
		MachineInfo[mach_index].proclist = tmpmem;
	} 
	else {
		for( ; memptr->next != NULL ; memptr = memptr->next )
			;
		memptr->next = tmpmem;
	}

	return TRUE;
}

build_list( xdrs )
XDR		*xdrs;
{
	int			i;
	int			cmd;
	STATUS_LINE	*line;

	cmd = GIVE_STATUS_LINES;
	ASSERT( xdr_int(xdrs, &cmd) );
	ASSERT( xdrrec_endofrecord(xdrs,TRUE) );

	xdrs->x_op = XDR_DECODE;

	for(;;) {
		line = (STATUS_LINE *)CALLOC( 1, sizeof(STATUS_LINE) );
		if( !xdr_status_line( xdrs, line ) ) {
			EXCEPT( "Can't read status line from Condor Collector" );
		}
		if( line->name == NULL || line->name[0] == '\0' ) {
			break;
		}
		if( line->tot != 0 ) {
			strcpy(MachineInfo[ MachineIndex++ ].hostname,line->name);
		}
	}
}

init_params()
{
	if( (CollectorHost = param("COLLECTOR_HOST")) == NULL ) {
		EXCEPT( "COLLECTOR_HOST not specified in config file\n" );
	}
}


SetSyscalls(){
}

display_all()
{
	int i;
	PROCMEM *procmem;
	char *hostname;

	/*printf("%4d.%-3d %-8s %2d/%-2d %02d:%02d %s %-2c %-3d %-4.1f %-17s %-7s\n"*/


	for( i=0 ; i<MachineIndex ; i++) {
		/* Check for case where jobs have been removed from a machine */
		/* before the collector has been notified. */
		if( MachineInfo[i].proclist == NULL)
			continue;
		hostname = MachineInfo[i].hostname;
		for ( procmem = MachineInfo[i].proclist; procmem != NULL ; 
												 procmem = procmem->next ) {
			if( Long )
				display_proc_long( &procmem->proc );
			else {
				if( globalq_display_proc_short( &procmem->proc, hostname ) ) {
					hostname = NULL;
				}
			}
		}
	}
}

/*
 ** This routine taken from library.  Modified to include the arch_os.
 */
globalq_display_proc_short( proc, hostname )
PROC	*proc;
char *hostname;
{
    char		activity;
    struct tm	*tm, *localtime();
    char		*format_time();
    char		cmd[23];
    int			len;
    char		*src, *dst;
    char *arch;
    char *os;
    char arch_os[ARCHOSLEN];
    char *parse_name();

    switch( proc->status ) {
    case UNEXPANDED:
		activity = 'U';
		break;
    case IDLE:
		activity = 'I';
		break;
    case RUNNING:
		activity = 'R';
		break;
    case COMPLETED:
		activity = 'C';
		break;
    case REMOVED:
		activity = 'X';
		break;
    default:
		activity = ' ';
    }
    
    tm = localtime( (time_t *)&proc->q_date );
    
    /* put as much of the cmd and program args as will fit in 7 spaces */
	len = 7;
	src = proc->cmd;
	dst = cmd;
	while( len && *src ) {
		*dst++ = *src++;
		len -= 1;
	}
	if( len > 0 ) {
		*dst++ = ' ';
		len -= 1;
	}
	src = proc->args;
	while( len && *src ) {
		*dst++ = *src++;
		len -= 1;
	}
	*dst = '\0';

	/* trunc the owner's login down to 8 spaces */
	if( strlen(proc->owner) > 8 )
		proc->owner[8]= '\0';

	arch = parse_name( "Arch", proc->requirements );
	if( arch == NULL ) {
		printf("Couldn't parse_name \"Arch\"\n");
		return (FALSE);
	}

	os = parse_name( "OpSys", proc->requirements );
	if( os == NULL ) {
		printf("Couldn't parse_name \"OpSys\"\n");
		return (FALSE);
	}

	sprintf( arch_os, "%s_%s", arch, os);

	if( MatchingArch_Os ) {
		if( strcmp( MatchingArch_Os, arch_os ) != MATCH ) {
			return (FALSE);
		}
	}

	if( hostname ) {
		printf("Hostname: %s\n", hostname);
		printf( "%-7s %-8s %-11s %-12s %-2s %-3s %-4s %-17s %-7s\n",
		"   ID", " OWNER", "  SUBMITTED", "   CPU_USAGE",
		" ST", "PRI", "SIZE", "ARCH_OS", "COMMAND" );
	}

	printf("%4d.%-3d %-8s %2d/%-2d %02d:%02d %s %-2c %-3d %-4.1f %-17s %-7s\n", 
		proc->id.cluster, proc->id.proc, proc->owner,
		tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, 
		/* format_time(proc->cpu_time), */ 
		format_time((float)proc->remote_usage.ru_utime.tv_sec), 
		activity, proc->prio, proc->image_size/1024.0, arch_os, cmd);

	return (TRUE);
}

char *
parse_name( name, requirements )
char *name;
char *requirements;
{
	char line[1024];
	CONTEXT *proc_context;
	EXPR *name_expr;
	int i;
	EXPR *search_expr();

	proc_context = create_context();

	sprintf(line, "PROC_REQUIREMENTS = (%s)", requirements);    
	store_stmt( scan(line), proc_context );

	name_expr = search_expr("PROC_REQUIREMENTS", proc_context, (CONTEXT *)0);
	if( name_expr == NULL ) {
		printf("parse_name: couldn't find name_expr\n");
		return NULL;
	}

	for( i=0 ; i<name_expr->len; i++) {
		if( name_expr->data[i]->type == NAME ) {
			if( strcmp(name, name_expr->data[i]->s_val) == MATCH) {
				return(strdup(name_expr->data[i+1]->s_val));
			}
		}
	}

	free_context(proc_context);
	return NULL;
}
