/* * 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: * * 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. */ /* * * qstat - (PBS) show stats of batch jobs, queues, or servers * * Authors: * Terry Heidelberg * Livermore Computing * * Bruce Kelly * National Energy Research Supercomputer Center * * Lawrence Livermore National Laboratory * University of California */ #include /* the master config generated by configure */ #include #include #include #if TCL_QSTAT #include #include #if TCLX #include #endif #endif #include "cmds.h" #include "mcom.h" #include "utils.h" static void states(); #if !defined(PBS_NO_POSIX_VIOLATION) /* defines for alternative display formats */ #define ALT_DISPLAY_a 1 /* -a option - show all jobs */ #define ALT_DISPLAY_i 2 /* -i option - show not running */ #define ALT_DISPLAY_r 4 /* -r option - show only running */ #define ALT_DISPLAY_u 8 /* -u option - list user's jobs */ #define ALT_DISPLAY_n 0x10 /* -n option - add node list */ #define ALT_DISPLAY_s 0x20 /* -s option - add scheduler comment */ #define ALT_DISPLAY_R 0x40 /* -R option - add SRFS info */ #define ALT_DISPLAY_q 0x80 /* -q option - alt queue display */ #define ALT_DISPLAY_Mb 0x100 /* show sizes in MB */ #define ALT_DISPLAY_Mw 0x200 /* -M option - show sizes in MW */ #define ALT_DISPLAY_G 0x400 /* -G option - show sizes in GB */ #define ALT_DISPLAY_o 0x800 /* -1 option - add node list on same line */ #endif /* not PBS_NO_POSIX_VIOLATION */ /* globals */ mbool_t DisplayXML = FALSE; #define maxlinesize 65536 int linesize = 77; int tasksize; static char *summarize_arrays_extend_opt = "summarize_arrays"; /* END globals */ #define DEFTASKSIZE 6 int tasksize = DEFTASKSIZE; int alias_opt = FALSE; int isjobid( char *string) { int i; int result; i = strspn(string, " "); /* locate first non-blank */ if (isdigit(string[i])) result = 1; /* job_id */ else if (isalpha(string[i])) result = 0; /* not a job_id */ else result = 0; /* who knows - probably a syntax error */ return(result); } /* END isjobid() */ int istrue( char *string) /* I */ { if (!strcasecmp(string, "TRUE")) { return(TRUE); } if (!strcmp(string, "1")) { return(TRUE); } return(FALSE); } /* END istrue() */ int time_to_string( char *time_string, int time_to_convert) { int seconds = 0; int total_minutes = 0; int minutes = 0; int hours = 0; int time_in_seconds = 0; time_in_seconds = time_to_convert; /* Get the number of seconds in the job */ seconds = time_in_seconds % 60; /* Calculate the total minutes and then get the minutes less than an hour */ total_minutes = time_in_seconds / 60; /* Calculate hours */ hours = total_minutes / 60; /* calculate minutes */ minutes = total_minutes % 60; sprintf(time_string, "%.2d:%.2d:%.2d", hours, minutes, seconds); return(PBSE_NONE); } int timestring_to_int( char *timestring, int *req_walltime) { char *ptr_string; char *ptr; char *number; int hours; int minutes; int seconds; ptr_string = (char *)malloc(strlen(timestring)+1); if (ptr_string == NULL) return(PBSE_MEM_MALLOC); strcpy(ptr_string, timestring); number = ptr_string; ptr = strstr(ptr_string, ":"); if (ptr == NULL) { free(ptr_string); return (PBSE_BAD_PARAMETER); } *ptr = 0; ptr++; hours = atoi(number); hours = hours * 3600; number = ptr; ptr = strstr(ptr, ":"); if (ptr == NULL) { free(ptr_string); return (PBSE_BAD_PARAMETER); } *ptr = 0; ptr++; minutes = atoi(number); minutes = minutes * 60; number = ptr; if (number == NULL) { free(ptr_string); return(PBSE_BAD_PARAMETER); } seconds = atoi(number); *req_walltime = hours + minutes + seconds; free(ptr_string); return(PBSE_NONE); } static void states( char *string, /* I */ char *q, /* O */ char *r, /* O */ char *h, /* O */ char *w, /* O */ char *t, /* O */ char *e, /* O */ int len) /* I */ { char *c, *d, *f, *s, l; /* FORMAT: Queued:X Running:Y... */ c = string; while (isspace(*c) && *c != '\0') c++; while (*c != '\0') { s = c; while (*c != ':') c++; *c = '\0'; d = NULL; if (strcmp(s, "Queued") == 0) d = q; else if (strcmp(s, "Running") == 0) d = r; else if (strcmp(s, "Held") == 0) d = h; else if (strcmp(s, "Waiting") == 0) d = w; else if (strcmp(s, "Transit") == 0) d = t; else if (strcmp(s, "Exiting") == 0) d = e; c++; if (d != NULL) { s = c; while ((*c != ' ') && (*c != '\0')) c++; l = *c; *c = '\0'; if (strlen(s) > (size_t)len) { f = s + len; *f = '\0'; } strcpy(d, s); if (l != '\0') c++; } } return; } /* END states() */ /* * print an attribute value string, formating to break a comma if possible */ void prt_attr( char *n, /* I name */ char *r, /* I resource (optional) */ char *v) /* I value */ { char *c; char *comma = ","; int first = 1; int l; int start; start = strlen(n) + 7; /* 4 spaces + ' = ' is 7 */ printf(" %s", n); if (r != NULL) { start += strlen(r) + 1; printf(".%s", r); } printf(" = "); c = strtok(v, comma); while (c != NULL) { if ((l = strlen(c)) + start < linesize) { printf("%s", c); start += l; } else { if (!first) { printf("\n\t"); start = 9; } while (*c) { putchar(*c++); if (++start > linesize) { start = 8; printf("\n\t"); } } } if ((c = strtok(NULL, comma)) != NULL) { first = 0; putchar(','); } } return; } /* END prt_attr() */ /* * locate an attribute (attrl) by name (and resource) and return value * returns null if not found */ static char *findattrl( struct attrl *pattrl, char *name, char *resc) { while (pattrl != NULL) { if (!strcmp(name, pattrl->name)) { if (resc != NULL) { if (!strcmp(resc, pattrl->resource)) { return(pattrl->value); } } else { return(pattrl->value); } } pattrl = pattrl->next; } return(NULL); } #ifndef PBS_MINNAMELEN #define PBS_MINNAMELEN 16 /* min size for printf job jobs, queues, and servers */ #endif /* PBS_MINNAMELEN */ #ifndef PBS_NAMELEN #define PBS_NAMELEN 16 /* printf of jobs, queues, and servers */ #endif /* PBS_NAMELEN */ #define PBS_JOB_ID_LEN 22 #define OWNERL 15 /* printf of jobs */ #define TIMEUL 8 /* printf of jobs */ #define STATEL 1 /* printf of jobs */ #define LOCL 15 /* printf of jobs */ #define SIZEL 6 /* length of "SIZE" fields in printf */ /* * Format and display string of assigned nodes, (1) strip off domain name * if present and (2) break line at '+' sign. */ static void prt_nodes( char *nodes) /* I */ { int i; char *stp; char linebuf[65536]; if ((nodes == NULL) || (*nodes == '\0')) { /* FAILURE - node is invalid */ return; } i = 0; stp = nodes; while (*nodes != '\0') { if ((*stp == '.') || (*stp == '+') || (*stp == '\0')) { /* does node fit into line? */ if (i + stp - nodes < linesize) { while (nodes < stp) linebuf[i++] = *nodes++; } else { /* flush line and start next */ linebuf[i] = '\0'; printf(" %s\n", linebuf); i = 0; while (nodes < stp) linebuf[i++] = *nodes++; } /* strip off domain name to keep string short */ while ((*stp != '+') && (*stp != '\0')) stp++; nodes = stp++; } else { stp++; } } if (i != 0) { linebuf[i] = '\0'; printf(" %s\n", linebuf); } return; } /* END prt_nodes() */ /* * convert size from suffix string (nnnn[ kmgt][ bw]) to string of * k[bw] for neither -M or -G * mw for -M * gb for -G */ static char *cnv_size( char *value, int opt) { static int sift_factor[3][5] = { { -20, -10, 0, 10, 20 }, /* mb conversion */ { -23, -13, -3, 7, 17 }, /* mw conversion */ { -30, -20, -10, 0, 10 } }; /* gb conversion */ int in; int out; int sft; unsigned long nval; char *pc; char *suffix; static char outbuf[25]; if (opt & ALT_DISPLAY_Mb) { out = 0; suffix = "mb"; } else if (opt & ALT_DISPLAY_Mw) { out = 1; suffix = "mw"; } else if (opt & ALT_DISPLAY_G) { out = 2; suffix = "gb"; } else { return (value); /* return unmodified */ } nval = strtol(value, &pc, 10); if (*pc == 'k') in = 1; else if (*pc == 'm') in = 2; else if (*pc == 'g') in = 3; else if (*pc == 't') in = 4; else in = 0; sft = sift_factor[out][in]; if ((*pc == 'w') || (*(pc + 1) == 'w')) nval = nval << 3; /* convert to bytes */ if (sft < 0) { nval = nval + ((1 << -sft) - 1); /* round up (ceiling) */ nval = nval >> -sft; } else { nval = nval << sft; } sprintf(outbuf, "%lu%s", nval, suffix); return(outbuf); } /* * Format and display status of job in alternate form (not POSIX standard) */ static void altdsp_statjob( struct batch_status *pstat, /* I */ struct batch_status *prtheader, /* I */ int alt_opt) /* I */ { char *comment; char *pc; struct attrl *pat; char *exechost; char *usern = NULL; char *queuen = NULL; char *jobn = NULL; char *sess; char *tasks; char calcTasks[64]; char *nodect; char *rqtimecpu; char *rqtimewal; char *jstate; char *eltimecpu; char *eltimewal; char *walltime_remaining = "0"; int rem_walltime = 0; int req_walltime = 0; int elap_time = 0; char elap_time_string[100]; char tmpLine[MAX_LINE_LEN+1]; int usecput; static char pfs[SIZEL]; static char rqmem[SIZEL]; static char srfsbig[SIZEL]; static char srfsfast[SIZEL]; static char *blank = " -- "; if (prtheader) { printf("\n%s: ", prtheader->name); if ((pc = findattrl(prtheader->attribs, ATTR_comment, NULL)) != NULL) { printf("%s", pc); } if (alt_opt & ALT_DISPLAY_R) { printf("\n Req'd Req'd Elap \n"); printf("Job ID Username Queue NDS TSK Memory Time S Time BIG FAST PFS\n"); printf("----------------------- ----------- -------- ----- ------ ------ --------- - --------- ----- ----- -----\n"); } else { printf("\n Req'd Req'd Elap\n"); printf("Job ID Username Queue Jobname SessID NDS TSK Memory Time S Time\n"); printf("----------------------- ----------- -------- ---------------- ------ ----- ------ ------ --------- - ---------\n"); } } while (pstat != NULL) { exechost = blank; sess = blank; nodect = blank; tasks = blank; rqtimecpu = blank; rqtimewal = blank; eltimecpu = blank; eltimewal = blank; jstate = blank; comment = blank; strcpy(elap_time_string, blank); /* *pfs = *blank; */ strcpy(pfs, blank); /* *rqmem = *blank; */ strcpy(rqmem, blank); /* *srfsbig = *blank; */ strcpy(srfsbig, blank); /* *srfsfast = *blank; */ strcpy(srfsfast, blank); usecput = 0; elap_time = 0; req_walltime = 0; rem_walltime = 0; pat = pstat->attribs; while (pat != NULL) { if (!strcmp(pat->name, ATTR_N)) { jobn = pat->value; } else if (!strcmp(pat->name, ATTR_owner)) { usern = pat->value; if ((pc = strchr(usern, (int)'@')) != NULL) * pc = '\0'; } else if (!strcmp(pat->name, ATTR_state)) { jstate = pat->value; } else if (!strcmp(pat->name, ATTR_queue)) { queuen = pat->value; } else if (!strcmp(pat->name, ATTR_session)) { sess = pat->value; } else if (!strcmp(pat->name, ATTR_l)) { if (!strcmp(pat->resource, "nodect")) { nodect = pat->value; } else if (!strcmp(pat->resource, "nodes")) { char *tmp = pat->value; char *eq = strchr(tmp,'='); if (eq != NULL) { int nodes = atoi(pat->value); int procs = atoi(eq+1); sprintf(calcTasks,"%d",nodes*procs); tasks = calcTasks; } else { tasks = pat->value; } } else if (!strcmp(pat->resource, "ncpus")) { if ((!strcmp(tasks,blank)) && (strcmp(pat->value, "0"))) tasks = pat->value; } else if (!strcmp(pat->resource, "mppe")) { if (strcmp(pat->value, "0")) tasks = pat->value; } else if (!strcmp(pat->resource, "size")) { if (strcmp(pat->value, "0")) tasks = pat->value; } else if (!strcmp(pat->resource, "mem")) { strncpy(rqmem, cnv_size(pat->value, alt_opt), SIZEL); } else if (!strcmp(pat->resource, "walltime")) { rqtimewal = pat->value; timestring_to_int(pat->value, &req_walltime); } else if (!strcmp(pat->resource, "cput")) { rqtimecpu = pat->value; usecput = 1; } else if (!strcmp(pat->resource, "srfs_big")) { strncpy(srfsbig, cnv_size(pat->value, alt_opt), SIZEL - 1); } else if (!strcmp(pat->resource, "srfs_fast")) { strncpy(srfsfast, cnv_size(pat->value, alt_opt), SIZEL - 1); } else if (!strcmp(pat->resource, "piofs")) { strncpy(pfs, cnv_size(pat->value, alt_opt), SIZEL - 1); } } else if (!strcmp(pat->name, ATTR_exechost)) { exechost = pat->value; } else if (!strcmp(pat->name, ATTR_used)) { if (!strcmp(pat->resource, "walltime")) { eltimewal = pat->value; } else if (!strcmp(pat->resource, "cput")) { eltimecpu = pat->value; } } else if (!strcmp(pat->name, ATTR_comment)) { comment = pat->value; } else if (!strcmp(pat->name, "Walltime")) { walltime_remaining = pat->value; rem_walltime = atoi(walltime_remaining); } pat = pat->next; } if ((*jstate != 'Q') && (*jstate != 'C')) { elap_time = req_walltime - rem_walltime; time_to_string(elap_time_string, elap_time); } snprintf(tmpLine, MAX_LINE_LEN, "%%-23.%ds %%-11.11s %%-8.8s ", PBS_JOB_ID_LEN); printf(tmpLine, pstat->name, usern, queuen); if (alt_opt & ALT_DISPLAY_R) { printf("%5.5s %*.*s %6.6s %9.9s %1.1s %9.9s %5.5s %5.5s %5.5s", nodect, tasksize, tasksize, tasks, rqmem, usecput ? rqtimecpu : rqtimewal, jstate, usecput ? eltimecpu : elap_time_string, srfsbig, srfsfast, pfs); } else { snprintf(tmpLine, MAX_LINE_LEN, "%%-%d.%ds %%6.6s %%5.5s %%*.*s %%6.6s %%9.9s %%1.1s %%9.9s", PBS_NAMELEN, PBS_NAMELEN); printf(tmpLine, jobn, sess, nodect, tasksize, tasksize, tasks, rqmem, usecput ? rqtimecpu : rqtimewal, jstate, usecput ? eltimecpu : elap_time_string); } if (linesize < maxlinesize) printf("\n"); if (alt_opt & ALT_DISPLAY_n) { /* print assigned nodes */ prt_nodes(exechost); } if (alt_opt & ALT_DISPLAY_s) { /* print (scheduler) comment */ if (*comment != '\0') printf(" %s\n", comment); } /* This makes the compiler happy because this value is now set but not used. It was replaced by elap_time_string. I am leaving it here as an artifact incase we need to still use it. */ if (eltimewal) { ; } pstat = pstat->next; } return; } /* END altdsp_statjob() */ /* * get_ct - get count of jobs in queue/run state * support function for altdsp_statque() */ static void get_ct( char *str, int *jque, int *jrun) { char *ps; int colon = (int)':'; ps = strchr(str, colon); /* Transit - skip */ ps = strchr(ps + 1, colon); /* Queued - add to jque */ *jque += atoi(ps + 1); ps = strchr(ps + 1, colon); /* Held - add to jque */ *jque += atoi(ps + 1); ps = strchr(ps + 1, colon); /* Waiting - add to jque */ *jque += atoi(ps + 1); ps = strchr(ps + 1, colon); /* Running - add to jrun */ *jrun += atoi(ps + 1); return; } /* END get_ct() */ /* * altdsp_statque - alternative display for queue information, -q option */ static void altdsp_statque( char *serv, struct batch_status *pstat, int opt) { char rmem[SIZEL]; char *cput; char *wallt; char *jmax; char *nodect; char *blank = "-- "; int jrun; int jque; char qenabled = '\0'; char qstarted = '\0'; int tot_jrun = 0; int tot_jque = 0; struct attrl *pat; printf("\nserver: %s\n\n", serv); printf("Queue Memory CPU Time Walltime Node Run Que Lm State\n"); printf("---------------- ------ -------- -------- ---- --- --- -- -----\n"); while (pstat != NULL) { /* *rmem = '\0'; */ strncpy(rmem, "-- ", SIZEL - 1); cput = blank; wallt = blank; nodect = "-- "; jrun = 0; jque = 0; jmax = blank; pat = pstat->attribs; while (pat != NULL) { if (strcmp(pat->name, ATTR_maxrun) == 0) { jmax = pat->value; } else if (strcmp(pat->name, ATTR_enable) == 0) { if (*pat->value == 'T') qenabled = 'E'; else qenabled = 'D'; } else if (strcmp(pat->name, ATTR_start) == 0) { if (*pat->value == 'T') qstarted = 'R'; else qstarted = 'S'; } else if (strcmp(pat->name, ATTR_count) == 0) { get_ct(pat->value, &jque, &jrun); tot_jque += jque; tot_jrun += jrun; } else if (strcmp(pat->name, ATTR_rescmax) == 0) { if (strcmp(pat->resource, "mem") == 0) { strncpy( rmem, cnv_size(pat->value, opt), SIZEL); } else if (strcmp(pat->resource, "cput") == 0) { cput = pat->value; } else if (strcmp(pat->resource, "walltime") == 0) { wallt = pat->value; } else if (strcmp(pat->resource, "nodect") == 0) { nodect = pat->value; } } pat = pat->next; } printf("%-16.16s %6.6s %8.8s %8.8s %5.5s ", pstat->name, rmem, cput, wallt, nodect); printf("%3d %3d %2.2s %c %c\n", jrun, jque, jmax, qenabled, qstarted); pstat = pstat->next; } /* END while (pstat != NULL) */ printf(" ----- -----\n"); printf(" %5d %5d\n", tot_jrun, tot_jque); return; } /* END altdsp_statque() */ /* build and add an attropl struct to the list */ static void add_atropl( struct attropl **list, char *name, char *resc, char *value, enum batch_op op) { struct attropl *patro; patro = (struct attropl *)malloc(sizeof(struct attropl)); if (patro == NULL) { fprintf(stderr, "cannot malloc space\n"); exit(1); } patro->next = *list; patro->name = name; patro->resource = resc; patro->value = value; patro->op = op; *list = patro; return; } /* END add_atropl() */ /* display when a normal "qstat" is executed */ void display_statjob( struct batch_status *status, /* I (data) */ int prtheader, /* I (boolean) */ int full) /* I (boolean) */ { struct batch_status *p; struct attrl *a; int l; char *c; char *jid; char *name; char *owner; char *timeu; char *state; char *location; char format[80]; char long_name[17]; time_t epoch; mxml_t *DE; mxml_t *JE; mxml_t *AE; mxml_t *RE1; mxml_t *JI; /* XML only support for full output */ if (DisplayXML == TRUE) full = 1; if (!full) { sprintf(format, "%%-%ds %%-%ds %%-%ds %%%ds %%%ds %%-%ds\n", PBS_MAXSEQNUM + PBS_MAXJOBARRAYLEN + 11, PBS_MINNAMELEN, OWNERL, TIMEUL, STATEL, LOCL); if (prtheader) { /* display summary header TODO - the sizes of these fields should be determined from #defines in pbs_ifl.h */ printf("Job ID Name User Time Use S Queue\n"); printf("------------------------- ---------------- --------------- -------- - -----\n"); } } /* END if (!full) */ if (DisplayXML == TRUE) { /* create parent */ DE = NULL; MXMLCreateE(&DE, "Data"); } for (p = status;p != NULL;p = p->next) { jid = NULL; name = NULL; owner = NULL; timeu = NULL; state = NULL; location = NULL; if (full) { if (DisplayXML == TRUE) { JE = NULL; MXMLCreateE(&JE, "Job"); MXMLAddE(DE, JE); JI = NULL; MXMLCreateE(&JI, "Job_Id"); MXMLSetVal(JI, p->name,mdfString); MXMLAddE(JE, JI); } else { printf("Job Id: %s\n", p->name); } a = p->attribs; RE1 = NULL; while (a != NULL) { if (a->name != NULL) { if (DisplayXML == TRUE) { /* lookup a->name -> XML attr name */ AE = NULL; if (a->resource != NULL) { if (RE1 == NULL) { MXMLCreateE(&RE1, a->name); MXMLAddE(JE, RE1); } MXMLCreateE(&AE, a->resource); MXMLSetVal(AE, a->value, mdfString); MXMLAddE(RE1, AE); } else { RE1 = NULL; MXMLCreateE(&AE, a->name); MXMLSetVal(AE, a->value, mdfString); MXMLAddE(JE, AE); } } else { if (!strcmp(a->name, ATTR_ctime) || !strcmp(a->name, ATTR_etime) || !strcmp(a->name, ATTR_mtime) || !strcmp(a->name, ATTR_qtime) || !strcmp(a->name, ATTR_start_time) || !strcmp(a->name, ATTR_comp_time) || !strcmp(a->name, ATTR_checkpoint_time) || !strcmp(a->name, ATTR_a)) { epoch = (time_t)atoi(a->value); prt_attr(a->name, a->resource, ctime(&epoch)); } else { prt_attr(a->name, a->resource, a->value); printf("\n"); } } } a = a->next; } } /* END if (full) */ else { /* display summary data */ if (p->name != NULL) { c = p->name; while ((*c != '.') && (*c != '\0')) c++; if (alias_opt == TRUE) { /* show the alias as well as the first part of the server name */ if (*c == '.') { c++; while((*c != '.') && (*c != '\0')) c++; } } if (alias_opt == TRUE) { /* show the alias as well as the first part of the server name */ if (*c == '.') { c++; while((*c != '.') && (*c != '\0')) c++; } } c++; /* List the first part of the server name, too. */ while ((*c != '.') && (*c != '\0')) c++; *c = '\0'; l = strlen(p->name); if (l > (PBS_MAXSEQNUM + PBS_MAXJOBARRAYLEN + 8)) { /* truncate job name */ c = p->name + PBS_MAXSEQNUM + PBS_MAXJOBARRAYLEN + 14; *c = '\0'; } jid = p->name; } a = p->attribs; while (a != NULL) { if (a->name != NULL) { if (strcmp(a->name, ATTR_name) == 0) { l = strlen(a->value); /* truncate AName */ if (l > PBS_NAMELEN) { l = l - PBS_NAMELEN + 3; c = a->value + l; while ((*c != '/') && (*c != '\0')) c++; if (*c == '\0') c = a->value + l; strcpy(long_name, "..."); strcat(long_name, c); c = long_name; } else { c = a->value; } name = c; } else if (!strcmp(a->name, ATTR_owner)) { c = a->value; while ((*c != '@') && (*c != '\0')) c++; *c = '\0'; l = strlen(a->value); if (l > OWNERL) { c = a->value + OWNERL; *c = '\0'; } owner = a->value; } else if (!strcmp(a->name, ATTR_used)) { if (!strcmp(a->resource, "cput")) { l = strlen(a->value); if (l > TIMEUL) { c = a->value + TIMEUL; *c = '\0'; } timeu = a->value; } } else if (!strcmp(a->name, ATTR_state)) { l = strlen(a->value); if (l > STATEL) { c = a->value + STATEL; *c = '\0'; } state = a->value; } else if (!strcmp(a->name, ATTR_queue)) { c = a->value; while ((*c != '@') && (*c != '\0')) c++; *c = '\0'; l = strlen(a->value); if (l > LOCL) { c = a->value + LOCL; *c = '\0'; } location = a->value; } } a = a->next; } if (timeu == NULL) timeu = "0"; /* display summary data */ printf(format, jid, name, owner, timeu, state, location); } /* END else (full) */ if (DisplayXML != TRUE) { if (full) printf("\n"); } } /* END for (p = status) */ if (DisplayXML == TRUE) { char *tmpBuf = NULL, *tail = NULL; int bufsize; MXMLToXString(DE, &tmpBuf, &bufsize, INT_MAX, &tail, TRUE); MXMLDestroyE(&DE); fprintf(stdout, "%s\n", tmpBuf); } return; } /* END display_statjob() */ #define MINNUML 3 #define MAXNUML 5 #define TYPEL 10 void display_statque( struct batch_status *status, int prtheader, int full) { struct batch_status *p; struct attrl *a = NULL; int l; char *c; char *name; char *max; char *tot; char ena[MAXNUML + 1]; char str[MAXNUML + 1]; char que[MAXNUML + 1]; char run[MAXNUML + 1]; char hld[MAXNUML + 1]; char wat[MAXNUML + 1]; char trn[MAXNUML + 1]; char ext[MAXNUML + 1]; char *type; char format[80]; int NUML = 5; sprintf(format, "%%-%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%-%ds\n", PBS_MINNAMELEN, NUML, NUML, NUML, NUML, NUML, NUML, NUML, NUML, NUML, NUML, TYPEL); if (!full && prtheader) { printf(format, "Queue", "Max", "Tot", "Ena", "Str", "Que", "Run", "Hld", "Wat", "Trn", "Ext", "T"); printf(format, "----------------", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "-"); } p = status; while (p != NULL) { name = NULL; max = "0"; tot = "0"; strcpy(ena, "no"); strcpy(str, "no"); strcpy(que, "0"); strcpy(run, "0"); strcpy(hld, "0"); strcpy(wat, "0"); strcpy(trn, "0"); strcpy(ext, "0"); type = "not defined"; if (full) { printf("Queue: %s\n", p->name); a = p->attribs; while (a != NULL) { if (a->name != NULL) { prt_attr(a->name, a->resource, a->value); printf("\n"); } a = a->next; } } else { if (p->name != NULL) { l = strlen(p->name); if (l > PBS_NAMELEN) { c = a->name + PBS_NAMELEN; *c = '\0'; } name = p->name; } a = p->attribs; while (a != NULL) { if (a->name != NULL) { if (strcmp(a->name, ATTR_maxrun) == 0) { l = strlen(a->value); if (l > NUML) { c = a->value + NUML; *c = '\0'; } max = a->value; } else if (strcmp(a->name, ATTR_total) == 0) { l = strlen(a->value); if (l > NUML) { c = a->value + NUML; *c = '\0'; } tot = a->value; } else if (strcmp(a->name, ATTR_enable) == 0) { if (istrue(a->value)) strcpy(ena, "yes"); else strcpy(ena, "no"); } else if (strcmp(a->name, ATTR_start) == 0) { if (istrue(a->value)) strcpy(str, "yes"); else strcpy(str, "no"); } else if (strcmp(a->name, ATTR_count) == 0) { states(a->value, que, run, hld, wat, trn, ext, NUML); } else if (strcmp(a->name, ATTR_qtype) == 0) { type = a->value; *(type + 1) = '\0'; } } a = a->next; } printf(format, name, max, tot, ena, str, que, run, hld, wat, trn, ext, type); } if (full) printf("\n"); p = p->next; } return; } #define STATUSL 10 void display_statserver( struct batch_status *status, int prtheader, int full) { struct batch_status *p; struct attrl *a; int l; char *c; char *name; char *max; char *tot; char que[MAXNUML + 1]; char run[MAXNUML + 1]; char hld[MAXNUML + 1]; char wat[MAXNUML + 1]; char trn[MAXNUML + 1]; char ext[MAXNUML + 1]; char *stats; char format[80]; int NUML; NUML = MAXNUML; sprintf(format, "%%-%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%-%ds\n", PBS_MINNAMELEN, NUML, NUML, NUML, NUML, NUML, NUML, NUML, NUML, STATUSL); if (!full && prtheader) { printf(format, "Server", "Max", "Tot", "Que", "Run", "Hld", "Wat", "Trn", "Ext", "Status"); printf(format, "----------------", "---", "---", "---", "---", "---", "---", "---", "---", "----------"); } p = status; while (p != NULL) { name = NULL; max = "0"; tot = "0"; strcpy(que, "0"); strcpy(run, "0"); strcpy(hld, "0"); strcpy(wat, "0"); strcpy(trn, "0"); strcpy(ext, "0"); stats = ""; if (full) { printf("Server: %s\n", p->name); a = p->attribs; while (a != NULL) { if (a->name != NULL) { prt_attr(a->name, a->resource, a->value); printf("\n"); } a = a->next; } } else { if (p->name != NULL) { l = strlen(p->name); if (l > PBS_NAMELEN) { c = p->name + PBS_NAMELEN; *c = '\0'; } name = p->name; } a = p->attribs; while (a != NULL) { if (a->name != NULL) { if (strcmp(a->name, ATTR_maxrun) == 0) { l = strlen(a->value); if (l > NUML) { c = a->value + NUML; *c = '\0'; } max = a->value; } else if (strcmp(a->name, ATTR_total) == 0) { l = strlen(a->value); if (l > NUML) { c = a->value + NUML; *c = '\0'; } tot = a->value; } else if (strcmp(a->name, ATTR_count) == 0) { states(a->value, que, run, hld, wat, trn, ext, NUML); } else if (strcmp(a->name, ATTR_status) == 0) { l = strlen(a->value); if (l > STATUSL) { c = a->value + STATUSL; *c = '\0'; } stats = a->value; } } a = a->next; } printf(format, name, max, tot, que, run, hld, wat, trn, ext, stats); } if (full) printf("\n"); p = p->next; } return; } /* END display_statserver() */ #if TCL_QSTAT #define ARGNUM 1024 char *attrlist( struct attrl *ap) { char nameres[256]; char *argv[ARGNUM]; char *ret; int i, num = 0; while (ap) { char *twol[2]; if (ap->resource != NULL) { sprintf(nameres, "%s%s%s", ap->name, TCL_ATRSEP, ap->resource); twol[0] = nameres; } else { twol[0] = ap->name; } twol[1] = ap->value; argv[num++] = Tcl_Merge(2, (const char **)twol); if (num == ARGNUM) break; ap = ap->next; } ret = Tcl_Merge(num, (const char **)argv); for (i = 0;i < num;i++) free(argv[i]); return(ret); } Tcl_Interp *interp = NULL; char script[200]; char flags[] = "flags"; char ops[] = "operands"; char error[] = "error"; void tcl_init(void) { struct passwd *pw; uid_t uid; struct stat sb; uid = getuid(); pw = getpwuid(uid); if (pw == NULL) return; sprintf(script, "%s/.qstatrc", pw->pw_dir); if (stat(script, &sb) == -1) { strcpy(script, QSTATRC_PATH); if (stat(script, &sb) == -1) return; } interp = Tcl_CreateInterp(); if (Tcl_Init(interp) == TCL_ERROR) { fprintf(stderr, "Tcl_Init error: %s", interp->result); } #if TCLX #if TCL_MINOR_VERSION < 5 && TCL_MAJOR_VERSION < 8 if (TclX_Init(interp) == TCL_ERROR) { #else if (Tclx_Init(interp) == TCL_ERROR) { #endif fprintf(stderr, "Tclx_Init error: %s", interp->result); } #endif /* TCLX */ return; } void tcl_addarg(name, arg) char *name; char *arg; { if (interp == NULL) return; if (arg == NULL || *arg == '\0') return; Tcl_SetVar(interp, name, arg, TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); } int tcl_stat( char *type, struct batch_status *bs, int f_opt) { struct batch_status *bp; char *twol[2]; char *argv[ARGNUM]; int i, num = 0; char *result; if (interp == NULL) { return(1); } if (f_opt == 0) { return(1); } twol[0] = type; for (bp = bs;bp != NULL;bp = bp->next) { char *threel[3]; threel[0] = bp->name; threel[1] = attrlist(bp->attribs); threel[2] = bp->text; argv[num++] = Tcl_Merge(3, (const char **)threel); free(threel[1]); /* malloc'ed in attrlist() */ if (num == ARGNUM) break; } twol[1] = Tcl_Merge(num, (const char **)argv); for (i = 0;i < num;i++) free(argv[i]); result = Tcl_Merge(2, (const char **)twol); Tcl_SetVar( interp, "objects", result, TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); free(twol[1]); free(result); return(0); } void tcl_run( int f_opt) { if (interp == NULL) { return; } if (f_opt && Tcl_EvalFile(interp, script) != TCL_OK) { char *trace; trace = (char *)Tcl_GetVar(interp, "errorInfo", 0); if (trace == NULL) trace = interp->result; fprintf(stderr, "%s: TCL error @ line %d: %s\n", script, interp->errorLine, trace); } Tcl_DeleteInterp(interp); return; } /* END tcl_run() */ #else #define tcl_init() #define tcl_addarg(name, arg) #define tcl_stat(type, bs, f_opt) 1 #define tcl_run(f_opt) #endif /* TCL_QSTAT */ /* connects to server side routine pbs_statjob() in lib/Libifl/pbs_statjob.c */ /* routes to req_stat_job() in server/req_stat.c (PBS_BATCH_StatusJob) */ int main( int argc, /* I */ char **argv) /* I */ { int c; int errflg = 0; int any_failed = 0; extern char *optarg; char *conflict = "qstat: conflicting options.\n"; #if (TCL_QSTAT == 0) char *pc; #endif int located = FALSE; char option[3]; char job_id[PBS_MAXCLTJOBID]; char job_id_out[PBS_MAXCLTJOBID]; char server_out[MAXSERVERNAME]; char server_old[MAXSERVERNAME] = ""; char rmt_server[MAXSERVERNAME]; char destination[PBS_MAXDEST + 1]; char *def_server; char *queue_name_out; char *server_name_out; char *ExtendOpt = NULL; char operand[PBS_MAXCLTJOBID + 1]; int alt_opt; int f_opt, B_opt, Q_opt, t_opt, E_opt; int p_header = TRUE; int stat_single_job = 0; enum { JOBS, QUEUES, SERVERS } mode; struct batch_status *p_status; struct batch_status *p_server; struct attropl *p_atropl = 0; char *errmsg; int exec_only = 0; #ifndef mbool #define mbool char #endif /* !mbool */ #ifndef TRUE #define TRUE 1 #endif /* !TRUE */ #ifndef FALSE #define FALSE 0 #endif /* !FALSE */ #if !defined(PBS_NO_POSIX_VIOLATION) #define GETOPT_ARGS "aeE:filn1qrstu:xGMQRBW:-:" #else #define GETOPT_ARGS "flQBW:" #endif /* PBS_NO_POSIX_VIOLATION */ mode = JOBS; /* default */ alt_opt = 0; f_opt = 0; B_opt = 0; Q_opt = 0; t_opt = 0; E_opt = 0; tcl_init(); tcl_addarg(flags, argv[0]); option[0] = '-'; option[2] = '\0'; if (getenv("PBS_QSTAT_EXECONLY") != NULL) exec_only = 1; while ((c = getopt(argc, argv, GETOPT_ARGS)) != EOF) { option[1] = (char)c; tcl_addarg(flags, option); tcl_addarg(flags, optarg); switch (c) { #if !defined(PBS_NO_POSIX_VIOLATION) case '1': alt_opt |= ALT_DISPLAY_o; break; case 'a': alt_opt |= ALT_DISPLAY_a; break; case 'e': exec_only = 1; break; case 'E': if (optarg != NULL) { ExtendOpt = strdup(optarg); E_opt = TRUE; } break; case 'i': alt_opt |= ALT_DISPLAY_i; add_atropl(&p_atropl, ATTR_state, NULL, "EHQTW", EQ); break; case 'n': alt_opt |= ALT_DISPLAY_n; break; case 'q': alt_opt |= ALT_DISPLAY_q; mode = QUEUES; break; case 'r': alt_opt |= ALT_DISPLAY_r; add_atropl(&p_atropl, ATTR_state, NULL, "RS", EQ); break; case 's': alt_opt |= ALT_DISPLAY_s; break; case 't': t_opt = 1; break; case 'u': alt_opt |= ALT_DISPLAY_u; add_atropl(&p_atropl, ATTR_u, NULL, optarg, EQ); break; case 'R': alt_opt |= ALT_DISPLAY_R; break; case 'G': alt_opt |= ALT_DISPLAY_G; break; case 'M': alt_opt |= ALT_DISPLAY_Mw; break; #endif /* PBS_NO_POSIX_VIOLATION */ case 'f': if (alt_opt != 0) { fprintf(stderr, "%s", conflict); errflg++; } f_opt = 1; break; case 'x': DisplayXML = TRUE; break; case 'B': B_opt = 1; mode = SERVERS; if (Q_opt || alt_opt) { fprintf(stderr, "%s", conflict); errflg++; } break; case 'l': alias_opt = TRUE; break; case 'Q': Q_opt = 1; mode = QUEUES; if (B_opt || alt_opt) { fprintf(stderr, "%s", conflict); errflg++; } break; case '-': /* handle '--' options */ if ((optarg != NULL) && !strcmp(optarg, "version")) { fprintf(stderr, "version: %s\n", PACKAGE_VERSION); exit(0); } if ((optarg != NULL) && !strcmp(optarg, "about")) { TShowAbout(); exit(0); } /* unexpected '--' option received */ errflg = 1; break; case 'W': #if (TCL_QSTAT == 0) pc = optarg; while (*pc) { switch (*pc) { case 'a': alt_opt |= ALT_DISPLAY_a; break; case 'i': alt_opt |= ALT_DISPLAY_i; add_atropl(&p_atropl, ATTR_state, (char *)0, "EHQTW", EQ); break; case 'r': alt_opt |= ALT_DISPLAY_r; add_atropl(&p_atropl, ATTR_state, (char *)0, "RS", EQ); break; case 'u': /* note - u option is assumed to be last in */ /* string and all remaining is the name list */ alt_opt |= ALT_DISPLAY_u; while (*++pc == ' '); add_atropl(&p_atropl, ATTR_u, (char *)0, pc, EQ); pc = pc + strlen(pc) - 1; /* for the later incr */ break; case 'n': alt_opt |= ALT_DISPLAY_n; break; case 's': alt_opt |= ALT_DISPLAY_s; break; case 'q': alt_opt |= ALT_DISPLAY_q; mode = QUEUES; break; case 'R': alt_opt |= ALT_DISPLAY_R; break; case 'G': alt_opt |= ALT_DISPLAY_G; break; case 'M': alt_opt |= ALT_DISPLAY_Mw; break; case ' ': break; /* ignore blanks */ default: errflg++; } ++pc; } #endif /* (TCL_QSTAT == 0) */ break; case '?': default: /* unexpected argument */ errflg++; break; } /* END switch (c) */ } /* END while (c = getopt()) */ #if !defined(PBS_NO_POSIX_VIOLATION) /* certain combinations are not allowed */ c = alt_opt & (ALT_DISPLAY_a | ALT_DISPLAY_i | ALT_DISPLAY_r | ALT_DISPLAY_q); if ((c != 0) && (c != ALT_DISPLAY_a) && (c != ALT_DISPLAY_i) && (c != ALT_DISPLAY_r) && (c != ALT_DISPLAY_q)) { fprintf(stderr, "%s", conflict); errflg++; } c = alt_opt & (ALT_DISPLAY_Mw | ALT_DISPLAY_G); if (c == (ALT_DISPLAY_Mw | ALT_DISPLAY_G)) { fprintf(stderr, "%s", conflict); errflg++; } if ((alt_opt & ALT_DISPLAY_q) && (f_opt == 1)) { fprintf(stderr, "%s", conflict); errflg++; } if ((alt_opt & ALT_DISPLAY_o) && !((alt_opt & ALT_DISPLAY_n) || (f_opt))) { fprintf(stderr, "%s", conflict); errflg++; } if (alt_opt & ALT_DISPLAY_o) { linesize = maxlinesize; alt_opt &= ~ALT_DISPLAY_o; } #endif /* PBS_NO_POSIX_VIOLATION */ if (errflg) { static char usage[] = "usage: \n\ qstat [-f [-1]] [-W site_specific] [-x] [ job_identifier... | destination... ]\n\ qstat [-a|-i|-r|-e] [-u user] [-n [-1]] [-s] [-t] [-G|-M] [-R] [job_id... | destination...]\n\ qstat -Q [-f [-1]] [-W site_specific] [ destination... ]\n\ qstat -q [-G|-M] [ destination... ]\n\ qstat -B [-f [-1]] [-W site_specific] [ server_name... ]\n\ qstat -t\n"; fprintf(stderr,"%s", usage); exit(2); } if (!t_opt && !E_opt && !exec_only) { ExtendOpt = summarize_arrays_extend_opt; } def_server = pbs_default(); if (def_server == NULL) def_server = ""; if (optind >= argc) { /* If no arguments, then set defaults */ switch (mode) { case JOBS: server_out[0] = '@'; strcpy(&server_out[1], def_server); tcl_addarg(ops, server_out); job_id_out[0] = '\0'; server_out[0] = '\0'; goto job_no_args; /*NOTREACHED*/ break; case QUEUES: server_out[0] = '@'; strcpy(&server_out[1], def_server); tcl_addarg(ops, server_out); queue_name_out = NULL; server_out[0] = '\0'; goto que_no_args; /*NOTREACHED*/ break; case SERVERS: tcl_addarg(ops, def_server); server_out[0] = '\0'; goto svr_no_args; /*NOTREACHED*/ break; default: /* NO-OP */ break; } } /* END if (optind >= argc) */ for (;optind < argc;optind++) { int connect; int ret; located = FALSE; strcpy(operand, argv[optind]); tcl_addarg(ops, operand); switch (mode) { case JOBS: /* get status of batch jobs */ if (isjobid(operand)) { /* must be a job-id */ stat_single_job = 1; strcpy(job_id, operand); if (get_server(job_id, job_id_out, server_out)) { fprintf(stderr, "qstat: illegally formed job identifier: %s\n", job_id); ret = tcl_stat(error, NULL, f_opt); any_failed = 1; break; } } else { /* must be a destination-id */ stat_single_job = 0; strcpy(destination, operand); if (parse_destination_id( destination, &queue_name_out, &server_name_out)) { fprintf(stderr, "qstat: illegally formed destination: %s\n", destination); ret = tcl_stat(error, NULL, f_opt); any_failed = 1; break; } if (notNULL(server_name_out)) { strcpy(server_out, server_name_out); } else { server_out[0] = '\0'; } strcpy(job_id_out, queue_name_out); if (*queue_name_out != '\0') { add_atropl(&p_atropl, ATTR_q, NULL, queue_name_out, EQ); } } /* END else */ job_no_args: connect = cnt2server(server_out); if (connect <= 0) { fprintf(stderr, "qstat: cannot connect to server %s (errno=%d) %s\n", pbs_server, pbs_errno, pbs_strerror(pbs_errno)); ret = tcl_stat(error, NULL, f_opt); any_failed = connect; break; } if ((alt_opt != 0) && (strcmp(pbs_server, server_old) != 0)) { /* changing to a different server */ p_server = pbs_statserver(connect, NULL, NULL); strcpy(server_old, pbs_server); } else { p_server = 0; } if ((stat_single_job == 1) || (p_atropl == 0)) { p_status = pbs_statjob( connect, job_id_out, NULL, exec_only ? EXECQUEONLY : ExtendOpt); } else { if (t_opt) { p_status = pbs_selstat(connect, p_atropl, exec_only ? EXECQUEONLY : NULL); } else { p_status = pbs_selstat(connect, p_atropl, exec_only ? EXECQUEONLY : summarize_arrays_extend_opt); } } if (p_status == NULL) { if ((pbs_errno == PBSE_UNKJOBID) && !located) { located = TRUE; if (locate_job(job_id_out, server_out, rmt_server)) { pbs_disconnect(connect); strcpy(server_out, rmt_server); goto job_no_args; } ret = tcl_stat("job", NULL, f_opt); prt_job_err("qstat", connect, job_id_out); any_failed = pbs_errno; } else { ret = tcl_stat("job", NULL, f_opt); if (pbs_errno != PBSE_NONE) { prt_job_err("qstat", connect, job_id_out); any_failed = pbs_errno; } } } else { if (alt_opt != 0) { altdsp_statjob(p_status, p_server, alt_opt); } else if ((f_opt == 0) || tcl_stat("job", p_status, f_opt)) { display_statjob(p_status, p_header, f_opt); } p_header = FALSE; pbs_statfree(p_status); } pbs_disconnect(connect); break; case QUEUES: /* get status of batch queues */ strcpy(destination, operand); if (parse_destination_id(destination, &queue_name_out, &server_name_out)) { fprintf(stderr, "qstat: illegal 'destination' value\n"); ret = tcl_stat(error, NULL, f_opt); any_failed = 1; break; } else { if (notNULL(server_name_out)) { strcpy(server_out, server_name_out); } else server_out[0] = '\0'; } que_no_args: connect = cnt2server(server_out); if (connect <= 0) { fprintf(stderr, "qstat: cannot connect to server %s (errno=%d) %s\n", pbs_server, pbs_errno, pbs_strerror(pbs_errno)); ret = tcl_stat(error, NULL, f_opt); any_failed = connect; break; } p_status = pbs_statque(connect, queue_name_out, NULL, NULL); if (p_status == NULL) { if (pbs_errno) { errmsg = pbs_geterrmsg(connect); if (errmsg != NULL) { fprintf(stderr, "qstat: %s ", errmsg); } else fprintf(stderr, "qstat: Error (%d - %s) getting status of queue ", pbs_errno, pbs_strerror(pbs_errno)); fprintf(stderr, "%s\n", queue_name_out); ret = tcl_stat(error, NULL, f_opt); any_failed = pbs_errno; } } else { if (alt_opt & ALT_DISPLAY_q) { altdsp_statque(pbs_server, p_status, alt_opt); } else if (tcl_stat("queue", p_status, f_opt)) { display_statque(p_status, p_header, f_opt); } p_header = FALSE; pbs_statfree(p_status); } pbs_disconnect(connect); break; case SERVERS: /* get status of batch servers */ strcpy(server_out, operand); svr_no_args: connect = cnt2server(server_out); if (connect <= 0) { fprintf(stderr, "qstat: cannot connect to server %s (errno=%d) %s\n", pbs_server, pbs_errno, pbs_strerror(pbs_errno)); ret = tcl_stat(error, NULL, f_opt); any_failed = connect; break; } p_status = pbs_statserver(connect, NULL, NULL); if (p_status == NULL) { if (pbs_errno) { errmsg = pbs_geterrmsg(connect); if (errmsg != NULL) { fprintf(stderr, "qstat: %s ", errmsg); } else fprintf(stderr, "qstat: Error (%d - %s) getting status of server ", pbs_errno, pbs_strerror(pbs_errno)); fprintf(stderr, "%s\n", server_out); ret = tcl_stat(error, NULL, f_opt); any_failed = pbs_errno; } } else { if (tcl_stat("server", p_status, f_opt)) display_statserver(p_status, p_header, f_opt); p_header = FALSE; pbs_statfree(p_status); } pbs_disconnect(connect); break; } /* END switch (mode) */ } /* END for () */ tcl_run(f_opt); exit(any_failed); } /* END main() */