/* * 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 "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[] = "@(#) unicosmk2/$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 T3E machine. ** ** Resources known by this code: ** cput cpu time for a pid or session ** totmem total memory size ** availmem available memory size ** ncpus number of cpus ** physmem physical memory size ** size size of a file or filesystem ** idletime seconds of idle time ** quota quota information ** srfs_reserve set srfs reservation */ 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; extern int ignmem; /* ** 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); 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"; struct target tinfo; time_t wait_time; long last_time = 0; /* ** local resource array */ struct config dependent_config[] = { { "ncpus", {ncpus} }, { "totmem", {totmem} }, { "availmem", {availmem} }, { "physmem", {physmem} }, { "quota", {quota} }, { "srfs_reserve", {srfs_reserve} }, { NULL, {nullproc} }, }; /* * This routine is called on each cycle of the main loop. */ void dep_main_loop_cycle(void) { /* No periodic functions. */ } 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, (char *)"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)) dep_main_loop_cycle(); } void dep_cleanup(void) { char *id = "dep_cleanup"; int i; log_record(PBSEVENT_SYSTEM, 0, id, "dependent cleanup"); } /* * 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 mm_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 milliseconds in the unsigned long integer. */ static int mm_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); } /* * 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, * adjusted by cputfactor. */ static unsigned long cput_sum(job *pjob) { static char *id = "cput_sum"; ulong cputime = 0; int nps = 0; task *ptask; struct resclim rl; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) rl.resc_category = C_JOB; rl.resc_resource = L_CPU; 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 (getlim(ptask->ti_qs.ti_sid, &rl) == -1) continue; nps++; cputime += rl.resc_used; } if (nps == 0) pjob->ji_flags |= MOM_NO_PROC; else pjob->ji_flags &= ~MOM_NO_PROC; return ((unsigned long)((double)cputime * cputfactor)); } /* * Internal job cpu time decoding routine. * * Accepts a job pointer. Returns the sum of all moo time * consumed for all processes executed by the job, in seconds. */ static unsigned long mppt_sum(job *pjob) { static char *id = "mppt_sum"; ulong cputime = 0; task *ptask; struct resclim rl; DBPRT(("%s: entered %s\n", id, pjob->ji_qs.ji_jobid)) rl.resc_category = C_JOB; rl.resc_resource = L_MPPT; 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 (getlim(ptask->ti_qs.ti_sid, &rl) == -1) continue; cputime += rl.resc_used; } return (cputime); } 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 maxcput; 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 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 */ log_buffer[0] = '\0'; 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, (char *)"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, (char *)"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, (char *)"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]; 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 = mm_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 = mm_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 = mm_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 = mm_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 = mm_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 = mm_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 = mm_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 = mm_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 = mm_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 = mm_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)); } else if (strcmp(pname, "walltime") == 0) { retval = mm_gettime(pres, &value); if (retval != PBSE_NONE) return (error(pname, retval)); } 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_JOB, sessid, L_CPU, maxcput) < 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_JOBPROCS, sessid, L_CPU, maxpcput) < 0) return (error("pcput", PBSE_SYSTEM)); if (maxmem == MAXUE_LONG) /* if unlimited */ maxmem = 0; if (limit(C_JOB, sessid, L_MEM, maxmem) < 0) return (error("mem", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_MPPM, maxmem) < 0) return (error("mppm", 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_JOBPROCS, sessid, L_MEM, maxpmem) < 0) return (error("pmem", PBSE_SYSTEM)); if (maxpf == MAXUE_LONG) /* if unlimited */ maxpf = 0; if (limit(C_JOB, 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_JOBPROCS, sessid, L_FSBLK, maxppf) < 0) return (error("ppf", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_SDS, maxsds) < 0) return (error("sds", PBSE_SYSTEM)); if (limit(C_JOBPROCS, sessid, L_SDS, maxpsds) < 0) return (error("psds", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_CPROC, maxnproc) < 0) return (error("procs", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE0, maxmt[0]) < 0) return (error("mta", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE1, maxmt[1]) < 0) return (error("mtb", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE2, maxmt[2]) < 0) return (error("mtc", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE3, maxmt[3]) < 0) return (error("mtd", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE4, maxmt[4]) < 0) return (error("mte", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE5, maxmt[5]) < 0) return (error("mtf", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE6, maxmt[6]) < 0) return (error("mtg", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_TAPE7, maxmt[7]) < 0) return (error("mth", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_MPPE, maxmppe) < 0) return (error("mppe", PBSE_SYSTEM)); if (limit(C_JOB, sessid, L_MPPT, maxmppt) < 0) return (error("mppt", PBSE_SYSTEM)); if (limit(C_JOBPROCS, sessid, L_MPPT, maxpmppt) < 0) return (error("pmppt", PBSE_SYSTEM)); 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, "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)) 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) { 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 (ignwalltime == 0 && strcmp(pname, "walltime") == 0) { if ((pjob->ji_qs.ji_svrflags & JOB_SVFLG_HERE) == 0) continue; retval = mm_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; 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; 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, "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, "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, "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. */ int mom_close_poll(void) { 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_JOB, 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; } char * cput_job(jobid) pid_t jobid; { char *id = "cput_job"; struct resclim rl; rl.resc_category = C_JOB; rl.resc_resource = L_CPU; if (getlim(jobid, &rl) == -1) { rm_errno = RM_ERR_EXIST; return NULL; } sprintf(ret_string, "%.2f", cputfactor * rl.resc_used); return ret_string; } char * cput_proc(pid) pid_t pid; { char *id = "cput_pid"; struct resclim rl; DBPRT(("%s: entered %d\n", id, pid)) rl.resc_category = C_PROC; rl.resc_resource = L_CPU; if (getlim(pid, &rl) == -1) { rm_errno = RM_ERR_EXIST; return NULL; } sprintf(ret_string, "%.2f", cputfactor * rl.resc_used); return ret_string; } 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"; rm_errno = RM_ERR_EXIST; return NULL; } char * mem_proc(pid) pid_t pid; { char *id = "mem_proc"; 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"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } rm_errno = RM_ERR_EXIST; return NULL; } 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"; if (attrib) { log_err(-1, id, extra_parm); rm_errno = RM_ERR_BADPARAM; return NULL; } rm_errno = RM_ERR_EXIST; return NULL; } char * pids(struct rm_attribute *attrib) { char *id = "pids"; pid_t jobid; 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; } rm_errno = RM_ERR_EXIST; return NULL; } 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, (char *)"statfs"); rm_errno = RM_ERR_SYSTEM; return NULL; } DBPRT(("%s: bsize=%d blocks=%d\n", id, fsbuf.f_bsize, fsbuf.f_blocks)) sprintf(ret_string, "%d", fsbuf.f_bsize * fsbuf.f_blocks); 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, (char *)"statfs"); rm_errno = RM_ERR_SYSTEM; return NULL; } DBPRT(("%s: bsize=%d bfree=%d\n", id, fsbuf.f_bsize, fsbuf.f_bfree)) sprintf(ret_string, "%d", fsbuf.f_bsize * fsbuf.f_bfree); 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; } sprintf(ret_string, "%ld", tinfo.mc_msz * sizeof(int)); 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, (char *)"statfs"); rm_errno = RM_ERR_BADPARAM; return NULL; } 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, (char *)"stat"); rm_errno = RM_ERR_BADPARAM; return NULL; } sprintf(ret_string, "%d", sbuf.st_size); 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, (char *)"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; } static int quotasize(int blocks) { if (QFV_MINVALUE <= blocks && blocks <= QFV_MAXVALUE) { sprintf(ret_string, "%ld", BSIZE * blocks); 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; 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); 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; } log_err(errno, id, no_srfs); rm_errno = RM_ERR_SYSTEM; return NULL; } /* ** 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, (char *)"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"; log_err(errno, id, no_srfs); rm_errno = RM_ERR_SYSTEM; return NULL; } void scan_non_child_tasks(void) { /* NYI */ return; } /* END scan_non_child_tasks() */