/*-
 * customs.h --
 *	Header for the customs agent.
 *
 * Copyright (c) 1988, 1989 by the Regents of the University of California
 * Copyright (c) 1988, 1989 by Adam de Boor
 * Copyright (c) 1989 by Berkeley Softworks
 *
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any non-commercial purpose
 * and without fee is hereby granted, provided that the above copyright
 * notice appears in all copies.  The University of California,
 * Berkeley Softworks and Adam de Boor make no representations about
 * the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 *	"$Id: customs.h,v 1.55 1996/08/18 15:27:16 stolcke Exp $ ICSI (Berkeley)"
 */
#ifndef _CUSTOMS_H_
#define _CUSTOMS_H_

/*
 * First comes stuff needed by both the client and the server...
 */
#include    <sys/types.h>
#ifndef SOCK_STREAM /* ultrix doesn't guard against multiple inclusion ... */
#include    <sys/socket.h>
#endif
#include    <sys/param.h>
#include    <netinet/in.h>
#include    <arpa/inet.h>
#include    <sys/time.h>
#ifdef hpux
# define _KERNEL
# include    <sys/resource.h>
# undef _KERNEL
# define FSIZE_SCALE 512
#else
# ifndef RLIM_INFINITY /* see above ... */
# include    <sys/resource.h>
# endif
#endif
#ifdef sgi
# include    <sys/schedctl.h>
#endif

#ifndef INADDR_LOOPBACK
#define	INADDR_LOOPBACK		(u_long)0x7f000001	/* in host order */
#endif /* INADDR_LOOPBACK */

#ifndef RLIM_INFINITY
#define	RLIM_INFINITY	0x7fffffff
#endif /* RLIM_INFINITY */

#include    "config.h"		/* for default timeouts and ports */

#include    "rpc.h"
#include    "lst.h"

#define MACHINE_NAME_SIZE   	64  	    	/* Longest machine name */
#define MAX_INFO_SIZE	    	MAX_DATA_SIZE	/* Most data returned by
						 * CUSTOMS_INFO call */
#define MAX_NUM_GROUPS		16  	    	/* Most groups a caller
						 * can be in. Don't use
						 * NGROUP as that varies from
						 * OS to OS. */
#define MAX_NUM_RLIMITS		8		/* Should be RLIM_NLIMITS,
						 * but you never know how
						 * vendors can screw this up. */

#define CUSTOMS_PROTO_VERSION	1

typedef enum {
/* CLIENT FUNCTIONS */
    CUSTOMS_PING, 	/* See if server is up */
    CUSTOMS_HOST, 	/* Get address of host to use */
    CUSTOMS_AVAILINTV,	/* Set interval for availability check */
    CUSTOMS_SETAVAIL,	/* Set availability criteria */
    CUSTOMS_INFO, 	/* Find who's registered */
    CUSTOMS_MASTER,	/* Find address of MCA */
    CUSTOMS_LOG,  	/* Log information of rpc socket */
/* AGENT-INTERNAL FUNCTIONS */
    CUSTOMS_AVAIL,	/* Tell master if machine available */
    CUSTOMS_HOSTINT,	/* Agent-internal HOST call */
    CUSTOMS_REG,  	/* Register local machine with master */
    CUSTOMS_ALLOC,	/* Local machine allocated by master */
    CUSTOMS_CONFLICT,	/* More than one master exists */
/* ELECTION BROADCAST FUNCTIONS */
    CUSTOMS_CAMPAIGN,	/* Attempt to become master */
    CUSTOMS_NEWMASTER,	/* Declare oneself master */
/* IMPORT/TCP FUNCTIONS */
    CUSTOMS_IMPORT,	/* Import a job */
    CUSTOMS_KILL, 	/* Kill a running job with a signal */
    CUSTOMS_EXIT, 	/* RETURN CALL: status and id # of exited process */
/* DEBUG FUNCTIONS */
    CUSTOMS_ABORT,	/* Exit */
    CUSTOMS_RESTART,	/* Reexecute with same arguments */
    CUSTOMS_DEBUG,	/* Turn on debugging. */
    CUSTOMS_ELECT,  	/* Start off a new election */
    CUSTOMS_VERSION,	/* Get version number */
    CUSTOMS_JOBS,	/* Get list of imported jobs */
    CUSTOMS_STATS,	/* Get job summary statistics */
    CUSTOMS_SETSTATS,	/* Reset job statistics */
    CUSTOMS_ALLOW,	/* Add address to access list */
    CUSTOMS_DENY	/* Remore address from access list */
} Customs_Proc;

/*
 * Returned data for CUSTOMS_MASTER
 *	Because struct sockaddr_in is not portable (witness the sin_len
 *	field 4.4BSD added) we have to use or own structure.  However, it is
 *	designed to be compatible with the traditional sockaddr_in, so old
 *	customs daemons will stay happy.
 *	To handle multi-homed hosts, this and other RPC return CUSTOMS_FROMADDR
 *	in lieu of a real inet address to the caller, to indicate that it
 *	should use whatever address it has for the callee.  (The value used is
 *	compared to inet addresses, to it should be invariant with respect to
 *	host byte order.)
 */
typedef struct {
    Rpc_Short	family;
    Rpc_UShort	port;
    Rpc_ULong	addr;
#define CUSTOMS_FROMADDR	((Rpc_ULong)0xffffffff)
    char	zero[8];
} SockAddr;

/*
 * Parameter to CUSTOMS_DEBUG
 */
#define DEBUG_RPC 	1   	/* Debug rpc system */
#define DEBUG_CUSTOMS	2   	/* Debug customs itself */

/*
 * ExportPermits are what the servers use to authenticate exportation of
 * jobs. They are returned to the client from a Customs_Host().
 * CUSTOMS_FAIL may be used to see if the request succeeded. If it did not,
 * CUSTOMS_FAIL(&permit.addr) will be True.
 * Note: The value used for CUSTOMS_FAIL must be different from the one in
 * CUSTOMS_FROMADDR, since permit.addr can also return the latter.
 */
#define CUSTOMS_FAIL(inaddrPtr)	((inaddrPtr)->s_addr == htonl(INADDR_ANY))

typedef struct {
    struct in_addr	addr;	    	/* Address of host */
    Rpc_ULong    	id;	  	/* Authentication ID to give it */
} ExportPermit;


/*
 * Host_Data is what is passed to the Customs_Host() function. It contains the
 * UID under which the job will be exported (which must remain constant) and
 * a word of flags indicating criteria to use to determine which host to use,
 * as well as a list of required attributes in argv format.
 */
typedef struct {
    u_short   	  	uid;
    u_short		flags;
    char		attrs[1];   /* More bytes may follow */
} Host_Data;
#define EXPORT_ANY	0x0001	    /* Export to any sort of machine */
#define EXPORT_SAME	0x0002	    /* Export only to same sort of machine */
#define EXPORT_USELOCAL	0x0004	    /* Use local host if available */
#define EXPORT_68020	0x0008	    /* Go only to a 68020 (TEMPORARY) */
#define EXPORT_FORCE	0x0010	    /* Force export despite availability */
#define EXPORT_TEST	0x0020	    /* Test host allocation only */
#define EXPORT_EXCLUSIVE 0x0040	    /* Request exclusive machine use */

/*
 * Customs_AvailInterval() and other functions deal with BSD timeval's,
 * but we need our own definition of these that is independent of the
 * machine wordsize.
 */
typedef struct {
   Rpc_ULong	tv_sec;		    /* seconds */
   Rpc_ULong	tv_usec;	    /* micro-seconds */
} Time_Interval;

/*
 * Avail_Data is what is passed to and returned from the Customs_SetAvail()
 * function. changeMask contains a bitwise-OR of AVAIL_IDLE, AVAIL_SWAP,
 * AVAIL_LOAD and AVAIL_IMPORTS, indicating what fields of the Avail_Data
 * structure are valid. On return, changeMask indicates what fields in the
 * request were invalid. If changeMask is 0, everything was accepted.
 * The returned structure contains the current (after the change, if nothing
 * was wrong) criteria.
 * Load averages are sent as a fixed-point number. The location of the
 * decimal point is given by LOADSHIFT. Divide by LOADSCALE to get the
 * appropriate floating-point number.
 */
typedef struct {
    Rpc_Long    changeMask;	    /* Parameters to change */
    Rpc_Long    localJobs; 	    /* Are local jobs allowed ? */
    Rpc_Long    idleTime; 	    /* Idle time (in seconds) */
    Rpc_Long	idleCrit;	    /* Idle criterion (flags defined below) */
    Rpc_Long    swapPct;  	    /* Percentage of free swap space */
    Rpc_Long    loadAvg;  	    /* Maximum load average */
    Rpc_Long    imports;  	    /* Greatest number of imported processes */
    Rpc_Long    procs;  	    /* Minumum no. of free processes */
    Rpc_Long    cpuLimit; 	    /* Maximum CPU time (in seconds) */
    Rpc_Long    memLimit; 	    /* Maximum memory use (in Kbytes) */
    Rpc_Long    checkUser; 	    /* Level of user access checking */
    Rpc_Long    niceLevel; 	    /* Nice increment for imported jobs */
    Rpc_Long    evictDelay; 	    /* Grace period before eviction */
    Rpc_Long    npriLevel;	    /* Non-degrading priority (SGI) */
} Avail_Data;

#define AVAIL_IDLE	    1
#define MAX_IDLE  	    (60*60)

#define AVAIL_SWAP	    2
#define MAX_SWAP  	    40

#define LOADSHIFT   	    8
#define LOADSCALE   	    (1<<LOADSHIFT)
#define AVAIL_LOAD	    4
#define MIN_LOAD  	    ((int)(0.25*LOADSCALE))

#define AVAIL_IMPORTS	    8
#define MIN_IMPORTS	    -1		/* disable imports with -jobs -1 */

#define AVAIL_PROC	    16
#define MAX_PROC  	    20

#define AVAIL_CPU	    32
#define MIN_CPU  	    (1*60)
#define GRACE_CPU	    15		/* Grace period after CPU time expires
					   (time between SIGXCPU and abort) */
#define AVAIL_CHECK         64
#define DONT_CHECK          0		/* Be very generous (or foolish) */
#define PWD_CHECK           1		/* Check for passwd entry */
#define SHELL_CHECK         2		/* Check for authorized shell */
#define LOG_CHECK           3		/* SHELL_CHECK + log violations */
#define MAX_CHECK           LOG_CHECK

#define AVAIL_NICE	    128
#define MAX_NICE  	    20

#define AVAIL_EVICT	    256
#define MIN_EVICT  	    1

#define AVAIL_SERVER	    512		/* Server host is down */

#define MIN_CHECK           5		/* Shortest -check interval */

#define AVAIL_IDLECRIT	    1024	/* Idle criterion */
#define IDLECRIT_KBD	    0x01	/*	Keyboard/mouse */
#define IDLECRIT_USER	    0x02	/*	Console user logins */
#define IDLECRIT_LOCAL      0x04	/*      Local logins */
#define IDLECRIT_REMOTE	    0x08	/*	Remote logins */

#define AVAIL_MEMORY	    2048
#define MIN_MEMORY  	    (1*1024)	/* 1M is minimum */

#define AVAIL_NPRI	    4096

#define AVAIL_TOLOCAL	    8192	/* Machine accepts jobs from local clients */

/*
 * The next few constants are return values, some of them, and are not to
 * be passed to the agent.
 */
#define AVAIL_DOWN	    0x80000000	/* Machine is down -- this is *not* a
					   parameter */
#define AVAIL_CLOCK	    0x40000000	/* Clock out of sync -- this is *not* a
					   parameter */
#define AVAIL_VERSION	    0x20000000	/* Incompatible protocol */
#define AVAIL_EXCLUSIVE	    0x10000000	/* Someone has taken the machine for
					   exclusive use */
#define AVAIL_EVERYTHING    (~0)

/*
 * Reset default values for limits that are not supported
 */
#ifndef RLIMIT_CPU
# undef DEF_CPU_LIMIT
# define DEF_CPU_LIMIT	0
#endif
#ifndef RLIMIT_RSS
# undef DEF_MEM_LIMIT
# define DEF_MEM_LIMIT	0
#endif
#ifndef sgi
# undef DEF_NPRI_LEVEL
# define DEF_NPRI_LEVEL	0
#endif

/*
 * Signals used in eviction protocol
 */
#ifndef EVICT_NOTIFY
#define EVICT_NOTIFY        SIGUSR2	/* Signal to notify imported jobs
					   of impending eviction */
#endif
#ifndef EVICT_SIGNAL
#ifdef SIGXCPU
#define EVICT_SIGNAL        SIGXCPU	/* Signal to evict imported jobs */
#else
#define EVICT_SIGNAL        SIGTERM	/* Signal to evict imported jobs */
#endif
#endif

/*
 * The load bias is an additive correction to the OS load value
 * (returned by OS_Load) to account for instantaneous changes
 * as a result of imported jobs starting or terminating.
 * It is incremented by 1.0 * LOADSCALE when a new job starts,
 * and decremented by the same amount when a job exits.
 * The effect is that we better approximate instantaneous 
 * (as opposed to time-averaged) load averages.
 * Alternatively, it can be seen as a bias to avoid duplicate
 * allocation of the same host back-to-back (before the load created
 * by the first job can kick in), and to encourage repeated
 * allocation of the same host when a job finishes (which is generally
 * a good idea because current directories are already mounted etc.).
 *
 * To prevent the bias from permanently affecting the real load
 * it is decayed exponentially.
 * Ideally the decay constants should match those used in the kernel
 * for the 1-minute load average.
 */
#define LOADBIAS		1.0	/* increment/decrement per job */
#define LOADDECAY_TIME		10	/* seconds */
#define LOADDECAY_FACTOR	0.85

/*
 * Strings follow the WayBill in the CUSTOMS_IMPORT call arguments as
 * follows:
 *	current-working-directory
 *	file	  	    	    # command to execute
 *	number-o'-arguments 	    # on a 32-bit boundary
 *	argument strings
 *	number-o'-envariables	    # on a 32-bit boundary
 *	environment strings
 *
 * The function Customs_MakeWayBill will create an appropriate buffer...
 */
typedef struct {
    Rpc_ULong   id;	    	/* Identifier returned by the MCA */
    Rpc_Long    deadline;	/* Deadline for remote process to start */
    Rpc_UShort  port; 	    	/* UDP Port for callback when process exits */
    Rpc_Short   ruid;  	    	/* The current real user id */
    Rpc_Short   euid; 	    	/* The current effective user id */
    Rpc_Short   rgid;	    	/* The current real group id */
    Rpc_Short   egid; 	    	/* The current effective group id */
    Rpc_Short   pad;        	/* Explicit padding for all architectures */
    Rpc_Long	umask;	    	/* File creation mask */
    Rpc_Long	ngroups;	/* Number of groups */
    Rpc_Long	groups[MAX_NUM_GROUPS];
				/* Array of group ids */
    Rpc_Long	priority;	/* Process priority */
    Rpc_ULong	rlimits[2*MAX_NUM_RLIMITS];
				/* Resource limits */
				/* Portable remapping of RLIMIT_* values */
#define Customs_RlimCur(wb,index) 		((wb).rlimits[2*(index)])
#define Customs_RlimMax(wb,index) 		((wb).rlimits[2*(index)+1])
#define CUSTOMS_RLIMCPU		0		/* portable RLIMIT_CPU */
#define CUSTOMS_RLIMFSIZE	1		/* portable RLIMIT_FSIZE */
#define CUSTOMS_RLIMDATA	2		/* portable RLIMIT_DATA */
#define CUSTOMS_RLIMSTACK	3		/* portable RLIMIT_STACK */
#define CUSTOMS_RLIMCORE	4		/* portable RLIMIT_CORE */
#define CUSTOMS_RLIMRSS		5		/* portable RLIMIT_RSS */
#define CUSTOMS_RLIMNOFILE	6		/* portable RLIMIT_NOFILE */
#define CUSTOMS_RLIMVMEM	7		/* portable RLIMIT_VMEM */
#define CUSTOMS_NORLIM		((Rpc_ULong)-1)	/* portable RLIM_INFINITY */
} WayBill;

/*
 * Kill_Data is passed to the CUSTOMS_KILL procedure.
 */
typedef struct {
    Rpc_ULong	id;		/* Job ID number (from ExportPermit) */
    Rpc_Long	signal;		/* Signal number to deliver */
} Kill_Data;


/*
 * Parameters to the CUSTOMS_EXIT call
 */
typedef struct {
    Rpc_ULong	id;	   	/* ID # of exported job */
    Rpc_Long	status;		/* Exit status */
    Rpc_Long	signal;		/* Host independent signal number */
} Exit_Data;

/*
 * Host independent signal numbers
 * (mostly derived from BSD, but that's not the point).
 * Each definition here must be mirrored in the array in signal.c.
 */
#define SIGNAL_NONE	0	/* Probe for process */
#define	SIGNAL_HUP	1	/* hangup */
#define	SIGNAL_INT	2	/* interrupt */
#define	SIGNAL_QUIT	3	/* quit */
#define	SIGNAL_ILL	4	/* illegal instruction */
#define	SIGNAL_TRAP	5	/* trace trap */
#define	SIGNAL_IOT	6	/* IOT instruction */
#define	SIGNAL_EMT	7	/* EMT instruction */
#define	SIGNAL_FPE	8	/* floating point exception */
#define	SIGNAL_KILL	9	/* kill (cannot be caught or ignored) */
#define	SIGNAL_BUS	10	/* bus error */
#define	SIGNAL_SEGV	11	/* segmentation violation */
#define	SIGNAL_SYS	12	/* bad argument to system call */
#define	SIGNAL_PIPE	13	/* write on a pipe with no one to read it */
#define	SIGNAL_ALRM	14	/* alarm clock */
#define	SIGNAL_TERM	15	/* software termination signal from kill */
#define	SIGNAL_URG	16	/* urgent condition on IO channel */
#define	SIGNAL_STOP	17	/* sendable stop signal not from tty */
#define	SIGNAL_TSTP	18	/* stop signal from tty */
#define	SIGNAL_CONT	19	/* continue a stopped process */
#define	SIGNAL_CHLD	20	/* to parent on child stop or exit */
#define	SIGNAL_TTIN	21	/* to readers pgrp upon background tty read */
#define	SIGNAL_TTOU	22	/* like TTIN for output with LTOSTOP flag */
#define	SIGNAL_IO	23	/* input/output possible signal */
#define	SIGNAL_XCPU	24	/* exceeded CPU time limit */
#define	SIGNAL_XFSZ	25	/* exceeded file size limit */
#define	SIGNAL_VTALRM	26	/* virtual time alarm */
#define	SIGNAL_PROF	27	/* profiling time alarm */
#define	SIGNAL_WINCH	28	/* window changed */
#define	SIGNAL_LOST	29	/* resource lost (eg, record-lock lost) */
#define	SIGNAL_USR1	30	/* user defined signal 1 */
#define	SIGNAL_USR2	31	/* user defined signal 2 */
#define SIGNAL_INVAL	32	/* Undefined on this system */

/*
 * Signal name/number mapping
 */
int	    Signal_ToHost();
int	    Signal_FromHost();
char	    *Signal_ToName();
int	    Signal_FromName();

/*
 * Return values for the CUSTOMS_VERSION call
 */
typedef struct {
    short	majorversion;	/* Major version number */
    short	minorversion;	/* Minor version number */
    short	patchlevel;	/* Patchlevel */
    short	buildno;	/* # of build generating this binary */
    char	builddate[30];	/* String returned by date(1) */
    char	builder[8+1+64];/* login@hostname */
} Version_Data;

/*
 * Data returned by the CUSTOMS_JOBS call
 */
#define MAX_CMD_LEN	(10 * sizeof(Rpc_Long))
typedef struct {
    Rpc_Long	pid;		/* Process (group) id */
    Rpc_ULong	id;		/* Job identifier */
    Rpc_ULong	time;		/* Run time of job */
    Rpc_Short	uid;		/* User id (redundant by id, but convenient */
    Rpc_UShort	from_port;	/* Port and ... */
    Rpc_Long	from_addr;	/* ... address job came from */
    char	command[MAX_CMD_LEN];
				/* Command executed */
} Job_Info;
    
/*
 * Data returned by the CUSTOMS_STATS call
 */
typedef struct {
    Rpc_Long	start;		/* Start time */
    Rpc_Long	jobs;		/* Total number of jobs */
    Rpc_Long	evictions;	/* Total number of evictions */
    Rpc_Long	signals;	/* Number of signals delivered */
    Rpc_Long	realTime;	/* Accumulated real time for jobs */
    Rpc_Long	userTime;	/* Accumulated user time for jobs */
    Rpc_Long	sysTime;	/* Accumulated system time for jobs */
    Rpc_Long	avail;		/* How often host was available */
    Rpc_Long	availChecks;	/* Total number of avail checks */
} Job_Stats;
    
/*
 * This is the time within which the daemon is "guaranteed" to respond.
 */
#ifndef CUSTOMS_RETRY
#define CUSTOMS_RETRY	2
#endif
#ifndef CUSTOMS_URETRY
#define CUSTOMS_URETRY	500000
#endif
#ifndef CUSTOMS_NRETRY
#define CUSTOMS_NRETRY	2
#endif

/*
 * Timeout for CUSTOMS_IMPORT call (in secs)
 */
#ifndef CUSTOMS_TIMEOUT
#define CUSTOMS_TIMEOUT	10	/* should be plenty for unloaded machines */
#endif

#define Customs_Align(ptr, type)    (type) (((unsigned long)(ptr) + \
						(sizeof(Rpc_Long)-1)) & \
						~(sizeof(Rpc_Long)-1))

/*
 * Name under which to look up customs service ports
 */
#ifndef CUSTOMS_SERVICE_NAME
#define CUSTOMS_SERVICE_NAME	"customs"
#endif

/*
 * Default ports if yellow pages f***s us over
 */
#ifndef DEF_CUSTOMS_UDP_PORT
#define DEF_CUSTOMS_UDP_PORT	8231
#endif
#ifndef DEF_CUSTOMS_TCP_PORT
#define DEF_CUSTOMS_TCP_PORT	8231
#endif

/*
 * Rpc front-ends
 */
Rpc_Stat    Customs_Host(),
	    Customs_HostAttr(),
	    Customs_Ping(),
	    Customs_UseLocal(),
	    Customs_SetAvail(),
	    Customs_AvailInterval(),
	    Customs_Master(),
	    Customs_MasterForHost(),
	    Customs_Info();
int	    Customs_MakeWayBill(),
	    Customs_RawExport(),
	    Customs_RawExportAttr(),
	    Customs_NormPath();
void	    Customs_Init();
short	    Customs_Port();

/*
 * Convenience functions
 */
void	    Customs_PError();
char	    *Customs_Hostname();
char	    *Customs_ErrorMessage();	/* Return string describing error */

/*
 * List to string conversion
 */
char	    *Customs_LstToArgv();
Lst	    Customs_ArgvToLst();

Boolean	    Customs_CheckAttr();

/*
 * Return codes from Customs_RawExport, for anyone interested.
 * If > -100, negation of result is Rpc_Stat code from call to local server.
 * if <= -200, -(code + 200) is Rpc_Stat for call to remote server.
 */
#define CUSTOMS_NOEXPORT    -100    	/* Couldn't export */
#define CUSTOMS_NORETURN    -101    	/* Couldn't create return socket */
#define CUSTOMS_NONAME	    -102    	/* Couldn't fetch socket name */
#define CUSTOMS_ERROR	    -104    	/* Remote export error -- message
					 * already printed */
#define CUSTOMS_NOIOSOCK    -105    	/* Couldn't create tcp I/O socket */
#define CUSTOMS_NOCWD       -106    	/* Couldn't determine current dir */

extern int  	  	    customs_Socket;	    /* RPC socket */
extern struct sockaddr_in   customs_AgentAddr;	    /* Local agent address */
extern struct timeval	    customs_RetryTimeOut;   /* Default RPC timeout */
extern Rpc_Stat	  	    customs_Status;	    /* Status of last RPC */

#endif /* _CUSTOMS_H_ */
