/* * OpenPBS (Portable Batch System) v2.3 Software License * * Copyright (c) 1999-2000 Veridian Information Solutions, Inc. * All rights reserved. * * --------------------------------------------------------------------------- * For a license to use or redistribute the OpenPBS software under conditions * other than those described below, or to purchase support for this software, * please contact Veridian Systems, PBS Products Department ("Licensor") at: * * www.OpenPBS.org +1 650 967-4675 sales@OpenPBS.org * 877 902-4PBS (US toll-free) * --------------------------------------------------------------------------- * * This license covers use of the OpenPBS v2.3 software (the "Software") at * your site or location, and, for certain users, redistribution of the * Software to other sites and locations. Use and redistribution of * OpenPBS v2.3 in source and binary forms, with or without modification, * are permitted provided that all of the following conditions are met. * After December 31, 2001, only conditions 3-6 must be met: * * 1. Commercial and/or non-commercial use of the Software is permitted * provided a current software registration is on file at www.OpenPBS.org. * If use of this software contributes to a publication, product, or * service, proper attribution must be given; see www.OpenPBS.org/credit.html * * 2. Redistribution in any form is only permitted for non-commercial, * non-profit purposes. There can be no charge for the Software or any * software incorporating the Software. Further, there can be no * expectation of revenue generated as a consequence of redistributing * the Software. * * 3. Any Redistribution of source code must retain the above copyright notice * and the acknowledgment contained in paragraph 6, this list of conditions * and the disclaimer contained in paragraph 7. * * 4. Any Redistribution in binary form must reproduce the above copyright * notice and the acknowledgment contained in paragraph 6, this list of * conditions and the disclaimer contained in paragraph 7 in the * documentation and/or other materials provided with the distribution. * * 5. Redistributions in any form must be accompanied by information on how to * obtain complete source code for the OpenPBS software and any * modifications and/or additions to the OpenPBS software. The source code * must either be included in the distribution or be available for no more * than the cost of distribution plus a nominal fee, and all modifications * and additions to the Software must be freely redistributable by any party * (including Licensor) without restriction. * * 6. All advertising materials mentioning features or use of the Software must * display the following acknowledgment: * * "This product includes software developed by NASA Ames Research Center, * Lawrence Livermore National Laboratory, and Veridian Information * Solutions, Inc. * Visit www.OpenPBS.org for OpenPBS software support, * products, and information." * * 7. DISCLAIMER OF WARRANTY * * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT * ARE EXPRESSLY DISCLAIMED. * * IN NO EVENT SHALL VERIDIAN CORPORATION, ITS AFFILIATED COMPANIES, OR THE * U.S. GOVERNMENT OR ANY OF ITS AGENCIES BE LIABLE FOR ANY DIRECT OR INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This license will be governed by the laws of the Commonwealth of Virginia, * without reference to its choice of law rules. */ #include /* the master config generated by configure */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "portability.h" #include "pbs_error.h" #include "log.h" #include "list_link.h" #include "server_limits.h" #include "attribute.h" #include "resource.h" #include "pbs_job.h" #include "log.h" #include "mom_mach.h" #include "mom_func.h" #include "resmon.h" #include "../rm_dep.h" static char ident[] = "@(#) c90/$RCSfile$ $Revision$"; #ifndef max #define max(a,b) (a>b ? a : b) #endif #ifndef TRUE #define FALSE 0 #define TRUE 1 #endif /* TRUE */ /* ** System dependent code to gather information for the resource ** monitor for a Cray c90 machine. ** ** Resources known by this code: ** cput cpu time for a pid or session ** mem memory size for a pid or session in KB ** sessions list of sessions in the system ** pids list of pids in a session ** nsessions number of sessions in the system ** nusers number of users in the system ** totmem total memory size in KB ** availmem available memory size in KB ** ncpus number of cpus ** physmem physical memory size in KB ** size size of a file or filesystem in KB ** idletime seconds of idle time ** quota quota information ** srfs_reserve set srfs reservation ** loadave current load average ** swaprate swap activity in chars / sec ** swapinrate swapin activity in chars / sec ** swapoutrate swapout activity in chars / sec ** swapused chars swapped out in KB ** swapavail KB available in swap area ** swaptotal total KB in swap area ** cpusysw percent cpu system wait ** cpuunix percent cpu unicos ** cpuuser percent cpu user ** cpuidle percent cpu idle ** cpuguest percent cpu guest */ #if SRFS #include dev_t srfs_tmp_dev = -1; dev_t srfs_big_dev = -1; dev_t srfs_fast_dev = -1; extern int ignmem; extern int ignvmem; extern int igncput; static char **v_name = NULL; static char **v_value = NULL; void var_init(void) { char *id = "var_init"; char *var_conf = "/etc/tmpdir.conf"; char line[200], *cp; int len, i; FILE *fil; if (v_name == NULL) { v_name = (char **)calloc(10, sizeof(char *)); v_value = (char **)calloc(10, sizeof(char *)); } if ((fil = fopen(var_conf, "r")) == NULL) { log_err(errno, id, var_conf); return; } for (i = 0; fgets(line, sizeof(line), fil);) { if (line[0] == '#') continue; len = strlen(line); if (line[len-1] == '\n') line[--len] = '\0'; for (cp = line; *cp; cp++) { if (isspace(*cp)) break; } if (*cp) *cp++ = '\0'; for (; *cp; cp++) { if (!isspace(*cp)) break; } if (*cp == '\0') cp = JTMPDIR; DBPRT(("%s: var(%d) $%s = %s\n", id, i, line, cp)) v_name = realloc(v_name, (i + 2) * sizeof(char *)); v_value = realloc(v_value, (i + 2) * sizeof(char *)); v_name[i] = strdup(line); v_value[i++] = strdup(cp); } v_name[i] = NULL; v_value[i] = NULL; fclose(fil); return; } void var_cleanup(void) { register i; if (v_name == NULL) return; for (i = 0; v_name[i]; i++) { free(v_name[i]); free(v_value[i]); } return; } char * var_value(char *name) { register i; for (i = 0; v_name[i]; i++) { if (strcmp(v_name[i], name) == 0) break; } return v_value[i]; } #endif /* SRFS */ static struct sess *session_table; static long session_table_size; static struct proc *process_table; static long process_table_size; extern time_t time_now; extern char *path_checkpoint; /* ** external functions and data */ extern struct config *search(struct config *, char *); extern struct rm_attribute *momgetattr(char *); extern int rm_errno; extern unsigned int reqnum; extern char *ret_string; extern double cputfactor; extern double wallfactor; extern long system_ncpus; extern int ignwalltime; extern int igncput; /* ** local functions and data */ static char *ncpus(struct rm_attribute *attrib); static char *totmem(struct rm_attribute *attrib); static char *availmem(struct rm_attribute *attrib); static char *physmem(struct rm_attribute *attrib); static char *quota(struct rm_attribute *attrib); static char *srfs_reserve(struct rm_attribute *attrib); static char *swaprate(struct rm_attribute *attrib); static char *swapinrate(struct rm_attribute *attrib); static char *swapoutrate(struct rm_attribute *attrib); static char *swapused(struct rm_attribute *attrib); static char *swapavail(struct rm_attribute *attrib); static char *swaptotal(struct rm_attribute *attrib); static char *cpuidle(struct rm_attribute *attrib); static char *cpuguest(struct rm_attribute *attrib); static char *cpuuser(struct rm_attribute *attrib); static char *cpuunix(struct rm_attribute *attrib); static char *cpusysw(struct rm_attribute *attrib); extern char *loadave(struct rm_attribute *attrib); extern char *nullproc(struct rm_attribute *attrib); extern char extra_parm[]; extern char no_parm[]; char no_srfs[] = "SRFS request not supported"; char procfs[] = "/proc"; #define FILTER 0.75 #define SAMPLE_DELTA 10 struct target tinfo; struct sysinfo sysinfo; double swap_rate; double swapin_rate; double swapout_rate; double cpu_sysw; double cpu_unix; double cpu_user; double cpu_idle; double cpu_guest; time_t wait_time; long last_time = 0; /* ** local resource array */ struct config dependent_config[] = { { "ncpus", {ncpus} }, { "totmem", {totmem} }, { "availmem", {availmem} }, { "physmem", {physmem} }, { "loadave", {loadave} }, { "quota", {quota} }, { "srfs_reserve", {srfs_reserve} }, { "swaprate", {swaprate} }, { "swapinrate", {swapinrate} }, { "swapoutrate", {swapoutrate} }, { "swapused", {swapused} }, { "swapavail", {swapavail} }, { "swaptotal", {swaptotal} }, { "cpuidle", {cpuidle} }, { "cpuguest", {cpuguest} }, { "cpuuser", {cpuuser} }, { "cpuunix", {cpuunix} }, { "cpusysw", {cpusysw} }, { NULL, {nullproc} }, }; /* * This routine is called on each cycle of the main loop. */ void dep_main_loop_cycle(void) { char *id = "dep_main_loop_cycle"; long now, delta; struct tbs info; struct pw pw; int nidlt, nuset, nunit, nguet, nsyst, i, newsios; double idlt, uset, unit, guet, syst, timec, srate; static int oidlt = 0; static int ouset = 0; static int ounit = 0; static int oguet = 0; static int osyst = 0; static int oldsios = 0; static int oldswapin = 0; static int oldswapout = 0; now = rtclock(); delta = now - last_time; if (delta <= SAMPLE_DELTA*tinfo.mc_clktck) { wait_time = (int)((SAMPLE_DELTA * tinfo.mc_clktck - delta) / tinfo.mc_clktck); return; } DBPRT(("%s: delta is %.3f\n", id, (double)delta / (double)tinfo.mc_clktck)) wait_time = SAMPLE_DELTA; if (tabinfo(PWS, &info) == -1) { log_err(errno, id, "tabinfo(PWS)"); return; } if (tabread(PWS, (char *)&pw, info.ent * info.len, info.head) == -1) { log_err(errno, id, "tabread(PWS)"); return; } if (tabinfo(SINFO, &info) == -1) { log_err(errno, id, "tabinfo(SINFO)"); return; } if (tabread(SINFO, (char *)&sysinfo, info.ent * info.len, info.head) == -1) { log_err(errno, id, "tabread(SINFO)"); return; } last_time = now; /* User, sys and idle time calc */ nidlt = 0; nuset = 0; nunit = 0; nguet = 0; nsyst = 0; for (i = 0; i < MAXCPUS; i++) { nidlt += pw.pws[i].pw_idlec; nuset += pw.pws[i].pw_userc; nunit += pw.pws[i].pw_unixc; nguet += pw.pws[i].pw_guestc; nsyst += pw.pws[i].pw_syswc; } idlt = (double)(nidlt - oidlt); uset = (double)(nuset - ouset); unit = (double)(nunit - ounit); guet = (double)(nguet - oguet); syst = (double)(nsyst - osyst); timec = idlt + uset + unit + guet + syst; if (timec <= 0.0) { sprintf(log_buffer, "bad time counter %.2f", timec); log_err(-1, id, log_buffer); return; } idlt = (idlt * 100.0) / timec; uset = (uset * 100.0) / timec; unit = (unit * 100.0) / timec; guet = (guet * 100.0) / timec; syst = (syst * 100.0) / timec; oidlt = nidlt; ouset = nuset; ounit = nunit; oguet = nguet; osyst = nsyst; cpu_sysw = FILTER * syst + (1 - FILTER) * cpu_sysw; DBPRT(("%s: syst %.2f cpu_sysw %.2f\n", id, syst, cpu_sysw)) cpu_unix = FILTER * unit + (1 - FILTER) * cpu_unix; DBPRT(("%s: unit %.2f cpu_unix %.2f\n", id, unit, cpu_unix)) cpu_user = FILTER * uset + (1 - FILTER) * cpu_user; DBPRT(("%s: uset %.2f cpu_user %.2f\n", id, uset, cpu_user)) cpu_idle = FILTER * idlt + (1 - FILTER) * cpu_idle; DBPRT(("%s: idlt %.2f cpu_idle %.2f\n", id, idlt, cpu_idle)) cpu_guest = FILTER * guet + (1 - FILTER) * cpu_guest; DBPRT(("%s: guet %.2f cpu_guest %.2f\n", id, guet, cpu_guest)) srate = (double)((sysinfo.bswapin - oldswapin) * tinfo.mc_clktck) / (double)delta; srate *= (double)BSIZE; swapin_rate = FILTER * srate + (1 - FILTER) * swapin_rate; DBPRT(("%s: swapin %d srate %.2f swapin_rate %.2f\n", id, sysinfo.bswapin - oldswapin, srate, swapin_rate)) oldswapin = sysinfo.bswapin; srate = (double)((sysinfo.bswapout - oldswapout) * tinfo.mc_clktck) / (double)delta; srate *= (double)BSIZE; swapout_rate = FILTER * srate + (1 - FILTER) * swapout_rate; DBPRT(("%s: swapout %d srate %.2f swapout_rate %.2f\n", id, sysinfo.bswapout - oldswapout, srate, swapout_rate)) oldswapout = sysinfo.bswapout; newsios = sysinfo.bswapin + sysinfo.bswapout; srate = (double)((newsios - oldsios) * tinfo.mc_clktck) / (double)delta; srate *= (double)BSIZE; swap_rate = FILTER * srate + (1 - FILTER) * swap_rate; DBPRT(("%s: sios %d srate %.2f swap_rate %.2f\n", id, newsios - oldsios, srate, swap_rate)) oldsios = newsios; } void dep_initialize(void) { char *id = "dep_initialize"; limit(C_PROC, 0, L_CPU, 0); /* set unlimited cpu */ if (target(MC_GET_TARGET, &tinfo) == -1) { log_err(errno, id, "target"); die(0); } DBPRT(("Primary machine type name = %s\n", &tinfo.mc_pmt)) DBPRT(("Number of memory banks = %ld\n", tinfo.mc_bank)) DBPRT(("Number of started processors = %ld\n", tinfo.mc_ncpu)) DBPRT(("Instruction Buffer Size (words) = %ld\n", tinfo.mc_ibsz)) DBPRT(("Main memory size (words) = %ld\n", tinfo.mc_msz)) DBPRT(("Number of clocks for a memory read = %ld\n", tinfo.mc_mspd)) DBPRT(("Clock period in picoseconds = %ld\n", tinfo.mc_clk)) DBPRT(("Number of cluster register sets = %ld\n", tinfo.mc_ncl)) DBPRT(("Memory bank busy time in clocks = %ld\n", tinfo.mc_bbsy)) DBPRT(("Number of clock ticks per second = %ld\n", tinfo.mc_clktck)) DBPRT(("System serial number = %ld\n", tinfo.mc_serial)) DBPRT(("UNICOS release level = %ld\n", tinfo.mc_rls)) #if SRFS var_init(); #endif dep_main_loop_cycle(); } void dep_cleanup(void) { char *id = "dep_cleanup"; int i; log_record(PBSEVENT_SYSTEM, 0, id, "dependent cleanup"); #if SRFS var_cleanup(); #endif } /* * Internal size decoding routine. * * Accepts a resource pointer and a pointer to the unsigned long integer * to receive the decoded value. It returns a PBS error code, and the * decoded value in the unsigned long integer. * * For Unicos, * * sizeof(word) = sizeof(int) */ static int getsize(resource *pres, unsigned long *ret) { unsigned long value; if (pres->rs_value.at_type != ATR_TYPE_SIZE) return (PBSE_ATTRTYPE); value = pres->rs_value.at_val.at_size.atsv_num; if (pres->rs_value.at_val.at_size.atsv_units == ATR_SV_WORDSZ) { if (value > ULONG_MAX / sizeof(int)) return (PBSE_BADATVAL); value *= sizeof(int); } if (value > ULONG_MAX >> pres->rs_value.at_val.at_size.atsv_shift) return (PBSE_BADATVAL); *ret = value << pres->rs_value.at_val.at_size.atsv_shift; return (PBSE_NONE); } /* * Internal time decoding routine. * * Accepts a resource pointer and a pointer to the unsigned long integer * to receive the decoded value. It returns a PBS error code, and the * decoded value of time in seconds in the unsigned long integer. */ static int gettime(resource *pres, unsigned long *ret) { if (pres->rs_value.at_type != ATR_TYPE_LONG) return (PBSE_ATTRTYPE); if (pres->rs_value.at_val.at_long < 0) return (PBSE_BADATVAL); *ret = pres->rs_value.at_val.at_long; return (PBSE_NONE); } /* * Internal long decoding routine. * * Accepts a resource pointer and a pointer to a long integer * to receive the decoded value. It returns a PBS error code, and the * decoded value of number in the long integer. */ static int getlong(resource *pres, long *ret) { if (pres->rs_value.at_type != ATR_TYPE_LONG) return (PBSE_ATTRTYPE); if (pres->rs_value.at_val.at_long < 0) return (PBSE_BADATVAL); *ret = pres->rs_value.at_val.at_long; return (PBSE_NONE); } /* * Internal boolean decoding routine. * * Accepts a resource pointer and a pointer to the unsigned integer * to receive the decoded value. It returns a PBS error code, and the * decoded value of true (1) or false (0). */ static int getbool(resource *pres, unsigned int *ret) { unsigned int val; if (pres->rs_value.at_type != ATR_TYPE_LONG) return (PBSE_ATTRTYPE); val = pres->rs_value.at_val.at_long; if (val != 0 && val != 1) return (PBSE_BADATVAL); *ret = val; return (PBSE_NONE); } static int injob(pjob, sesid) job *pjob; pid_t sesid; { task *ptask; for (ptask = (task *)GET_NEXT(pjob->ji_tasks); ptask; ptask = (task *)GET_NEXT(ptask->ti_jobtask)) { if (ptask->ti_qs.ti_sid <= 1) continue; if (ptask->ti_qs.ti_sid == sesid) return TRUE; } return FALSE; } /* * Internal job cpu count decoding routine. * * Accepts a job pointer. Returns the sum of all "multi-task" * procs in a job. */ static unsigned long cpus_sum(job *pjob) { static char *id = "cpus_sum"; struct proc *pproc; int i; ulong cpus; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) cpus = 0; pproc = process_table; for (i = 0; i < process_table_size; i++, pproc++) { if (pproc->p_stat == 0) continue; if (!injob(pjob, pproc->p_pcomm.pc_sid)) continue; if (pproc->p_pcomm.pc_maxcnt <= 1) continue; cpus += pproc->p_pcomm.pc_maxcnt; DBPRT(("Session: %d, maxcnt = %d, tot = %d\n", pproc->p_pcomm.pc_sid, pproc->p_pcomm.pc_maxcnt, cpus)) } return (cpus); } /* * Internal job cpu time decoding routine. * * Accepts a job pointer. Returns the sum of all cpu time * consumed for all processes executed by the job, in seconds. */ static unsigned long cput_sum(job *pjob) { static char *id = "cput_sum"; struct sess *psess; int i; ulong cputime = 0; int nps = 0; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) psess = session_table; for (i = 0; i < session_table_size; i++, psess++) { if (!injob(pjob, psess->s_sid)) continue; nps++; cputime += (psess->s_ucputime + psess->s_scputime) / CLK_TCK; DBPRT(("Session: %d, cput = %d\n", psess->s_sid, cputime)) } if (nps == 0) pjob->ji_flags |= MOM_NO_PROC; else pjob->ji_flags &= ~MOM_NO_PROC; return ((unsigned long)((double)cputime * cputfactor)); } #define CLICKS 4096 /* * Internal job memory decoding routine. * * Accepts a job pointer. Returns the sum of all memory * consumed for all processes executed by the job, in bytes. */ static unsigned long mem_sum(job *pjob) { static char *id = "mem_sum"; struct sess *psess; int i; ulong memsize = 0; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) psess = session_table; for (i = 0; i < session_table_size; psess++, i++) { if (!injob(pjob, psess->s_sid)) continue; memsize += ((psess->s_memhiwat) * CLICKS); DBPRT(("Session: %d, mem = %d\n", psess->s_sid, memsize)) } return (memsize); } #define BLOCKS 4096 /* * Internal job file space decoding routine. * * Accepts a job pointer. Returns the sum of all file space * consumed for all processes executed by the job, in bytes. */ static long pf_sum(job *pjob) { static char *id = "pf_sum"; struct sess *psess; int i; long fsize = 0; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) psess = session_table; for (i = 0; i < session_table_size; psess++, i++) { if (!injob(pjob, psess->s_sid)) continue; fsize += ((psess->s_fsblkused) * BLOCKS); DBPRT(("Session: %d, pf = %d\n", psess->s_sid, fsize)) } return (fsize); } /* * Internal session SDS decoding routine. * * Accepts a job pointer. Returns the sum of all SDS * consumed for all processes executed by the job, in bytes. */ static unsigned long sds_sum(job *pjob) { static char *id = "sds_sum"; struct sess *psess; int i; ulong sdssize = 0; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) psess = session_table; for (i = 0; i < session_table_size; psess++, i++) { if (!injob(pjob, psess->s_sid)) continue; sdssize += ((psess->s_sdsuse) * CLICKS); DBPRT(("Session: %d, sds = %d\n", psess->s_sid, sdssize)) } return (sdssize); } #if SRFS /* * Internal session SRFS decoding routine. * * Accepts a job pointer and device num. Returns the max of all SRFS * consumed for the device for all processes executed by the session, * in bytes. */ static unsigned long srfs_sum(pjob, dev) job *pjob; dev_t dev; { static char *id = "srfs_sum"; struct sess *psess; int i; ulong srfssize; DBPRT(("%s: entered dev %d %s\n", id, dev, pjob->ji_qs.ji_jobid)) if (dev == -1) return 0; srfssize = 0; psess = session_table; for (i = 0; i < session_table_size; psess++, i++) { if (!injob(pjob, psess->s_sid)) continue; srfssize += ((psess->s_srfs[dev].hiwater) * BLOCKS); DBPRT(("Session: %d, sds = %d\n", psess->s_sid, srfssize)) } return (srfssize); } static int srfs_error(char *mes1, char *mes2) { char buf[512]; sprintf(buf, "%s (%s) errno=%d", mes1, mes2, errno); log_err(errno, mes1, mes2); return (error(buf, PBSE_RESCUNAV)); } #endif /* SRFS */ /* * Internal session procs decoding routine. * * Accepts a job pointer id. Returns the number of processes * active for the job. */ static unsigned long proc_cnt(job *pjob) { static char *id = "proc_cnt"; struct sess *psess; int i; ulong nprocs = 0; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) psess = session_table; for (i = 0; i < session_table_size; psess++, i++) { if (!injob(pjob, psess->s_sid)) continue; nprocs += psess->s_nprocs; DBPRT(("Session: %d, nprocs = %d\n", psess->s_sid, nprocs)) } return (nprocs); } /* * Internal session mpp time decoding routine. * * Accepts a session id. Returns the sum of all moo time * consumed for all processes executed by the session, in seconds. */ static unsigned long mppt_sum(job *pjob) { static char *id = "mppt_ses"; struct sess *psess; int i; ulong mpptime = 0; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) psess = session_table; for (i = 0; i < session_table_size; psess++, i++) { if (!injob(pjob, psess->s_sid)) continue; mpptime += psess->s_mpptimeused; DBPRT(("Session: %d, mppt = %d\n", psess->s_sid, mpptime)) } return (mpptime); } extern char *msg_momsetlim; /* * Internal error routine */ int error(char *string, int value) { char *message; assert(string != NULL); assert(*string != '\0'); message = pbse_to_txt(value); assert(message != NULL); assert(*message != '\0'); (void)fprintf(stderr, msg_momsetlim, string, message); (void)fflush(stderr); return (value); } /* * which_limit - set either user's limit or udb limit: * * If user's limit is a default, then use lesser of it or udb * * Else, use user's limit unless it is greater than the udb and the * the udb limit is not unlimited. This case is an error. */ static int which_limit( long rlimit, /* limit value from resource_limit */ long udblimit, /* limit for that resource from UDB */ int r_flags, /* resource entry flags (ATR_VFLAG_DEFLT) */ int zlimit, /* true if 0 in udb mean real limit of zero */ long *rtn_limit /* RETURN: the limit to set */ ) { if (r_flags & ATR_VFLAG_DEFLT) { /* User's limit is a default value, if default > UDB, use UDB */ if ((udblimit == MAXUE_LONG) || ((udblimit == 0) && (zlimit == 0)) || (rlimit < udblimit)) *rtn_limit = rlimit; else *rtn_limit = udblimit; } else { /* user specified an actual limit */ if (zlimit) { if ((udblimit != MAXUE_LONG) && (rlimit > udblimit)) return (PBSE_EXLIMIT); } else { if (((udblimit != 0) || (udblimit != MAXUE_LONG)) && (rlimit > udblimit)) return (PBSE_EXLIMIT); } *rtn_limit = rlimit; } return (0); } /* * Establish system-enforced limits for the tasks of a job. * * Run through the resource list, checking the values for all items * we recognize. * * If set_mode is SET_LIMIT_SET, then also set hard limits for the * system enforced limits (not-polled). * If anything goes wrong with the process, return a PBS error code * and print a message on standard error. A zero-length resource list * is not an error. * * If set_mode is SET_LIMIT_SET the entry conditions are: * 1. MOM has already forked, and we are called from the child. * 2. The child is still running as root. * 3. Standard error is open to the user's file. * * If set_mode is SET_LIMIT_ALTER, we are beening called to modify * existing limits. Unlike bsd based systems that use setrlimit, the * Cray limit() call can set limits for another session. Hence all * limits can be adjusted. */ int mom_set_limits( job *pjob, int set_mode /* unused here */ ) { static char *id = "mom_set_limits"; int acid; int maxcore; int maxcput; int maxfdm; int maxpcput; int maxmem; int maxmt[MAXUE_TAPETYPE]; int maxpmem; int maxpf; int maxppf; int maxsds; int maxpsds; int maxnproc; int maxmppe; int maxmppt; int maxpmppt; int maxsockbf; int niceval; int num; char *pc; char *phost; char *pname; struct udb *pudb; int sessid; int retval; attribute *pat; resource *pres; task *ptask; unsigned long value; /* place in which to build resource value */ #if SRFS int srfs_tmp = -1; int srfs_big = -1; int srfs_fast = -1; int srfs_assist = 0; extern char *fast_dir; extern char *big_dir; extern char *tmp_dir; struct srfs_req_s srfs_brk; struct fsres_s srfsinfo; log_buffer[0] = '\0'; #define SRFS_SET(fs, val) \ if (val > 0) { \ DBPRT(("%s: going to set %s to %d\n", id, fs, val)) \ if (srfs_assist) { \ if (quotactl(fs, SRFS_INFO, (caddr_t)&srfsinfo) == -1) \ return (srfs_error(fs, "SRFS_INFO")); \ num = srfsinfo.reserve + val; \ if (quotactl(fs, SRFS_RESERVE, (caddr_t)&num) == -1) \ return (srfs_error(fs, "SRFS_RESERVE")); \ } \ srfs_brk.count = val; \ if (quotactl(fs, SRFS_SBRK, (char *)&srfs_brk) == -1) \ return (srfs_error(fs, "SRFS_SBRK")); \ } #endif /* SRFS */ DBPRT(("%s: entered\n", id)) assert(pjob != NULL); assert(pjob->ji_wattr[(int)JOB_ATR_resource].at_type == ATR_TYPE_RESC); /* initialize limits to values from user's UDB */ if (set_mode == SET_LIMIT_SET) { getsysudb(); /* get the priviled (locked) udb */ } pudb = getudbuid(pjob->ji_qs.ji_un.ji_momt.ji_exuid); if (pudb == UDB_NULL) return (PBSE_BADUSER); if (set_mode == SET_LIMIT_SET) { /* can this user run batch jobs */ if (pudb->ue_permbits & PERMBITS_NOBATCH) { endudb(); return (PBSE_QACESS); } /* set Account ID: 1 - if supplied and is valid acid, */ /* or 2 - default acid from UDB */ pat = &pjob->ji_wattr[(int)JOB_ATR_account]; if (pat->at_flags & ATR_VFLAG_SET) { pname = pat->at_val.at_str; if ((acid = nam2acid(pname)) == -1) { for (pc = pname; *pc; ++pc) { if (!isdigit((int)*pc)) return (error(pname, PBSE_BADACCT)); } if (acid2nam(acid = atoi(pname)) == (char *)0) return (error(pname, PBSE_BADACCT)); } for (num = 0; num < MAXVIDS; ++num) { if (pudb->ue_acids[num] == acid) break; } if (num == MAXVIDS) return (error(pname, PBSE_BADACCT)); } else { acid = pudb->ue_acids[0]; } if (acctid(0, acid) == -1) return (error("Account", PBSE_BADACCT)); /* lock and update the UDB with the batch host/time */ if (lockudb() < 0) { log_err(udb_errno, id, "Unable to lock UDB"); } else { pudb->ue_batchtime = time_now; phost = arst_string("PBS_O_HOST", &pjob->ji_wattr[(int)JOB_ATR_variables]); if ((phost == (char *)0) || ((phost = strchr(phost, (int)'=')) == (char *)0)) log_err(-1, id, "PBS_O_HOST not set"); strncpy(pudb->ue_batchhost, phost + 1, MAXUE_HOSTNAME); pudb->ue_batchhost[MAXUE_HOSTNAME] = '\0'; if (rewriteudb(pudb) < 0) log_err(udb_errno, id, "UDB Update failed"); } } endudb(); /* * set basic limits to values from the user's UDB entry; later * we have to check for values == MAXUE_LONG, meaning unlimited, * where in the limit() call it must be changed to 0. * A click is 512 words = 4096 bytes */ maxcput = pudb->ue_jcpulim[UDBRC_BATCH]; /* seconds */ maxpcput = pudb->ue_pcpulim[UDBRC_BATCH]; /* seconds */ maxmem = pudb->ue_jmemlim[UDBRC_BATCH]; /* clicks */ maxpmem = pudb->ue_pmemlim[UDBRC_BATCH]; /* clicks */ maxpf = pudb->ue_jfilelim[UDBRC_BATCH]; /* clicks */ maxppf = pudb->ue_pfilelim[UDBRC_BATCH]; /* clicks */ maxsds = pudb->ue_jsdslim[UDBRC_BATCH]; /* clicks */ maxpsds = pudb->ue_psdslim[UDBRC_BATCH]; /* clicks */ maxnproc = pudb->ue_jproclim[UDBRC_BATCH]; maxmppe = pudb->ue_jpelimit[UDBRC_BATCH]; maxmppt = pudb->ue_jmpptime[UDBRC_BATCH]; maxpmppt = pudb->ue_pmpptime[UDBRC_BATCH]; niceval = pudb->ue_nice[UDBRC_BATCH]; maxcore = pudb->ue_pcorelim[UDBRC_BATCH]; /* clicks */ maxfdm = pudb->ue_pfdlimit[UDBRC_BATCH]; maxsockbf = pudb->ue_jsocbflim[UDBRC_BATCH]; for (num = 0; num < MAXUE_TAPETYPE; ++num) maxmt[num] = pudb->ue_jtapelim[UDBRC_BATCH][num]; pres = (resource *) GET_NEXT(pjob->ji_wattr[(int)JOB_ATR_resource].at_val.at_list); /* * Cycle through all the resource specifications, * setting limits appropriately. */ while (pres != NULL) { assert(pres->rs_defin != NULL); pname = pres->rs_defin->rs_name; assert(pname != NULL); assert(*pname != '\0'); if (strcmp(pname, "cput") == 0) { if (igncput == FALSE) { retval = gettime(pres, &value); value = (unsigned long)((double)value / cputfactor); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit(value, maxcput, pres->rs_value.at_flags, 0, &maxcput); if (retval != PBSE_NONE) return (error(pname, retval)); } } else if (strcmp(pname, "pcput") == 0) { if (igncput == FALSE) { retval = gettime(pres, &value); value = (unsigned long)((double)value / cputfactor); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit(value, maxpcput, pres->rs_value.at_flags, 0, &maxpcput); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "mem") == 0) { if (ignmem == FALSE) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit((value + 4095) / 4096, maxmem, pres->rs_value.at_flags, 0, &maxmem); if (retval != PBSE_NONE) return (error(pname, retval)); } } else if (strcmp(pname, "pmem") == 0) { if (ignmem == FALSE) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit((value + 4095) / 4096, maxpmem, pres->rs_value.at_flags, 0, &maxpmem); if (retval != PBSE_NONE) return (error(pname, retval)); } } else if (strcmp(pname, "vmem") == 0) /* ignore */ { } else if (strcmp(pname, "pvmem") == 0) /* ignore */ { } else if (strcmp(pname, "file") == 0) /* ignore */ { } else if ((strcmp(pname, "mta") == 0) || (strcmp(pname, "mtb") == 0) || (strcmp(pname, "mtc") == 0) || (strcmp(pname, "mtd") == 0) || (strcmp(pname, "mte") == 0) || (strcmp(pname, "mtf") == 0) || (strcmp(pname, "mtg") == 0) || (strcmp(pname, "mth") == 0)) { num = (int) * (pname + 2) - (int)'a'; maxmt[num] = pres->rs_value.at_val.at_long; retval = which_limit(pres->rs_value.at_val.at_long, maxmt[num], pres->rs_value.at_flags, 0, &maxmt[num]); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "pf") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit((value + 4095) / 4096, maxpf, pres->rs_value.at_flags, 0, &maxpf); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "ppf") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit((value + 4095) / 4096, maxppf, pres->rs_value.at_flags, 0, &maxppf); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "sds") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit((value + 4095) / 4096, maxsds, pres->rs_value.at_flags, 1, &maxsds); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "psds") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit((value + 4095) / 4096, maxpsds, pres->rs_value.at_flags, 1, &maxpsds); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "procs") == 0) { retval = getlong(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit(value, maxnproc, pres->rs_value.at_flags, 0, &maxnproc); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "mppe") == 0) { retval = getlong(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit(value, maxmppe, pres->rs_value.at_flags, 1, &maxmppe); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "mppt") == 0) { retval = gettime(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit(value, maxmppt, pres->rs_value.at_flags, 1, &maxmppt); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "pmppt") == 0) { retval = gettime(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); retval = which_limit(value, maxpmppt, pres->rs_value.at_flags, 1, &maxpmppt); if (retval != PBSE_NONE) return (error(pname, retval)); #if SRFS } else if (strcmp(pname, "srfs_tmp") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); value = (value + 4095) / 4096; srfs_tmp = value; } else if (strcmp(pname, "srfs_big") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); value = (value + 4095) / 4096; srfs_big = value; } else if (strcmp(pname, "srfs_fast") == 0) { retval = getsize(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); if (value > INT_MAX) return (error(pname, PBSE_BADATVAL)); value = (value + 4095) / 4096; srfs_fast = value; } else if (strcmp(pname, "srfs_assist") == 0) { retval = getbool(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); srfs_assist = value; #endif /* SRFS */ } else if (strcmp(pname, "walltime") == 0) { retval = gettime(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); } else if (strcmp(pname, "ncpus") == 0) { char hold[16]; extern struct var_table vtable; if ((int)pres->rs_value.at_val.at_long < 0) return (error(pname, PBSE_BADATVAL)); sprintf(hold, "%d", (int)pres->rs_value.at_val.at_long); bld_env_variables(&vtable, "NCPUS", hold); } else if (strcmp(pname, "nice") == 0) { if (set_mode == SET_LIMIT_SET) { niceval = (int)pres->rs_value.at_val.at_long; } } else if ((pres->rs_defin->rs_flags & ATR_DFLAG_RMOMIG) == 0) /* don't recognize and nor marked as ignore by mom */ return (error(pname, PBSE_UNKRESC)); pres = (resource *)GET_NEXT(pres->rs_link); } /* * Set the limits * * If pcput, pmem, or ppf is unlimited but the corresponding session * limit is not, use the session limit for the process limit. */ for (ptask = (task *)GET_NEXT(pjob->ji_tasks); ptask != NULL; ptask = (task *)GET_NEXT(ptask->ti_jobtask)) { sessid = ptask->ti_qs.ti_sid; if (maxcput == MAXUE_LONG) /* if unlimited */ maxcput = 0; if (limit(C_SESS, sessid, L_CPU, maxcput * CLK_TCK) < 0) return (error("cput", PBSE_SYSTEM)); if ((maxpcput == MAXUE_LONG) || (maxpcput == 0)) /* if unlimited */ { if (maxcput != 0) maxpcput = maxcput; else maxpcput = 0; } else if ((maxpcput > maxcput) && (maxcput != 0)) { maxpcput = maxcput; } if (limit(C_SESSPROCS, sessid, L_CPU, maxpcput * CLK_TCK) < 0) return (error("pcput", PBSE_SYSTEM)); if (maxmem == MAXUE_LONG) /* if unlimited */ maxmem = 0; if (limit(C_SESS, sessid, L_MEM, maxmem) < 0) return (error("mem", PBSE_SYSTEM)); if ((maxpmem == MAXUE_LONG) || (maxpmem == 0)) /* if unlimited */ { if (maxmem != 0) maxpmem = maxmem; else maxpmem = 0; } else if ((maxpmem > maxmem) && (maxmem != 0)) { maxpmem = maxmem; } if (limit(C_SESSPROCS, sessid, L_MEM, maxpmem) < 0) return (error("pmem", PBSE_SYSTEM)); if (maxpf == MAXUE_LONG) /* if unlimited */ maxpf = 0; if (limit(C_SESS, sessid, L_FSBLK, maxpf) < 0) return (error("pf", PBSE_SYSTEM)); if ((maxppf == MAXUE_LONG) || (maxppf == 0)) /* if unlimited */ { if (maxpf != 0) maxppf = maxpf; else maxppf = 0; } else if ((maxppf > maxpf) && (maxpf != 0)) { maxppf = maxpf; } if (limit(C_SESSPROCS, sessid, L_FSBLK, maxppf) < 0) return (error("ppf", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_SDS, maxsds) < 0) return (error("sds", PBSE_SYSTEM)); if (limit(C_SESSPROCS, sessid, L_SDS, maxpsds) < 0) return (error("psds", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_CPROC, maxnproc) < 0) return (error("procs", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE0, maxmt[0]) < 0) return (error("mta", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE1, maxmt[1]) < 0) return (error("mtb", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE2, maxmt[2]) < 0) return (error("mtc", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE3, maxmt[3]) < 0) return (error("mtd", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE4, maxmt[4]) < 0) return (error("mte", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE5, maxmt[5]) < 0) return (error("mtf", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE6, maxmt[6]) < 0) return (error("mtg", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_TAPE7, maxmt[7]) < 0) return (error("mth", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_MPPE, maxmppe) < 0) return (error("mppe", PBSE_SYSTEM)); if (limit(C_SESS, sessid, L_MPPT, maxmppt) < 0) return (error("mppt", PBSE_SYSTEM)); if (limit(C_SESSPROCS, sessid, L_MPPT, maxpmppt) < 0) return (error("pmppt", PBSE_SYSTEM)); if (maxcore == MAXUE_LONG) /* if unlimited */ maxcore = 0; if (limit(C_SESSPROCS, sessid, L_CORE, maxcore) < 0) return (error("core", PBSE_SYSTEM)); if (maxfdm == MAXUE_LONG) /* if unlimited */ maxfdm = 0; if (limit(C_SESSPROCS, sessid, L_FDM, maxfdm) < 0) return (error("fdm", PBSE_SYSTEM)); if (maxsockbf == MAXUE_LONG) /* if unlimited */ maxsockbf = 0; if (limit(C_SESS, sessid, L_SOCKBF, maxsockbf) < 0) return (error("sockbuf", PBSE_SYSTEM)); #if SRFS srfs_brk.id = 0; /* current job */ SRFS_SET(tmp_dir, srfs_tmp) SRFS_SET(big_dir, srfs_big) SRFS_SET(fast_dir, srfs_fast) #endif /* SRFS */ if (set_mode == SET_LIMIT_SET) { errno = 0; if ((nice(niceval) == -1) && (errno != 0)) return (error("nice", PBSE_SYSTEM)); } } return (PBSE_NONE); } /* * State whether MOM main loop has to poll this job to determine if some * limits are being exceeded. * * Sets flag TRUE if polling is necessary, FALSE otherwise. Actual * polling is done using the mom_over_limit machine-dependent function. */ int mom_do_poll(job *pjob) { static char *id = "mom_do_poll"; char *pname; resource *pres; DBPRT(("%s: entered\n", id)) assert(pjob != NULL); assert(pjob->ji_wattr[(int)JOB_ATR_resource].at_type == ATR_TYPE_RESC); pres = (resource *) GET_NEXT(pjob->ji_wattr[(int)JOB_ATR_resource].at_val.at_list); while (pres != NULL) { assert(pres->rs_defin != NULL); pname = pres->rs_defin->rs_name; assert(pname != NULL); assert(*pname != '\0'); if (strcmp(pname, "ncpus") == 0) return (TRUE); if (strcmp(pname, "walltime") == 0) return (TRUE); pres = (resource *)GET_NEXT(pres->rs_link); } return (FALSE); } /* * Setup for polling. * * Open kernel device and get namelist info. */ int mom_open_poll(void) { static char *id = "mom_open_poll"; DBPRT(("%s: entered\n", id)) #if SRFS #define SETDEV(name, var) \ if ((dir = var_value(name)) != NULL) { \ i |= chk_file_sec(dir, 1, 1, S_IWGRP|S_IWOTH, 1, NULL); \ if (quotactl(dir, SRFS_INFO, (caddr_t)&srfsinfo) == -1) \ log_err(errno, id, dir); \ else { \ var = srfsinfo.index; \ DBPRT(("%s: got %d for %s %s\n", id, var, name, dir)) \ } \ } { int i; struct fsres_s srfsinfo; char *dir, *var_value(); var_init(); i = 0; SETDEV("TMPDIR", srfs_tmp_dev) SETDEV("BIGDIR", srfs_big_dev) SETDEV("FASTDIR", srfs_fast_dev) #if !defined(DEBUG) && !defined(NO_SECURITY_CHECK) if (i) return (PBSE_PERM); #endif /* NO_SECURITY_CHECK */ } #else #if !defined(DEBUG) && !defined(NO_SECURITY_CHECK) if (chk_file_sec(TMP_DIR, 1, 1, S_IWGRP | S_IWOTH, 1, NULL)) return (PBSE_PERM); #endif /* NO_SECURITY_CHECK */ #endif /* SRFS */ return (PBSE_NONE); } /* * Declare start of polling loop. * * Until the next call to mom_get_sample, all mom_over_limit calls will * use the same data. Returns a PBS error code. */ int mom_get_sample(void) { static char *id = "mom_get_sample"; struct tbs info; struct proc *pp; struct pcomm *pc; int i, pbase; DBPRT(("%s: entered\n", id)) if (session_table != NULL) free(session_table); if (tabinfo(SESS, &info) == -1) return (PBSE_SYSTEM); session_table_size = info.ent * info.len; session_table = (struct sess*)malloc(session_table_size); if (session_table == NULL) return (PBSE_SYSTEM); if (tabread(SESS, (char *) session_table, session_table_size, info.head) == -1) return (PBSE_SYSTEM); session_table_size = info.ent; if (process_table != NULL) free(process_table); if (tabinfo(PROCTAB, &info) == -1) return (PBSE_SYSTEM); process_table_size = info.ent * info.len; process_table = (struct proc*)malloc(process_table_size); if (process_table == NULL) return (PBSE_SYSTEM); if (tabread(PROCTAB, (char *) process_table, process_table_size, info.head) == -1) return (PBSE_SYSTEM); process_table_size = info.ent; pbase = (int)info.addr; for (pp = process_table, i = 0; i < process_table_size; pp++, i++) { if (pp->p_stat == 0) continue; if ((pc = pp->p_pc) != NULL) { pp->p_pc = (struct pcomm *)((int)pc - pbase + (int)process_table); } } return (PBSE_NONE); } /* * Measure job resource usage and compare with its limits. * * If it has exceeded any well-formed polled limit return TRUE. * Otherwise, return FALSE. */ int mom_over_limit(job *pjob) { static char *id = "mom_over_limit"; char *pname; int retval; unsigned long value; resource *pres; int num; assert(pjob != NULL); assert(pjob->ji_wattr[(int)JOB_ATR_resource].at_type == ATR_TYPE_RESC); pres = (resource *) GET_NEXT(pjob->ji_wattr[(int)JOB_ATR_resource].at_val.at_list); DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) for (; pres != NULL; pres = (resource *)GET_NEXT(pres->rs_link)) { assert(pres->rs_defin != NULL); pname = pres->rs_defin->rs_name; assert(pname != NULL); assert(*pname != '\0'); if ((strcmp(pname, "ncpus") == 0) && (igncput == FALSE)) { retval = getlong(pres, &value); if (retval != PBSE_NONE) continue; if ((num = cpus_sum(pjob)) > value) { sprintf(log_buffer, "ncpus %d exceeded limit %d", num, value); return (TRUE); } } if (ignwalltime == 0 && strcmp(pname, "walltime") == 0) { if ((pjob->ji_qs.ji_svrflags & JOB_SVFLG_HERE) == 0) continue; retval = gettime(pres, &value); if (retval != PBSE_NONE) continue; num = (unsigned long)((double)(time_now - pjob->ji_qs.ji_stime) * wallfactor); if (num > value) { sprintf(log_buffer, "walltime %d exceeded limit %d", num, value); return (TRUE); } } } return (FALSE); } /* * Update the job attribute for resources used. * * The first time this is called for a job, set up resource entries for * each resource that can be reported for this machine. Fill in the * correct values. Return an error code. */ int mom_set_use(job *pjob) { static char *id = "mom_set_use"; resource *pres; attribute *at; resource_def *rd; unsigned long *ulp, unum; long *lp, num; assert(pjob != NULL); at = &pjob->ji_wattr[(int)JOB_ATR_resc_used]; assert(at->at_type == ATR_TYPE_RESC); if ((pjob->ji_qs.ji_svrflags & JOB_SVFLG_Suspend) != 0) return (PBSE_NONE); /* job suspended, don't track it */ DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) at->at_flags |= ATR_VFLAG_MODIFY; if ((at->at_flags & ATR_VFLAG_SET) == 0) { at->at_flags |= ATR_VFLAG_SET; #if SRFS rd = find_resc_def(svr_resc_def, "srfs_tmp", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_SIZE; pres->rs_value.at_val.at_size.atsv_shift = 10; /* KB */ pres->rs_value.at_val.at_size.atsv_units = ATR_SV_BYTESZ; rd = find_resc_def(svr_resc_def, "srfs_big", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_SIZE; pres->rs_value.at_val.at_size.atsv_shift = 10; /* KB */ pres->rs_value.at_val.at_size.atsv_units = ATR_SV_BYTESZ; rd = find_resc_def(svr_resc_def, "srfs_fast", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_SIZE; pres->rs_value.at_val.at_size.atsv_shift = 10; /* KB */ pres->rs_value.at_val.at_size.atsv_units = ATR_SV_BYTESZ; #endif /* SRFS */ rd = find_resc_def(svr_resc_def, "ncpus", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_LONG; rd = find_resc_def(svr_resc_def, "cput", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_LONG; rd = find_resc_def(svr_resc_def, "mem", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_SIZE; pres->rs_value.at_val.at_size.atsv_shift = 10; /* KB */ pres->rs_value.at_val.at_size.atsv_units = ATR_SV_BYTESZ; rd = find_resc_def(svr_resc_def, "pf", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_SIZE; pres->rs_value.at_val.at_size.atsv_shift = 10; /* KB */ pres->rs_value.at_val.at_size.atsv_units = ATR_SV_BYTESZ; rd = find_resc_def(svr_resc_def, "sds", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_SIZE; pres->rs_value.at_val.at_size.atsv_shift = 10; /* KB */ pres->rs_value.at_val.at_size.atsv_units = ATR_SV_BYTESZ; rd = find_resc_def(svr_resc_def, "procs", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_LONG; rd = find_resc_def(svr_resc_def, "mppt", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_LONG; rd = find_resc_def(svr_resc_def, "walltime", svr_resc_size); assert(rd != NULL); pres = add_resource_entry(at, rd); pres->rs_value.at_flags |= ATR_VFLAG_SET; pres->rs_value.at_type = ATR_TYPE_LONG; } rd = find_resc_def(svr_resc_def, "ncpus", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); lp = &pres->rs_value.at_val.at_long; num = cpus_sum(pjob); *lp = max(*lp, num); rd = find_resc_def(svr_resc_def, "cput", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); lp = &pres->rs_value.at_val.at_long; num = cput_sum(pjob); *lp = max(*lp, num); rd = find_resc_def(svr_resc_def, "mem", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); ulp = &pres->rs_value.at_val.at_size.atsv_num; unum = (mem_sum(pjob) + 1023) >> 10; /* KB */ *ulp = max(*ulp, unum); rd = find_resc_def(svr_resc_def, "pf", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); lp = (long *) & pres->rs_value.at_val.at_size.atsv_num; num = (pf_sum(pjob) + 1023) >> 10; /* KB */ *lp = max(*lp, num); rd = find_resc_def(svr_resc_def, "sds", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); ulp = &pres->rs_value.at_val.at_size.atsv_num; unum = (sds_sum(pjob) + 1023) >> 10; /* KB */ *ulp = max(*ulp, unum); #if SRFS rd = find_resc_def(svr_resc_def, "srfs_tmp", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); ulp = &pres->rs_value.at_val.at_size.atsv_num; unum = (srfs_sum(pjob, srfs_tmp_dev) + 1023) >> 10; /* KB */ *ulp = max(*ulp, unum); rd = find_resc_def(svr_resc_def, "srfs_big", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); ulp = &pres->rs_value.at_val.at_size.atsv_num; unum = (srfs_sum(pjob, srfs_big_dev) + 1023) >> 10; /* KB */ *ulp = max(*ulp, unum); rd = find_resc_def(svr_resc_def, "srfs_fast", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); ulp = &pres->rs_value.at_val.at_size.atsv_num; unum = (srfs_sum(pjob, srfs_fast_dev) + 1023) >> 10; /* KB */ *ulp = max(*ulp, unum); #endif /* SRFS */ rd = find_resc_def(svr_resc_def, "procs", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); lp = &pres->rs_value.at_val.at_long; num = proc_cnt(pjob); *lp = max(*lp, num); rd = find_resc_def(svr_resc_def, "mppt", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); lp = &pres->rs_value.at_val.at_long; num = mppt_sum(pjob); *lp = max(*lp, num); rd = find_resc_def(svr_resc_def, "walltime", svr_resc_size); assert(rd != NULL); pres = find_resc_entry(at, rd); assert(pres != NULL); pres->rs_value.at_val.at_long = (long)((double)(time_now - pjob->ji_qs.ji_stime) * wallfactor); return (PBSE_NONE); } /* * Kill a task session. * Call with the task pointer and a signal number. */ int kill_task(task *ptask, int sig, int pg) { static char *id = "kill_task"; int ct = 1; int sesid; sesid = ptask->ti_qs.ti_sid; if (sesid > 1) { if (killm(C_JOB, sesid, sig) == -1) { if (errno != ESRCH) { sprintf(log_buffer, "killm: sid=%d sig=%d", sesid, sig); log_err(errno, id, log_buffer); } else { ct = 0; sprintf(log_buffer, "killm: sid=%d sig=%d", sesid, sig); log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_JOB, ptask->ti_job->ji_qs.ji_jobid, log_buffer); } } } return ct; } /* * Clean up everything related to polling. * * In the case of the sun, close the kernal if it is open. */ int mom_close_poll(void) { static char *id = "mom_close_poll"; DBPRT(("%s: entered\n", id)) return (PBSE_NONE); } /* * mom_does_checkpoint */ int mom_does_checkpoint(void) { return (CST_MACH_DEP); } /* * Checkpoint the job. * * If abort is TRUE, kill it too. */ int mach_checkpoint(task *ptask, char *path, int abort) { int cprtn; long flags = 0; if (abort) flags = CHKPNT_KILL; cprtn = checkpoint(C_SESS, ptask->ti_qs.ti_sid, path, flags); return cprtn; } /* * Restart the job from the checkpoint file. * * Return the session/job id */ long mach_restart(task *ptask, char *path) { int sid; sid = restart(path, 0); return sid; } int getprocs(void) { static unsigned int lastproc = 0; if (lastproc == reqnum) /* don't need new proc table */ return process_table_size; if (mom_get_sample() != PBSE_NONE) return 0; lastproc = reqnum; return(process_table_size); } char * cput_job(jobid) pid_t jobid; { char *id = "cput_job"; int i, nproc; int found = 0; time_t addtime; double cputime; if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } cputime = 0.0; for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; register struct pcomm *pc; if (pp->p_stat == 0) continue; if ((pc = pp->p_pc) == NULL) continue; if (jobid != pc->pc_sid) continue; found = 1; addtime = pp->p_utime + pp->p_stime + pp->p_sctime + pc->pc_cutime + pc->pc_cstime; DBPRT(("%s: pid %d time=%d (%d + %d + %d + %d + %d)\n", id, pp->p_pid, addtime, pp->p_utime, pp->p_stime, pp->p_sctime, pc->pc_cutime, pc->pc_cstime)) cputime += (double)addtime / (double)CLK_TCK; } if (found) { sprintf(ret_string, "%.2f", cputime * cputfactor); return ret_string; } rm_errno = RM_ERR_EXIST; return NULL; } char * cput_proc(pid) pid_t pid; { char *id = "cput_pid"; int i, nproc; time_t addtime; if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; register struct pcomm *pc; if (pp->p_stat == 0) continue; if (pid != pp->p_pid) continue; if ((pc = pp->p_pc) == NULL) addtime = 0; else { addtime = pp->p_utime + pp->p_stime + pp->p_sctime + pc->pc_cutime + pc->pc_cstime; DBPRT(("%s: pid %d time=%d (%d + %d + %d + %d + %d)\n", id, pid, addtime, pp->p_utime, pp->p_stime, pp->p_sctime, pc->pc_cutime, pc->pc_cstime)) } sprintf(ret_string, "%.2f", ((double)addtime / (double)CLK_TCK) * cputfactor); return ret_string; } rm_errno = RM_ERR_EXIST; return NULL; } char * cput(struct rm_attribute *attrib) { char *id = "cput"; int value; if (attrib == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } if ((value = atoi(attrib->a_value)) == 0) { sprintf(log_buffer, "bad param: %s", attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if (momgetattr(NULL)) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (strcmp(attrib->a_qualifier, "session") == 0) return (cput_job((pid_t)value)); else if (strcmp(attrib->a_qualifier, "proc") == 0) return (cput_proc((pid_t)value)); else { rm_errno = RM_ERR_BADPARAM; return NULL; } } char * mem_job(jobid) pid_t jobid; { char *id = "mem_job"; int memsize; int i, nproc; int found = 0; if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } memsize = 0; for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; register struct pcomm *pc; if (pp->p_stat == 0) continue; if ((pc = pp->p_pc) == NULL) continue; if (jobid != pc->pc_sid) continue; found = 1; memsize += pc->pc_size; DBPRT(("%s: found pid %d size=%d total=%d\n", id, pp->p_pid, ctob(pc->pc_size), ctob(memsize))) } if (found) { sprintf(ret_string, "%ukb", ctob(memsize) >> 10); /* KB */ return ret_string; } rm_errno = RM_ERR_EXIST; return NULL; } char * mem_proc(pid) pid_t pid; { char *id = "mem_proc"; int i, nproc; if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; register struct pcomm *pc; if (pp->p_stat == 0) continue; if (pid != pp->p_pid) continue; if ((pc = pp->p_pc) == NULL) break; sprintf(ret_string, "%ukb", ctob(pc->pc_size) >> 10); /* KB */ return ret_string; } rm_errno = RM_ERR_EXIST; return NULL; } char * mem(struct rm_attribute *attrib) { char *id = "mem"; int value; if (attrib == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } if ((value = atoi(attrib->a_value)) == 0) { sprintf(log_buffer, "bad param: %s", attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if (momgetattr(NULL)) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (strcmp(attrib->a_qualifier, "session") == 0) return (mem_job((pid_t)value)); else if (strcmp(attrib->a_qualifier, "proc") == 0) return (mem_proc((pid_t)value)); else { rm_errno = RM_ERR_BADPARAM; return NULL; } } char * sessions(struct rm_attribute *attrib) { char *id = "sessions"; char *fmt; int i, j, nproc, njids = 0; pid_t *jids, *hold; static int maxjid = 300; register pid_t jobid; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } if ((jids = (pid_t *)calloc(maxjid, sizeof(pid_t))) == NULL) { log_err(errno, id, "no memory"); rm_errno = RM_ERR_SYSTEM; return NULL; } /* ** Search for members of session */ for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; if (pp->p_stat == 0) continue; if (pp->p_pc == NULL) continue; if (pp->p_pc->pc_suid == 0) continue; jobid = pp->p_pc->pc_sid; DBPRT(("%s[%d]: pid: %d sid %d\n", id, njids, pp->p_pid, jobid)) for (j = 0; j < njids; j++) { if (jids[j] == jobid) break; } if (j == njids) /* not found */ { if (njids == maxjid) /* need more space */ { maxjid += 100; hold = (pid_t *)realloc(jids, maxjid * sizeof(pid_t)); if (hold == NULL) { log_err(errno, id, "realloc"); rm_errno = RM_ERR_SYSTEM; free(jids); return NULL; } jids = hold; } jids[njids++] = jobid; /* add jobid to list */ } } fmt = ret_string; for (j = 0; j < njids; j++) { checkret(&fmt, 100); if (j == 0) sprintf(fmt, "%d", (int)jids[j]); else sprintf(fmt, " %d", (int)jids[j]); fmt += strlen(fmt); } free(jids); return ret_string; } char * nsessions(struct rm_attribute *attrib) { char *result, *ch; int num = 1; if ((result = sessions(attrib)) == NULL) return result; for (ch = result; *ch; ch++) { if (*ch == ' ') /* count blanks */ num++; } sprintf(ret_string, "%d", num); return ret_string; } char * nusers(struct rm_attribute *attrib) { char *id = "nusers"; int nproc; int i, j; int nuids = 0; uid_t *uids, uid; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } if ((uids = calloc(nproc, sizeof(uid_t))) == NULL) { log_err(errno, id, "no memory"); rm_errno = RM_ERR_SYSTEM; return NULL; } for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; if (pp->p_stat == 0) continue; if (pp->p_pc == NULL) continue; if ((uid = pp->p_pc->pc_suid) == 0) continue; DBPRT(("%s: pid %d uid %u\n", id, (int)pp->p_pid, uid)) for (j = 0; j < nuids; j++) { if (uids[j] == uid) break; } if (j == nuids) /* not found */ uids[nuids++] = uid; /* so add it to list */ } sprintf(ret_string, "%d", nuids); free(uids); return ret_string; } char * pids(struct rm_attribute *attrib) { char *id = "pids"; pid_t jobid; struct pcomm *pc; int i, nproc; char *fmt; int num_pids; if (attrib == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } if ((jobid = (pid_t)atoi(attrib->a_value)) == 0) { sprintf(log_buffer, "bad param: %s", attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if (momgetattr(NULL)) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (strcmp(attrib->a_qualifier, "session") != 0) { rm_errno = RM_ERR_BADPARAM; return NULL; } if ((nproc = getprocs()) == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } /* ** Search for members of session */ fmt = ret_string; for (i = 0; i < nproc; i++) { register struct proc *pp = &process_table[i]; if (pp->p_stat == 0) continue; if ((pc = pp->p_pc) == NULL) continue; if (jobid != pc->pc_sid) continue; sprintf(fmt, " %d", pp->p_pid); fmt += strlen(fmt); num_pids++; } if (num_pids == 0) { rm_errno = RM_ERR_EXIST; return NULL; } return ret_string; } static char * totmem(struct rm_attribute *attrib) { char *id = "totmem"; struct statfs fsbuf; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (statfs(procfs, &fsbuf, sizeof(struct statfs), 0) == -1) { log_err(errno, id, "statfs"); rm_errno = RM_ERR_SYSTEM; return NULL; } DBPRT(("%s: bsize=%d blocks=%d\n", id, fsbuf.f_bsize, fsbuf.f_blocks)) /* in KB */ sprintf(ret_string, "%ukb", (fsbuf.f_bsize * fsbuf.f_blocks) >> 10); return ret_string; } static char * availmem(struct rm_attribute *attrib) { char *id = "availmem"; struct statfs fsbuf; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (statfs(procfs, &fsbuf, sizeof(struct statfs), 0) == -1) { log_err(errno, id, "statfs"); rm_errno = RM_ERR_SYSTEM; return NULL; } DBPRT(("%s: bsize=%d bfree=%d\n", id, fsbuf.f_bsize, fsbuf.f_bfree)) /* in KB */ sprintf(ret_string, "%ukb", (fsbuf.f_bsize * fsbuf.f_bfree) >> 10); return ret_string; } static char * ncpus(struct rm_attribute *attrib) { char *id = "ncpus"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } sprintf(ret_string, "%ld", tinfo.mc_ncpu); system_ncpus = tinfo.mc_ncpu; return ret_string; } static char * physmem(struct rm_attribute *attrib) { char *id = "physmem"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } /* in KB */ sprintf(ret_string, "%lukb", (tinfo.mc_msz * sizeof(int)) >> 10); return ret_string; } char * size_fs(char *param) { char *id = "size_fs"; FILE *mf; struct mntent *mp; struct statfs fsbuf; if (param[0] != '/') { sprintf(log_buffer, "%s: not full path filesystem name: %s\n", id, param); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if (statfs(param, &fsbuf, sizeof(struct statfs), 0) == -1) { log_err(errno, id, "statfs"); rm_errno = RM_ERR_BADPARAM; return NULL; } /* in KB */ sprintf(ret_string, "%lukb", (unsigned long)((fsbuf.f_bsize * fsbuf.f_bfree) >> 10)); return ret_string; } char * size_file(char *param) { char *id = "size_file"; struct stat sbuf; if (param[0] != '/') { sprintf(log_buffer, "%s: not full path filesystem name: %s\n", id, param); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if (stat(param, &sbuf) == -1) { log_err(errno, id, "stat"); rm_errno = RM_ERR_BADPARAM; return NULL; } sprintf(ret_string, "%ukb", sbuf.st_size >> 10); /* KB */ return ret_string; } char * size(struct rm_attribute *attrib) { char *id = "size"; char *param; if (attrib == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } if (momgetattr(NULL)) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } param = attrib->a_value; if (strcmp(attrib->a_qualifier, "file") == 0) return (size_file(param)); else if (strcmp(attrib->a_qualifier, "fs") == 0) return (size_fs(param)); else { rm_errno = RM_ERR_BADPARAM; return NULL; } } time_t maxtm; void setmax(char *dev) { struct stat sb; if (stat(dev, &sb) == -1) return; if (maxtm < sb.st_atime) maxtm = sb.st_atime; return; } char * idletime(struct rm_attribute *attrib) { char *id = "idletime"; DIR *dp; struct dirent *de; char ttyname[50]; time_t curtm; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if ((dp = opendir("/dev")) == NULL) { log_err(errno, id, "opendir /dev"); rm_errno = RM_ERR_SYSTEM; return NULL; } maxtm = 0; curtm = time(NULL); while ((de = readdir(dp)) != NULL) { if (maxtm >= curtm) break; if (strncmp(de->d_name, "tty", 3)) continue; sprintf(ttyname, "/dev/%s", de->d_name); setmax(ttyname); } closedir(dp); sprintf(ret_string, "%d", MAX(0, curtm - maxtm)); return ret_string; } int quotasize(int blocks) { if (QFV_MINVALUE <= blocks && blocks <= QFV_MAXVALUE) { sprintf(ret_string, "%lukb", (BSIZE * blocks) >> 10); /* KB */ return 0; } switch (blocks) { case QFV_DEFAULT: strcpy(ret_string, "default"); return 1; case QFV_NOEVAL: strcpy(ret_string, "infinity"); break; case QFV_PREVENT: strcpy(ret_string, "prevent"); break; default: strcpy(ret_string, "unspecified"); break; } return 0; } typedef int (*ifunc)(); static char * quota(struct rm_attribute *attrib) { char *id = "quota"; time_t now; int ident; char dirname[FILENAME_MAX]; struct q_request qi; struct qf_header header; struct q_entry *qu; #if SRFS struct fsres_s srfsinfo; static unsigned int lastproc = 0; static char srfsdir[FILENAME_MAX]; #endif static char *bean_type[] = { "account", /* 0 */ "group", /* 1 */ "user" /* 2 */ }; static ifunc bean_func[] = { nam2acid, nam2gid, nam2uid }; enum bean_name { account, group, user, bean_end } bean; static char *type_array[] = { "harddata", "softdata", "currdata", "hardfile", "softfile", "currfile", "timedata", "timefile", "snap_avail", /* srfs */ "ares_avail", /* srfs */ "res_total", /* srfs */ "soft_res", /* srfs */ "delta", /* srfs */ "reserve", /* srfs */ }; enum type_name { harddata, softdata, currdata, hardfile, softfile, currfile, timedata, timefile, snap_avail, ares_avail, res_total, soft_res, delta, reserve, type_end } type; if (attrib == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } if (strcmp(attrib->a_qualifier, "type")) { sprintf(log_buffer, "unknown qualifier %s", attrib->a_qualifier); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } for (type = 0; type < type_end; type++) { if (strcmp(attrib->a_value, type_array[type]) == 0) break; } if (type == type_end) /* check to see if command is legal */ { sprintf(log_buffer, "bad param: %s=%s", attrib->a_qualifier, attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if ((attrib = momgetattr(NULL)) == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } if (strcmp(attrib->a_qualifier, "dir") != 0) { sprintf(log_buffer, "bad param: %s=%s", attrib->a_qualifier, attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } if (attrib->a_value[0] == '/') /* must be absolute path */ strcpy(dirname, attrib->a_value); #if SRFS else if (attrib->a_value[0] == '$') /* variable location */ { char *var = &attrib->a_value[1]; char *val; if ((val = (char *)var_value(var)) == NULL) { sprintf(log_buffer, "variable %s not found", attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } strcpy(dirname, val); } #endif /* SRFS */ else { sprintf(log_buffer, "not an absolute path: %s", attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } /* ** See if it's a srfs request. They don't need an id. */ if (type >= snap_avail) { if (momgetattr(NULL)) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } #if SRFS /* check to see if we need to call quotactl() */ if (lastproc == reqnum && strcmp(dirname, srfsdir) == 0) { DBPRT(("%s: already got srfsinfo\n", id)) } else { if (quotactl(dirname, SRFS_INFO, (caddr_t)&srfsinfo) == -1) { log_err(errno, id, "quotactl(SRFS_INFO)"); rm_errno = RM_ERR_SYSTEM; return NULL; } strcpy(srfsdir, dirname); lastproc = reqnum; } /* all sizes in KB */ switch (type) { case snap_avail: sprintf(ret_string, "%ukb", (BSIZE * srfsinfo.snap_avail) >> 10); break; case ares_avail: sprintf(ret_string, "%ukb", (BSIZE * srfsinfo.ares_avail) >> 10); break; case res_total: sprintf(ret_string, "%d", (BSIZE * srfsinfo.res_total) >> 10); break; case soft_res: sprintf(ret_string, "%s", srfsinfo.soft_res ? "true" : "false"); break; case delta: sprintf(ret_string, "%lukb", (BSIZE * srfsinfo.delta) >> 10); break; case reserve: sprintf(ret_string, "%ld", (-BSIZE * srfsinfo.reserve) >> 10); break; } return ret_string; #else log_err(errno, id, no_srfs); rm_errno = RM_ERR_SYSTEM; return NULL; #endif } /* ** Check type of id: user, group or acct. */ if ((attrib = momgetattr(NULL)) == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } for (bean = 0; bean < bean_end; bean++) { if (strcmp(attrib->a_qualifier, bean_type[bean]) == 0) break; } if (bean == bean_end) { sprintf(log_buffer, "bad param: %s=%s", attrib->a_qualifier, attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } ident = atoi(attrib->a_value); if (ident == 0) { ident = bean_func[bean](attrib->a_value); if (ident == -1) { sprintf(log_buffer, "%s not found: %s", bean_type[bean], attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_EXIST; return NULL; } } if (momgetattr(NULL)) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } qi.qf_entry.id = ident; qi.qf_magic = QF_MAGIC; if (quotactl(dirname, Q_GETQUOTA, (caddr_t)&qi) == -1) { log_err(errno, id, "quotactl(Q_GETQUOTA)"); rm_errno = RM_ERR_SYSTEM; return NULL; } qu = NULL; switch (bean) { case account: if (qi.acct) qu = &qi.qf_entry.acct_q; break; case group: if (qi.group) qu = &qi.qf_entry.group_q; break; case user: if (qi.user) qu = &qi.qf_entry.user_q; break; } if (qu == NULL) { sprintf(log_buffer, "%s quota information not returned", bean_type[bean]); log_err(-1, id, log_buffer); rm_errno = RM_ERR_EXIST; return NULL; } switch (type) { case harddata: if (quotasize(qu->f_quota)) break; return ret_string; case softdata: if (quotasize(qu->f_warn)) break; return ret_string; case currdata: sprintf(ret_string, "%ld", BSIZE*qu->f_use); return ret_string; case hardfile: if (quotasize(qu->i_quota)) break; return ret_string; case softfile: if (quotasize(qu->i_warn)) break; return ret_string; case currfile: sprintf(ret_string, "%ld", qu->i_use); return ret_string; case timedata: case timefile: now = time((time_t *)NULL); if (qu->f_wtime > now) /* time is in the future */ sprintf(ret_string, "%ld", qu->f_wtime - now); else strcpy(ret_string, "0"); return ret_string; } /* ** If we get here, the default number is needed. */ DBPRT(("%s: getting default info\n", id)) header.qf_magic = QF_MAGIC; if (quotactl(dirname, Q_GETHEADER, (caddr_t)&header) == -1) { log_err(errno, id, "quotactl(Q_GETHEADER)"); rm_errno = RM_ERR_SYSTEM; return NULL; } switch (type) { case harddata: (void)quotasize(header.user_h.def_fq); return ret_string; case softdata: (void)quotasize(header.user_h.warn_fq); return ret_string; case hardfile: sprintf(ret_string, "%ld", header.user_h.def_iq); return ret_string; case softfile: sprintf(ret_string, "%ld", header.user_h.warn_iq); return ret_string; } return ret_string; } static char * srfs_reserve(struct rm_attribute *attrib) { char *id = "srfs_reserve"; #if SRFS char *dir, *end, *name; long num; if (attrib == NULL) { log_err(-1, id, no_parm); rm_errno = RM_ERR_NOPARAM; return NULL; } for (;;) { if ((name = (char *)var_value(attrib->a_qualifier)) == NULL) { sprintf(log_buffer, "unknown qualifier %s", attrib->a_qualifier); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } num = strtol(attrib->a_value, &end, 10); if (end == attrib->a_value) { sprintf(log_buffer, "bad number %s", attrib->a_value); log_err(-1, id, log_buffer); rm_errno = RM_ERR_BADPARAM; return NULL; } num = -(num + BSIZE - 1) / BSIZE; /* convert to blks */ if (quotactl(name, SRFS_RESERVE, (caddr_t)&num) == -1) { log_err(errno, id, "quotactl(SRFS_RESERVE)"); rm_errno = RM_ERR_SYSTEM; return NULL; } if ((attrib = momgetattr(NULL)) == NULL) break; } return "okay"; #else log_err(errno, id, no_srfs); rm_errno = RM_ERR_SYSTEM; return NULL; #endif } int get_la(double *rv) { char *id = "get_la"; *rv = (double)sysinfo.avenrun[0]; return 0; } static char * swaprate(struct rm_attribute *attrib) { char *id = "swaprate"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", swap_rate); return ret_string; } static char * swapinrate(struct rm_attribute *attrib) { char *id = "swapinrate"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", swapin_rate); return ret_string; } static char * swapoutrate(struct rm_attribute *attrib) { char *id = "swapoutrate"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", swapout_rate); return ret_string; } static struct swapper swapper; int getswap(void) { static unsigned int lastproc = 0; char *id = "getswap"; struct tbs info; if (lastproc == reqnum) /* don't need new swap info */ return 0; if (tabinfo(SWAPTAB, &info) == -1) { log_err(errno, id, "tabinfo(SWAPTAB)"); return 1; } if (tabread(SWAPTAB, (char *)&swapper, info.ent * info.len, info.head) == -1) { log_err(errno, id, "tabread(SWAPTAB)"); return 1; } DBPRT(("Total swap space: %8d\tAvailable swap space: %8d\n", swapper.swp_map.bmp_total * SWP_WGHT, swapper.swp_map.bmp_avail * SWP_WGHT)) lastproc = reqnum; return 0; } static char * swapused(struct rm_attribute *attrib) { char *id = "swapused"; int sout; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (getswap()) return NULL; sout = swapper.swp_map.bmp_total - swapper.swp_map.bmp_avail; /* in KB */ sprintf(ret_string, "%ukb", (ctob(swutoc(sout)) + 1023) >> 10); return ret_string; } static char * swapavail(struct rm_attribute *attrib) { char *id = "swapused"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (getswap()) return NULL; /* in KB */ sprintf(ret_string, "%ukb", (ctob(swutoc(swapper.swp_map.bmp_avail)) + 1023) >> 10); return ret_string; } static char * swaptotal(struct rm_attribute *attrib) { char *id = "swapused"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (getswap()) return NULL; /* in KB */ sprintf(ret_string, "%ukb", (ctob(swutoc(swapper.swp_map.bmp_total)) + 1023) >> 10); return ret_string; } static char * cpuidle(struct rm_attribute *attrib) { char *id = "cpuidle"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", cpu_idle); return ret_string; } static char * cpusysw(struct rm_attribute *attrib) { char *id = "cpusysw"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", cpu_sysw); return ret_string; } static char * cpuguest(struct rm_attribute *attrib) { char *id = "cpuguest"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", cpu_guest); return ret_string; } static char * cpuuser(struct rm_attribute *attrib) { char *id = "cpuuser"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", cpu_user); return ret_string; } static char * cpuunix(struct rm_attribute *attrib) { char *id = "cpuunix"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } if (last_time == 0) { rm_errno = RM_ERR_SYSTEM; return NULL; } sprintf(ret_string, "%.2f", cpu_unix); return ret_string; } void scan_non_child_tasks(void) { /* NYI */ return; } /* END scan_non_child_tasks() */