diff --git a/NEWS b/NEWS index 8297d66d6f2999d7d429409e5654f6dbb0125b20..9e91621fbcd79e22453c82ca85ceb58ed23a25c9 100644 --- a/NEWS +++ b/NEWS @@ -59,6 +59,8 @@ documents those changes that are of interest to users and admins. -- Changed getpwent to getpwent_r in the slurmctld and slurmd -- Increase timeout on most slurmdbd communications to 60 secs (time for substantial database updates). + -- Treat srun option of --begin= with a value of now without a numeric + component as a failure (e.g. "--begin=now+hours"). * Changes in SLURM 1.3.6 ======================== @@ -477,6 +479,7 @@ documents those changes that are of interest to users and admins. -- For PMI only (MPICH2/MVAPICH2) base address to send messages to (the srun) upon the address from which slurmd gets the task launch request rather then "hostname" where srun executes. + -- Make test for StateSaveLocation directory more comprehensive. * Changes in SLURM 1.2.33 ========================= diff --git a/auxdir/x_ac_gtk.m4 b/auxdir/x_ac_gtk.m4 index ecdf3cf47504c54fe7a24737577a19d1718d1322..7ab71b2d081362073e49fcafb46ace4be1fd5aad 100644 --- a/auxdir/x_ac_gtk.m4 +++ b/auxdir/x_ac_gtk.m4 @@ -46,7 +46,7 @@ AC_DEFUN([X_AC_GTK], # fi -### Check for gtk2.6 package +### Check for gtk2.7.1 package if test "$ac_have_gtk" == "yes" ; then $HAVEPKGCONFIG --exists gtk+-2.0 if ! test $? -eq 0 ; then @@ -60,8 +60,8 @@ AC_DEFUN([X_AC_GTK], gtk_config_micro_version=`$HAVEPKGCONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` - if test $gtk_config_major_version -lt 2 || test $gtk_config_minor_version -lt 6 ; then - AC_MSG_WARN([*** gtk+-$gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version available, we need >= gtk+-2.6.0 installed for sview.]) + if test $gtk_config_major_version -lt 2 || test $gtk_config_minor_version -lt 7 || test $gtk_config_micro_version -lt 1; then + AC_MSG_WARN([*** gtk+-$gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version available, we need >= gtk+-2.7.1 installed for sview.]) ac_have_gtk="no" fi fi diff --git a/configure b/configure index 67d4bfd2c48ce3300699c7e6278d9b2734c77adb..00ef5f35adfa7d27dc85c7820cfe319b4da50222 100755 --- a/configure +++ b/configure @@ -25271,7 +25271,7 @@ echo "$as_me: WARNING: *** pkg-config not found. Cannot probe for libglade-2.0 o # fi -### Check for gtk2.6 package +### Check for gtk2.8 package if test "$ac_have_gtk" == "yes" ; then $HAVEPKGCONFIG --exists gtk+-2.0 if ! test $? -eq 0 ; then @@ -25286,9 +25286,9 @@ echo "$as_me: WARNING: *** gtk+-2.0 is not available." >&2;} gtk_config_micro_version=`$HAVEPKGCONFIG --modversion gtk+-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` - if test $gtk_config_major_version -lt 2 || test $gtk_config_minor_version -lt 6 ; then - { echo "$as_me:$LINENO: WARNING: *** gtk+-$gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version available, we need >= gtk+-2.6.0 installed for sview." >&5 -echo "$as_me: WARNING: *** gtk+-$gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version available, we need >= gtk+-2.6.0 installed for sview." >&2;} + if test $gtk_config_major_version -lt 2 || test $gtk_config_minor_version -lt 7 || test $gtk_config_micro_version -lt 1; then + { echo "$as_me:$LINENO: WARNING: *** gtk+-$gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version available, we need >= gtk+-2.7.1 installed for sview." >&5 +echo "$as_me: WARNING: *** gtk+-$gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version available, we need >= gtk+-2.7.1 installed for sview." >&2;} ac_have_gtk="no" fi fi diff --git a/doc/man/man1/sacctmgr.1 b/doc/man/man1/sacctmgr.1 index 383728ed253c081a5c59b63f79c0b5de4e43ea6f..94947cebb5afd592e170ff05650e77d0aba326ec 100644 --- a/doc/man/man1/sacctmgr.1 +++ b/doc/man/man1/sacctmgr.1 @@ -45,13 +45,22 @@ This is equivalent to the \fBoneliner\fR command. .TP \fB\-p\fR, \fB\-\-parsable\fR -Output will be '|' delimited. +Output will be '|' delimited with a '|' at the end. + +.TP +\fB\-P\fR, \fB\-\-parsable2\fR +Output will be '|' delimited without a '|' at the end. .TP \fB\-q\fR, \fB\-\-quiet\fR Print no messages other than error messages. This is equivalent to the \fBquiet\fR command. +.TP +\fB\-r\fR, \fB\-\-readonly\fR +Makes it so the running sacctmgr can not modify accounting information. +This is equivalent to the \fBreadonly\fR command. + .TP \fB\-s\fR, \fB\-\-associations\fR Use with show or list to display associations with the entity. diff --git a/doc/man/man1/sreport.1 b/doc/man/man1/sreport.1 index ac0d0b7d575c4618ebffa378daa052d22ea33a1c..e07f8c0cf474e049622441c7162e168c67dba5a3 100644 --- a/doc/man/man1/sreport.1 +++ b/doc/man/man1/sreport.1 @@ -33,7 +33,11 @@ This is equivalent to the \fBquiet\fR command. .TP \fB\-p\fR, \fB\-\-parsable\fR -Make output '|' delimited. +Output will be '|' delimited with a '|' at the end. + +.TP +\fB\-P\fR, \fB\-\-parsable2\fR +Output will be '|' delimited without a '|' at the end. .TP \fB\-v\fR, \fB\-\-verbose\fR diff --git a/src/common/parse_time.c b/src/common/parse_time.c index e72f2c93e455f3e69936a8bac89ad03e9ddcda9f..33c0e7f42b7c09351f5a0d77d965660ca027742d 100644 --- a/src/common/parse_time.c +++ b/src/common/parse_time.c @@ -60,6 +60,7 @@ static int _get_delta(char *time_str, int *pos, long *delta) { int offset; long cnt = 0; + int digit = 0; offset = (*pos) + 1; for ( ; ((time_str[offset]!='\0')&&(time_str[offset]!='\n')); offset++) { @@ -87,10 +88,15 @@ static int _get_delta(char *time_str, int *pos, long *delta) } if ((time_str[offset] >= '0') && (time_str[offset] <= '9')) { cnt = (cnt * 10) + (time_str[offset] - '0'); + digit++; continue; } goto prob; } + + if (!digit) /* No numbers after the '=' */ + return -1; + *pos = offset - 1; *delta = cnt; return 0; diff --git a/src/common/print_fields.c b/src/common/print_fields.c index cb5d3ed858ee86d58160686406ba45c4dec099d8..e95864f0651d030ea372ee984942d9a069a3d4c3 100644 --- a/src/common/print_fields.c +++ b/src/common/print_fields.c @@ -67,16 +67,24 @@ extern void print_fields_header(List print_fields_list) { ListIterator itr = NULL; print_field_t *field = NULL; - + int curr_inx = 1; + int field_count = 0; if(!print_fields_list || !print_fields_have_header) return; + field_count = list_count(print_fields_list); + itr = list_iterator_create(print_fields_list); while((field = list_next(itr))) { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && (curr_inx == field_count)) + printf("%s", field->name); + else if(print_fields_parsable_print) printf("%s|", field->name); else printf("%-*.*s ", field->len, field->len, field->name); + curr_inx++; } list_iterator_reset(itr); printf("\n"); @@ -90,7 +98,7 @@ extern void print_fields_header(List print_fields_list) printf("\n"); } -extern void print_fields_date(print_field_t *field, time_t value) +extern void print_fields_date(print_field_t *field, time_t value, int last) { char temp_char[field->len]; time_t now = value; @@ -98,13 +106,16 @@ extern void print_fields_date(print_field_t *field, time_t value) if(!now) now = time(NULL); slurm_make_time_str(&value, (char *)temp_char, field->len); - if(print_fields_parsable_print) + if(print_fields_parsable_print == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", temp_char); + else if(print_fields_parsable_print) printf("%s|", temp_char); else printf("%-*.*s ", field->len, field->len, temp_char); } -extern void print_fields_str(print_field_t *field, char *value) +extern void print_fields_str(print_field_t *field, char *value, int last) { char temp_char[field->len]; char *print_this = NULL; @@ -116,7 +127,10 @@ extern void print_fields_str(print_field_t *field, char *value) print_this = " "; } - if(print_fields_parsable_print) + if(print_fields_parsable_print == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", value); + else if(print_fields_parsable_print) printf("%s|", value); else { if(!print_this) { @@ -130,32 +144,48 @@ extern void print_fields_str(print_field_t *field, char *value) } } -extern void print_fields_uint32(print_field_t *field, uint32_t value) +extern void print_fields_uint32(print_field_t *field, uint32_t value, int last) { /* (value == unset) || (value == cleared) */ if((value == NO_VAL) || (value == INFINITE)) { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + ; + else if(print_fields_parsable_print) printf("|"); else printf("%*s ", field->len, " "); } else { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%u", value); + else if(print_fields_parsable_print) printf("%u|", value); else printf("%*u ", field->len, value); } } -extern void print_fields_uint64(print_field_t *field, uint64_t value) +extern void print_fields_uint64(print_field_t *field, uint64_t value, int last) { /* (value == unset) || (value == cleared) */ if((value == NO_VAL) || (value == INFINITE)) { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + ; + else if(print_fields_parsable_print) printf("|"); else printf("%*s ", field->len, " "); } else { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%llu", (long long unsigned) value); + else if(print_fields_parsable_print) printf("%llu|", (long long unsigned) value); else printf("%*llu ", field->len, @@ -163,25 +193,33 @@ extern void print_fields_uint64(print_field_t *field, uint64_t value) } } -extern void print_fields_time(print_field_t *field, uint32_t value) +extern void print_fields_time(print_field_t *field, uint32_t value, int last) { /* (value == unset) || (value == cleared) */ if((value == NO_VAL) || (value == INFINITE)) { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + ; + else if(print_fields_parsable_print) printf("|"); else printf("%*s ", field->len, " "); } else { char time_buf[32]; mins2time_str((time_t) value, time_buf, sizeof(time_buf)); - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", time_buf); + else if(print_fields_parsable_print) printf("%s|", time_buf); else printf("%*s ", field->len, time_buf); } } -extern void print_fields_char_list(print_field_t *field, List value) +extern void print_fields_char_list(print_field_t *field, List value, int last) { ListIterator itr = NULL; char *print_this = NULL; @@ -204,7 +242,10 @@ extern void print_fields_char_list(print_field_t *field, List value) list_iterator_destroy(itr); } - if(print_fields_parsable_print) + if(print_fields_parsable_print == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", print_this); + else if(print_fields_parsable_print) printf("%s|", print_this); else { if(strlen(print_this) > field->len) diff --git a/src/common/print_fields.h b/src/common/print_fields.h index 37ade380f5e27b6327168cacc60d5ef60ec30bc3..36eed4add7d8a55b48a30c0b67c1f897a5fb81bc 100644 --- a/src/common/print_fields.h +++ b/src/common/print_fields.h @@ -74,17 +74,25 @@ typedef struct { uint16_t type; /* defined in the local function */ } print_field_t; +enum { + PRINT_FIELDS_PARSABLE_NOT = 0, + PRINT_FIELDS_PARSABLE_ENDING, + PRINT_FIELDS_PARSABLE_NO_ENDING +}; + extern int print_fields_parsable_print; extern int print_fields_have_header; extern void destroy_print_field(void *object); extern void print_fields_header(List print_fields_list); -extern void print_fields_date(print_field_t *field, time_t value); -extern void print_fields_str(print_field_t *field, char *value); -extern void print_fields_uint32(print_field_t *field, uint32_t value); -extern void print_fields_uint64(print_field_t *field, uint64_t value); -extern void print_fields_time(print_field_t *field, uint32_t value); -extern void print_fields_char_list(print_field_t *field, List value); +extern void print_fields_date(print_field_t *field, time_t value, int last); +extern void print_fields_str(print_field_t *field, char *value, int last); +extern void print_fields_uint32( + print_field_t *field, uint32_t value, int last); +extern void print_fields_uint64( + print_field_t *field, uint64_t value, int last); +extern void print_fields_time(print_field_t *field, uint32_t value, int last); +extern void print_fields_char_list(print_field_t *field, List value, int last); #define print_fields_uint print_fields_uint32 #endif diff --git a/src/common/slurm_accounting_storage.c b/src/common/slurm_accounting_storage.c index 6265ce45ab20deb7f55f8499d0e5a21b33c85447..fdac0c483ea238ad58f545d40c6ef7d500f148ac 100644 --- a/src/common/slurm_accounting_storage.c +++ b/src/common/slurm_accounting_storage.c @@ -2322,39 +2322,39 @@ extern acct_admin_level_t str_2_acct_admin_level(char *level) extern void log_assoc_rec(acct_association_rec_t *assoc_ptr) { - debug("association rec id : %u", assoc_ptr->id); - debug(" acct : %s", assoc_ptr->acct); - debug(" cluster : %s", assoc_ptr->cluster); + debug2("association rec id : %u", assoc_ptr->id); + debug2(" acct : %s", assoc_ptr->acct); + debug2(" cluster : %s", assoc_ptr->cluster); if(assoc_ptr->fairshare == INFINITE) - debug(" fairshare : NONE"); + debug2(" fairshare : NONE"); else - debug(" fairshare : %u", - assoc_ptr->fairshare); + debug2(" fairshare : %u", + assoc_ptr->fairshare); if(assoc_ptr->max_cpu_secs_per_job == INFINITE) - debug(" max_cpu_secs_per_job : NONE"); + debug2(" max_cpu_secs_per_job : NONE"); else - debug(" max_cpu_secs_per_job : %d", - assoc_ptr->max_cpu_secs_per_job); + debug2(" max_cpu_secs_per_job : %d", + assoc_ptr->max_cpu_secs_per_job); if(assoc_ptr->max_jobs == INFINITE) - debug(" max_jobs : NONE"); + debug2(" max_jobs : NONE"); else - debug(" max_jobs : %u", assoc_ptr->max_jobs); + debug2(" max_jobs : %u", assoc_ptr->max_jobs); if(assoc_ptr->max_nodes_per_job == INFINITE) - debug(" max_nodes_per_job : NONE"); + debug2(" max_nodes_per_job : NONE"); else - debug(" max_nodes_per_job : %d", - assoc_ptr->max_nodes_per_job); + debug2(" max_nodes_per_job : %d", + assoc_ptr->max_nodes_per_job); if(assoc_ptr->max_wall_duration_per_job == INFINITE) - debug(" max_wall_duration_per_job : NONE"); + debug2(" max_wall_duration_per_job : NONE"); else - debug(" max_wall_duration_per_job : %d", - assoc_ptr->max_wall_duration_per_job); - debug(" parent_acct : %s", assoc_ptr->parent_acct); - debug(" partition : %s", assoc_ptr->partition); - debug(" user : %s(%u)", - assoc_ptr->user, assoc_ptr->uid); - debug(" used_jobs : %u", assoc_ptr->used_jobs); - debug(" used_share : %u", assoc_ptr->used_share); + debug2(" max_wall_duration_per_job : %d", + assoc_ptr->max_wall_duration_per_job); + debug2(" parent_acct : %s", assoc_ptr->parent_acct); + debug2(" partition : %s", assoc_ptr->partition); + debug2(" user : %s(%u)", + assoc_ptr->user, assoc_ptr->uid); + debug2(" used_jobs : %u", assoc_ptr->used_jobs); + debug2(" used_share : %u", assoc_ptr->used_share); } /* diff --git a/src/common/uid.c b/src/common/uid.c index 8a1838ce9d0bafa9695e1579df00958fedda8fe8..f6b38b37bd31d8672283da4b7d94fb40f851d718 100644 --- a/src/common/uid.c +++ b/src/common/uid.c @@ -49,16 +49,14 @@ uid_t uid_from_string (char *name) { struct passwd pwd, *result; - size_t bufsize; - char *buffer, *p = NULL; + char buffer[PW_BUF_SIZE], *p = NULL; int rc; uid_t uid = (uid_t) strtoul (name, &p, 10); - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - buffer = xmalloc(bufsize); if (*p != '\0') { while (1) { - rc = getpwnam_r(name, &pwd, buffer, bufsize, &result); + rc = getpwnam_r(name, &pwd, buffer, PW_BUF_SIZE, + &result); if (rc == EINTR) continue; if (rc != 0) @@ -71,7 +69,8 @@ uid_from_string (char *name) uid = result->pw_uid; } else { while (1) { - rc = getpwuid_r(uid, &pwd, buffer, bufsize, &result); + rc = getpwuid_r(uid, &pwd, buffer, PW_BUF_SIZE, + &result); if (rc == EINTR) continue; if (rc != 0) @@ -82,7 +81,6 @@ uid_from_string (char *name) uid = (uid_t) -1; /* else uid is already correct */ } - xfree(buffer); return uid; } @@ -90,18 +88,15 @@ char * uid_to_string (uid_t uid) { struct passwd pwd, *result; - size_t bufsize; - char *buffer, *ustring; + char buffer[PW_BUF_SIZE], *ustring; int rc; /* Suse Linux does not handle multiple users with UID=0 well */ if (uid == 0) return xstrdup("root"); - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - buffer = xmalloc(bufsize); while (1) { - rc = getpwuid_r(uid, &pwd, buffer, bufsize, &result); + rc = getpwuid_r(uid, &pwd, buffer, PW_BUF_SIZE, &result); if (rc == EINTR) continue; if (rc != 0) @@ -112,7 +107,6 @@ uid_to_string (uid_t uid) ustring = xstrdup(result->pw_name); else ustring = xstrdup("nobody"); - xfree(buffer); return ustring; } @@ -120,16 +114,14 @@ gid_t gid_from_string (char *name) { struct group grp, *result; - size_t bufsize; - char *buffer, *p = NULL; + char buffer[PW_BUF_SIZE], *p = NULL; int rc; gid_t gid = (gid_t) strtoul (name, &p, 10); - bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); - buffer = xmalloc(bufsize); if (*p != '\0') { while (1) { - rc = getgrnam_r(name, &grp, buffer, bufsize, &result); + rc = getgrnam_r(name, &grp, buffer, PW_BUF_SIZE, + &result); if (rc == EINTR) continue; if (rc != 0) @@ -142,7 +134,8 @@ gid_from_string (char *name) gid = result->gr_gid; } else { while (1) { - rc = getgrgid_r(gid, &grp, buffer, bufsize, &result); + rc = getgrgid_r(gid, &grp, buffer, PW_BUF_SIZE, + &result); if (rc == EINTR) continue; if (rc != 0) @@ -153,7 +146,6 @@ gid_from_string (char *name) gid = (gid_t) -1; /* else gid is already correct */ } - xfree(buffer); return gid; } @@ -161,14 +153,11 @@ char * gid_to_string (gid_t gid) { struct group grp, *result; - size_t bufsize; - char *buffer, *gstring; + char buffer[PW_BUF_SIZE], *gstring; int rc; - bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); - buffer = xmalloc(bufsize); while (1) { - rc = getgrgid_r(gid, &grp, buffer, bufsize, &result); + rc = getgrgid_r(gid, &grp, buffer, PW_BUF_SIZE, &result); if (rc == EINTR) continue; if (rc != 0) @@ -179,6 +168,5 @@ gid_to_string (gid_t gid) gstring = xstrdup(result->gr_name); else gstring = xstrdup("nobody"); - xfree(buffer); return gstring; } diff --git a/src/common/uid.h b/src/common/uid.h index 91e5d9a9f449fcd36f8e74da261c5047df894dd0..0779a711f8a37bf0d46e6f3d14a1d3f3996c46a6 100644 --- a/src/common/uid.h +++ b/src/common/uid.h @@ -42,6 +42,14 @@ #include <sys/types.h> #include <unistd.h> +/* + * In an ideal world, we could use sysconf(_SC_GETPW_R_SIZE_MAX) to get the + * maximum buffer size neede for getpwnam_r(), but if there is no maximum + * value configured, the value returned is 1024, which can too small. + * Diito for _SC_GETGR_R_SIZE_MAX. Use 64k byte buffer by default. + */ +#define PW_BUF_SIZE 65536 + /* * Return validated uid_t for string in ``name'' which contains * either the UID number or user name diff --git a/src/plugins/accounting_storage/filetxt/accounting_storage_filetxt.c b/src/plugins/accounting_storage/filetxt/accounting_storage_filetxt.c index 22c52c03330edf32655b3884420c73a264d47931..fff6191be6e44f4316064714b9fcf967e206bedd 100644 --- a/src/plugins/accounting_storage/filetxt/accounting_storage_filetxt.c +++ b/src/plugins/accounting_storage/filetxt/accounting_storage_filetxt.c @@ -186,7 +186,12 @@ extern int init ( void ) "Please use a database plugin"); } - if(first) { + /* This check for the slurm user id is a quick and dirty patch + * to see if the controller is calling this, since we open the + * file in append mode sacct could fail on it if the file + * isn't world writable. + */ + if(first && (getuid() == slurm_get_slurm_user_id())) { debug2("jobacct_init() called"); log_file = slurm_get_accounting_storage_loc(); if(!log_file) diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c index c6b95f1afa3f26019b7b20170fac25f08ba02c33..095e3fe2f555f2ec3f5e13214913836bca9d4a34 100644 --- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c +++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c @@ -5641,7 +5641,8 @@ empty: assoc_table, row[ASSOC_REQ_ACCT], row[ASSOC_REQ_CLUSTER], without_parent_limits); - + debug4("%d(%d) query\n%s", + mysql_conn->conn, __LINE__, query); if(!(result2 = mysql_db_query_ret( mysql_conn->db_conn, query, 1))) { xfree(query); @@ -5661,7 +5662,7 @@ empty: parent_mnpj = atoi(row2[ASSOC2_REQ_MNPJ]); else - parent_mwpj = INFINITE; + parent_mnpj = INFINITE; if(row2[ASSOC2_REQ_MWPJ]) parent_mwpj = diff --git a/src/sacctmgr/account_functions.c b/src/sacctmgr/account_functions.c index 65dc397cec72a3ce0e4da557cf107de14f1d610e..068ee3ecc79af7b567e15f57abc036b6276f81f1 100644 --- a/src/sacctmgr/account_functions.c +++ b/src/sacctmgr/account_functions.c @@ -84,7 +84,7 @@ static int _set_cond(int *start, int argc, char *argv[], } if(slurm_addto_char_list( acct_cond->assoc_cond->acct_list, - argv[i]+end)) + argv[i]+end)) u_set = 1; } else if (!strncasecmp (argv[i], "Clusters", 1)) { if(!acct_cond->assoc_cond->cluster_list) { @@ -706,6 +706,8 @@ extern int sacctmgr_list_account(int argc, char *argv[]) char *object; List qos_list = NULL; + int field_count = 0; + print_field_t *field = NULL; List format_list = list_create(slurm_destroy_char); @@ -755,7 +757,8 @@ extern int sacctmgr_list_account(int argc, char *argv[]) itr = list_iterator_create(format_list); while((object = list_next(itr))) { field = xmalloc(sizeof(print_field_t)); - if(!strncasecmp("Account", object, 1)) { + if(!strncasecmp("Account", object, 1) + || !strncasecmp("Name", object, 2)) { field->type = PRINT_ACCOUNT; field->name = xstrdup("Account"); field->len = 10; @@ -866,65 +869,90 @@ extern int sacctmgr_list_account(int argc, char *argv[]) itr2 = list_iterator_create(print_fields_list); print_fields_header(print_fields_list); + field_count = list_count(print_fields_list); + while((acct = list_next(itr))) { if(acct->assoc_list && list_count(acct->assoc_list)) { ListIterator itr3 = list_iterator_create(acct->assoc_list); while((assoc = list_next(itr3))) { + int curr_inx = 1; while((field = list_next(itr2))) { switch(field->type) { case PRINT_ACCOUNT: field->print_routine( - field, acct->name); + field, acct->name, + (curr_inx == + field_count)); break; case PRINT_CLUSTER: field->print_routine( - field, assoc->cluster); + field, assoc->cluster, + (curr_inx == + field_count)); break; case PRINT_COORDS: field->print_routine( field, - acct->coordinators); + acct->coordinators, + (curr_inx == + field_count)); break; case PRINT_DESC: field->print_routine( field, - acct->description); + acct->description, + (curr_inx == + field_count)); break; case PRINT_FAIRSHARE: field->print_routine( field, - assoc->fairshare); + assoc->fairshare, + (curr_inx == + field_count)); break; case PRINT_ID: field->print_routine( - field, assoc->id); + field, assoc->id, + (curr_inx == + field_count)); break; case PRINT_MAXC: field->print_routine( field, assoc-> - max_cpu_secs_per_job); + max_cpu_secs_per_job, + (curr_inx == + field_count)); break; case PRINT_MAXJ: field->print_routine( - field, assoc->max_jobs); + field, assoc->max_jobs, + (curr_inx == + field_count)); break; case PRINT_MAXN: field->print_routine( field, assoc-> - max_nodes_per_job); + max_nodes_per_job, + (curr_inx == + field_count)); break; case PRINT_MAXW: field->print_routine( field, assoc-> - max_wall_duration_per_job); + max_wall_duration_per_job, + (curr_inx == + field_count)); break; case PRINT_ORG: field->print_routine( field, - acct->organization); + acct->organization, + (curr_inx == + field_count)); break; case PRINT_QOS: if(!qos_list) { @@ -936,7 +964,9 @@ extern int sacctmgr_list_account(int argc, char *argv[]) field->print_routine( field, qos_list, - acct->qos_list); + acct->qos_list, + (curr_inx == + field_count)); break; case PRINT_QOS_RAW: if(!qos_list) { @@ -948,82 +978,116 @@ extern int sacctmgr_list_account(int argc, char *argv[]) field->print_routine( field, qos_list, - acct->qos_list); + acct->qos_list, + (curr_inx == + field_count)); break; case PRINT_PID: field->print_routine( field, - assoc->parent_id); + assoc->parent_id, + (curr_inx == + field_count)); break; case PRINT_PNAME: field->print_routine( field, - assoc->parent_acct); + assoc->parent_acct, + (curr_inx == + field_count)); break; case PRINT_PART: field->print_routine( field, - assoc->partition); + assoc->partition, + (curr_inx == + field_count)); break; case PRINT_USER: field->print_routine( - field, assoc->user); + field, assoc->user, + (curr_inx == + field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); } list_iterator_destroy(itr3); } else { + int curr_inx = 1; while((field = list_next(itr2))) { switch(field->type) { case PRINT_ACCOUNT: field->print_routine( - field, acct->name); + field, acct->name, + (curr_inx == + field_count)); break; case PRINT_CLUSTER: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_COORDS: field->print_routine( field, - acct->coordinators); + acct->coordinators, + (curr_inx == + field_count)); break; case PRINT_DESC: field->print_routine( - field, acct->description); + field, acct->description, + (curr_inx == + field_count)); break; case PRINT_FAIRSHARE: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_ID: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_MAXC: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_MAXJ: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_MAXN: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_MAXW: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_ORG: field->print_routine( - field, acct->organization); + field, acct->organization, + (curr_inx == + field_count)); break; case PRINT_QOS: if(!qos_list) { @@ -1034,7 +1098,9 @@ extern int sacctmgr_list_account(int argc, char *argv[]) } field->print_routine( field, qos_list, - acct->qos_list); + acct->qos_list, + (curr_inx == + field_count)); break; case PRINT_QOS_RAW: if(!qos_list) { @@ -1045,27 +1111,38 @@ extern int sacctmgr_list_account(int argc, char *argv[]) } field->print_routine( field, qos_list, - acct->qos_list); + acct->qos_list, + (curr_inx == + field_count)); break; case PRINT_PID: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_PNAME: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_PART: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; case PRINT_USER: field->print_routine( - field, NULL); + field, NULL, + (curr_inx == + field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); @@ -1164,14 +1241,6 @@ extern int sacctmgr_modify_account(int argc, char *argv[]) assoc_start: if(rec_set == 3 || rec_set == 2) { // process the association changes - if(cond_set == 1) { - exit_code=1; - fprintf(stderr, - " There was a problem with your " - "'where' options.\n"); - rc = SLURM_ERROR; - goto assoc_end; - } ret_list = acct_storage_g_modify_associations( db_conn, my_uid, acct_cond->assoc_cond, assoc); @@ -1196,7 +1265,6 @@ assoc_start: list_destroy(ret_list); } -assoc_end: notice_thread_fini(); if(set) { if(commit_check("Would you like to commit changes?")) @@ -1258,7 +1326,7 @@ extern int sacctmgr_delete_account(int argc, char *argv[]) if(set == 1) { ret_list = acct_storage_g_remove_accounts( db_conn, my_uid, acct_cond); - } else if(set == 2) { + } else if(set == 2 || set == 3) { ret_list = acct_storage_g_remove_associations( db_conn, my_uid, acct_cond->assoc_cond); } @@ -1270,7 +1338,7 @@ extern int sacctmgr_delete_account(int argc, char *argv[]) ListIterator itr = list_iterator_create(ret_list); if(set == 1) { printf(" Deleting accounts...\n"); - } else if(set == 2) { + } else if(set == 2 || set == 3) { printf(" Deleting account associations...\n"); } while((object = list_next(itr))) { diff --git a/src/sacctmgr/cluster_functions.c b/src/sacctmgr/cluster_functions.c index 3a39ddb3211c33b77298c6968c7f36b4140c7f54..1eeea8540b9aa393468e6af719725c8795094fbe 100644 --- a/src/sacctmgr/cluster_functions.c +++ b/src/sacctmgr/cluster_functions.c @@ -54,7 +54,8 @@ static int _set_cond(int *start, int argc, char *argv[], break; } else if(!end && !strncasecmp(argv[i], "where", 5)) { continue; - } else if(!end || !strncasecmp (argv[i], "Names", 1)) { + } else if(!end || !strncasecmp (argv[i], "Names", 1) + || !strncasecmp (argv[i], "Clusters", 1)) { if(cluster_list) { if(slurm_addto_char_list(cluster_list, argv[i]+end)) @@ -329,6 +330,8 @@ extern int sacctmgr_list_cluster(int argc, char *argv[]) acct_cluster_rec_t *cluster = NULL; char *object; + int field_count = 0; + print_field_t *field = NULL; List format_list = list_create(slurm_destroy_char); @@ -365,7 +368,8 @@ extern int sacctmgr_list_cluster(int argc, char *argv[]) itr = list_iterator_create(format_list); while((object = list_next(itr))) { field = xmalloc(sizeof(print_field_t)); - if(!strncasecmp("Cluster", object, 2)) { + if(!strncasecmp("Cluster", object, 2) + || !strncasecmp("Name", object, 2)) { field->type = PRINT_CLUSTER; field->name = xstrdup("Cluster"); field->len = 10; @@ -436,50 +440,62 @@ extern int sacctmgr_list_cluster(int argc, char *argv[]) itr2 = list_iterator_create(print_fields_list); print_fields_header(print_fields_list); + field_count = list_count(print_fields_list); + while((cluster = list_next(itr))) { + int curr_inx = 1; while((field = list_next(itr2))) { switch(field->type) { case PRINT_CLUSTER: field->print_routine(field, - cluster->name); + cluster->name, + (curr_inx == field_count)); break; case PRINT_CHOST: field->print_routine(field, - cluster->control_host); + cluster->control_host, + (curr_inx == field_count)); break; case PRINT_CPORT: field->print_routine(field, - cluster->control_port); + cluster->control_port, + (curr_inx == field_count)); break; case PRINT_FAIRSHARE: field->print_routine( field, - cluster->default_fairshare); + cluster->default_fairshare, + (curr_inx == field_count)); break; case PRINT_MAXC: field->print_routine( field, - cluster->default_max_cpu_secs_per_job); + cluster->default_max_cpu_secs_per_job, + (curr_inx == field_count)); break; case PRINT_MAXJ: field->print_routine( field, - cluster->default_max_jobs); + cluster->default_max_jobs, + (curr_inx == field_count)); break; case PRINT_MAXN: field->print_routine( field, - cluster->default_max_nodes_per_job); + cluster->default_max_nodes_per_job, + (curr_inx == field_count)); break; case PRINT_MAXW: field->print_routine( field, cluster-> - default_max_wall_duration_per_job); + default_max_wall_duration_per_job, + (curr_inx == field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); diff --git a/src/sacctmgr/common.c b/src/sacctmgr/common.c index 23320d49515b54a2f1a54c5147e06942ea66658a..0f5d2db96d35137efc7a6e4d878f419e8634ba00 100644 --- a/src/sacctmgr/common.c +++ b/src/sacctmgr/common.c @@ -46,8 +46,8 @@ static pthread_t lock_warning_thread; static void *_print_lock_warn(void *no_data) { - sleep(2); - printf(" Waiting for lock from other user.\n"); + sleep(5); + printf(" Database is busy or waiting for lock from other user.\n"); return NULL; } @@ -655,7 +655,8 @@ end_it: return count; } -extern void sacctmgr_print_coord_list(print_field_t *field, List value) +extern void sacctmgr_print_coord_list( + print_field_t *field, List value, int last) { ListIterator itr = NULL; char *print_this = NULL; @@ -679,7 +680,10 @@ extern void sacctmgr_print_coord_list(print_field_t *field, List value) list_iterator_destroy(itr); } - if(print_fields_parsable_print) + if(print_fields_parsable_print == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", print_this); + else if(print_fields_parsable_print) printf("%s|", print_this); else { if(strlen(print_this) > field->len) @@ -691,13 +695,16 @@ extern void sacctmgr_print_coord_list(print_field_t *field, List value) } extern void sacctmgr_print_qos_list(print_field_t *field, List qos_list, - List value) + List value, int last) { char *print_this = NULL; print_this = get_qos_complete_str(qos_list, value); - if(print_fields_parsable_print) + if(print_fields_parsable_print == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", print_this); + else if(print_fields_parsable_print) printf("%s|", print_this); else { if(strlen(print_this) > field->len) diff --git a/src/sacctmgr/file_functions.c b/src/sacctmgr/file_functions.c index 65ab75dac8496d9ecc9d56619cc63b63a3f6b510..2724f0842f424293d278b3a7ff35b642db823000 100644 --- a/src/sacctmgr/file_functions.c +++ b/src/sacctmgr/file_functions.c @@ -211,7 +211,7 @@ static sacctmgr_file_opts_t *_parse_options(char *options) file_opts->max_jobs = INFINITE; file_opts->max_nodes_per_job = INFINITE; file_opts->max_wall_duration_per_job = INFINITE; - file_opts->admin = ACCT_ADMIN_NONE; + file_opts->admin = ACCT_ADMIN_NOTSET; while(options[i]) { quote = 0; @@ -887,7 +887,9 @@ static int _mod_user(sacctmgr_file_opts_t *file_opts, } } - if(user->admin_level != file_opts->admin) { + if(user->admin_level != ACCT_ADMIN_NOTSET + && file_opts->admin != ACCT_ADMIN_NOTSET + && user->admin_level != file_opts->admin) { printf(" Changed User '%s' " "AdminLevel '%s' -> '%s'\n", user->name, diff --git a/src/sacctmgr/sacctmgr.c b/src/sacctmgr/sacctmgr.c index afc94c20d6b784c4e338d860291ce9834b135259..ab7d69b86b699510eb77ed107a6347b7a0c9b6c2 100644 --- a/src/sacctmgr/sacctmgr.c +++ b/src/sacctmgr/sacctmgr.c @@ -49,6 +49,7 @@ int exit_flag; /* program to terminate if =1 */ int input_words; /* number of words of input permitted */ int one_liner; /* one record per line if =1 */ int quiet_flag; /* quiet=1, verbose=-1, normal=0 */ +int readonly_flag; /* make it so you can only run list commands */ int verbosity; /* count of -v options */ int rollback_flag; /* immediate execute=1, else = 0 */ int with_assoc_flag = 0; @@ -79,7 +80,9 @@ main (int argc, char *argv[]) {"oneliner", 0, 0, 'o'}, {"no_header", 0, 0, 'n'}, {"parsable", 0, 0, 'p'}, + {"parsable2", 0, 0, 'P'}, {"quiet", 0, 0, 'q'}, + {"readonly", 0, 0, 'r'}, {"associations", 0, 0, 's'}, {"usage", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, @@ -93,10 +96,11 @@ main (int argc, char *argv[]) exit_flag = 0; input_field_count = 0; quiet_flag = 0; + readonly_flag = 0; verbosity = 0; log_init("sacctmgr", opts, SYSLOG_FACILITY_DAEMON, NULL); - while((opt_char = getopt_long(argc, argv, "hionpqsvV", + while((opt_char = getopt_long(argc, argv, "hionpPqrsvV", long_options, &option_index)) != -1) { switch (opt_char) { case (int)'?': @@ -118,11 +122,19 @@ main (int argc, char *argv[]) print_fields_have_header = 0; break; case (int)'p': - print_fields_parsable_print = 1; + print_fields_parsable_print = + PRINT_FIELDS_PARSABLE_ENDING; + break; + case (int)'P': + print_fields_parsable_print = + PRINT_FIELDS_PARSABLE_NO_ENDING; break; case (int)'q': quiet_flag = 1; break; + case (int)'r': + readonly_flag = 1; + break; case (int)'s': with_assoc_flag = 1; break; @@ -409,6 +421,14 @@ _process_command (int argc, char *argv[]) argv[0]); } quiet_flag = -1; + } else if (strncasecmp (argv[0], "readonly", 4) == 0) { + if (argc > 1) { + exit_code = 1; + fprintf (stderr, + "too many arguments for %s keyword\n", + argv[0]); + } + readonly_flag = 1; } else if (strncasecmp (argv[0], "rollup", 2) == 0) { time_t my_time = 0; if (argc > 2) { @@ -454,6 +474,12 @@ static void _add_it (int argc, char *argv[]) { int error_code = SLURM_SUCCESS; + if(readonly_flag) { + exit_code = 1; + fprintf(stderr, "Can't run this command in readonly mode.\n"); + return; + } + /* First identify the entity to add */ if (strncasecmp (argv[0], "Account", 1) == 0) { error_code = sacctmgr_add_account((argc - 1), &argv[1]); @@ -525,6 +551,13 @@ static void _modify_it (int argc, char *argv[]) { int error_code = SLURM_SUCCESS; + + if(readonly_flag) { + exit_code = 1; + fprintf(stderr, "Can't run this command in readonly mode.\n"); + return; + } + /* First identify the entity to modify */ if (strncasecmp (argv[0], "Account", 1) == 0) { error_code = sacctmgr_modify_account((argc - 1), &argv[1]); @@ -554,6 +587,12 @@ static void _delete_it (int argc, char *argv[]) { int error_code = SLURM_SUCCESS; + if(readonly_flag) { + exit_code = 1; + fprintf(stderr, "Can't run this command in readonly mode.\n"); + return; + } + /* First identify the entity to delete */ if (strncasecmp (argv[0], "Account", 1) == 0) { error_code = sacctmgr_delete_account((argc - 1), &argv[1]); @@ -587,8 +626,10 @@ sacctmgr [<OPTION>] [<COMMAND>] \n\ -i or --immediate: commit changes immediately \n\ -n or --no_header: no header will be added to the beginning of output \n\ -o or --oneliner: equivalent to \"oneliner\" command \n\ - -p or --parsable: output will be '|' delimited \n\ + -p or --parsable: output will be '|' delimited with a '|' at the end \n\ + -P or --parsable2: output will be '|' delimited without a '|' at the end\n\ -q or --quiet: equivalent to \"quiet\" command \n\ + -r or --readonly: equivalent to \"readonly\" command \n\ -s or --associations: equivalent to \"associations\" command \n\ -v or --verbose: equivalent to \"verbose\" command \n\ -V or --version: equivalent to \"version\" command \n\ @@ -608,9 +649,11 @@ sacctmgr [<OPTION>] [<COMMAND>] \n\ is display all. \n\ modify <ENTITY> <SPECS> modify entity \n\ oneliner report output one record per line. \n\ + parsable output will be | delimited with an ending '|'\n\ + parsable2 output will be | delimited without an ending '|'\n\ + readonly makes it so no modification can happen. \n\ quiet print no messages other than error messages. \n\ quit terminate this command. \n\ - parsable output will be | delimited \n\ show same as list \n\ verbose enable detailed logging. \n\ version display tool version number. \n\ diff --git a/src/sacctmgr/sacctmgr.h b/src/sacctmgr/sacctmgr.h index b935efa51b0c21ca75837f7e8c8f3d3d19d3aee3..4fc865fd422c89d58a69debb18cd95227d30d84f 100644 --- a/src/sacctmgr/sacctmgr.h +++ b/src/sacctmgr/sacctmgr.h @@ -101,6 +101,7 @@ extern int one_liner; /* one record per line if =1 */ extern int quiet_flag; /* quiet=1, verbose=-1, normal=0 */ extern int rollback_flag;/* immediate execute=0, else = 1 */ extern int with_assoc_flag;/* show acct/user associations flag */ +extern int readonly_flag; /* make it so you can only run list commands */ extern void *db_conn; extern uint32_t my_uid; @@ -146,9 +147,10 @@ extern int commit_check(char *warning); extern int get_uint(char *in_value, uint32_t *out_value, char *type); extern int addto_qos_char_list(List char_list, List qos_list, char *names, int option); -extern void sacctmgr_print_coord_list(print_field_t *field, List value); +extern void sacctmgr_print_coord_list( + print_field_t *field, List value, int last); extern void sacctmgr_print_qos_list(print_field_t *field, List qos_list, - List value); + List value, int last); extern char *get_qos_complete_str(List qos_list, List num_qos_list); extern int sort_coord_list(acct_coord_rec_t *coord_a, acct_coord_rec_t *coord_b); diff --git a/src/sacctmgr/user_functions.c b/src/sacctmgr/user_functions.c index 8faa0b90b304b1091a672e0ca316216694130b93..0888a0234eb250f48dbb85b24efe365f6677d1b0 100644 --- a/src/sacctmgr/user_functions.c +++ b/src/sacctmgr/user_functions.c @@ -83,7 +83,7 @@ static int _set_cond(int *start, int argc, char *argv[], } if(slurm_addto_char_list( user_cond->assoc_cond->user_list, - argv[i]+end)) + argv[i]+end)) u_set = 1; } else if (!strncasecmp (argv[i], "Account", 2)) { if(!user_cond->assoc_cond->acct_list) { @@ -858,6 +858,7 @@ extern int sacctmgr_list_user(int argc, char *argv[]) List qos_list = NULL; print_field_t *field = NULL; + int field_count = 0; List format_list = list_create(slurm_destroy_char); List print_fields_list; /* types are of print_field_t */ @@ -981,7 +982,8 @@ extern int sacctmgr_list_user(int argc, char *argv[]) field->name = xstrdup("Partition"); field->len = 10; field->print_routine = print_fields_str; - } else if(!strncasecmp("User", object, 1)) { + } else if(!strncasecmp("User", object, 1) + || !strncasecmp("Name", object, 2)) { field->type = PRINT_USER; field->name = xstrdup("User"); field->len = 10; @@ -1017,73 +1019,100 @@ extern int sacctmgr_list_user(int argc, char *argv[]) itr2 = list_iterator_create(print_fields_list); print_fields_header(print_fields_list); + field_count = list_count(print_fields_list); + while((user = list_next(itr))) { if(user->assoc_list && list_count(user->assoc_list)) { ListIterator itr3 = list_iterator_create(user->assoc_list); while((assoc = list_next(itr3))) { + int curr_inx = 1; while((field = list_next(itr2))) { switch(field->type) { case PRINT_ACCOUNT: field->print_routine( field, - assoc->acct); + assoc->acct, + (curr_inx == + field_count)); break; case PRINT_ADMIN: field->print_routine( field, acct_admin_level_str( user-> - admin_level)); + admin_level), + (curr_inx == + field_count)); break; case PRINT_CLUSTER: field->print_routine( field, - assoc->cluster); + assoc->cluster, + (curr_inx == + field_count)); break; case PRINT_COORDS: field->print_routine( field, - user->coord_accts); + user->coord_accts, + (curr_inx == + field_count)); break; case PRINT_DACCT: field->print_routine( field, - user->default_acct); + user->default_acct, + (curr_inx == + field_count), + (curr_inx == + field_count)); break; case PRINT_FAIRSHARE: field->print_routine( field, - assoc->fairshare); + assoc->fairshare, + (curr_inx == + field_count)); break; case PRINT_ID: field->print_routine( field, - assoc->id); + assoc->id, + (curr_inx == + field_count)); break; case PRINT_MAXC: field->print_routine( field, assoc-> - max_cpu_secs_per_job); + max_cpu_secs_per_job, + (curr_inx == + field_count)); break; case PRINT_MAXJ: field->print_routine( field, - assoc->max_jobs); + assoc->max_jobs, + (curr_inx == + field_count)); break; case PRINT_MAXN: field->print_routine( field, assoc-> - max_nodes_per_job); + max_nodes_per_job, + (curr_inx == + field_count)); break; case PRINT_MAXW: field->print_routine( field, assoc-> - max_wall_duration_per_job); + max_wall_duration_per_job, + (curr_inx == + field_count)); break; case PRINT_QOS: if(!qos_list) { @@ -1095,7 +1124,9 @@ extern int sacctmgr_list_user(int argc, char *argv[]) field->print_routine( field, qos_list, - user->qos_list); + user->qos_list, + (curr_inx == + field_count)); break; case PRINT_QOS_RAW: if(!qos_list) { @@ -1107,94 +1138,117 @@ extern int sacctmgr_list_user(int argc, char *argv[]) field->print_routine( field, qos_list, - user->qos_list); + user->qos_list, + (curr_inx == + field_count)); break; case PRINT_PID: field->print_routine( field, - assoc->parent_id); + assoc->parent_id, + (curr_inx == + field_count)); break; case PRINT_PNAME: field->print_routine( field, - assoc->parent_acct); + assoc->parent_acct, + (curr_inx == + field_count)); break; case PRINT_PART: field->print_routine( field, - assoc->partition); + assoc->partition, + (curr_inx == + field_count)); break; case PRINT_USER: field->print_routine( field, - user->name); + user->name, + (curr_inx == + field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); } list_iterator_destroy(itr3); } else { + int curr_inx = 1; while((field = list_next(itr2))) { switch(field->type) { case PRINT_ACCOUNT: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_ADMIN: field->print_routine( field, acct_admin_level_str( - user->admin_level)); + user->admin_level), + (curr_inx == field_count)); break; case PRINT_CLUSTER: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_COORDS: field->print_routine( field, - user->coord_accts); + user->coord_accts, + (curr_inx == field_count)); break; case PRINT_DACCT: field->print_routine( field, - user->default_acct); + user->default_acct, + (curr_inx == field_count)); break; case PRINT_FAIRSHARE: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_ID: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_MAXC: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_MAXJ: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_MAXN: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_MAXW: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_QOS: if(!qos_list) { @@ -1205,7 +1259,8 @@ extern int sacctmgr_list_user(int argc, char *argv[]) } field->print_routine( field, qos_list, - user->qos_list); + user->qos_list, + (curr_inx == field_count)); break; case PRINT_QOS_RAW: if(!qos_list) { @@ -1216,26 +1271,31 @@ extern int sacctmgr_list_user(int argc, char *argv[]) } field->print_routine( field, qos_list, - user->qos_list); + user->qos_list, + (curr_inx == field_count)); break; case PRINT_PID: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_PART: field->print_routine( field, - NULL); + NULL, + (curr_inx == field_count)); break; case PRINT_USER: field->print_routine( field, - user->name); + user->name, + (curr_inx == field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); @@ -1352,14 +1412,6 @@ extern int sacctmgr_modify_user(int argc, char *argv[]) assoc_start: if(rec_set == 3 || rec_set == 2) { // process the association changes - if(cond_set == 1) { - rc = SLURM_ERROR; - exit_code=1; - fprintf(stderr, - " There was a problem with your " - "'where' options.\n"); - goto assoc_end; - } ret_list = acct_storage_g_modify_associations( db_conn, my_uid, user_cond->assoc_cond, assoc); @@ -1384,8 +1436,6 @@ assoc_start: list_destroy(ret_list); } -assoc_end: - notice_thread_fini(); if(set) { if(commit_check("Would you like to commit changes?")) @@ -1428,7 +1478,7 @@ extern int sacctmgr_delete_user(int argc, char *argv[]) if(set == 1) { ret_list = acct_storage_g_remove_users( db_conn, my_uid, user_cond); - } else if(set == 2) { + } else if(set == 2 || set == 3) { ret_list = acct_storage_g_remove_associations( db_conn, my_uid, user_cond->assoc_cond); } @@ -1441,7 +1491,7 @@ extern int sacctmgr_delete_user(int argc, char *argv[]) ListIterator itr = list_iterator_create(ret_list); if(set == 1) { printf(" Deleting users...\n"); - } else if(set == 2) { + } else if(set == 2 || set == 3) { printf(" Deleting user associations...\n"); } while((object = list_next(itr))) { diff --git a/src/slurmctld/controller.c b/src/slurmctld/controller.c index 70c6a2c8f7e7268b150bb1a5870f392b4ed14569..7e28c7b63ef7d2fc08bddbfc0788ee2738afb3c4 100644 --- a/src/slurmctld/controller.c +++ b/src/slurmctld/controller.c @@ -263,8 +263,7 @@ int main(int argc, char *argv[]) /* * Create StateSaveLocation directory if necessary. */ - if (set_slurmctld_state_loc() < 0) - fatal("Unable to initialize StateSaveLocation"); + set_slurmctld_state_loc(); if (daemonize) { slurmctld_config.daemonize = 1; @@ -1591,25 +1590,26 @@ _init_pidfile(void) /* * set_slurmctld_state_loc - create state directory as needed and "cd" to it */ -extern int +extern void set_slurmctld_state_loc(void) { - char *tmp; - - if ((mkdir(slurmctld_conf.state_save_location, 0755) < 0) && - (errno != EEXIST)) { - fatal("mkdir(%s): %m", slurmctld_conf.state_save_location); - return SLURM_ERROR; - } + int rc; + struct stat st; + const char *path = slurmctld_conf.state_save_location; - tmp = xstrdup(slurmctld_conf.state_save_location); - xstrcat(tmp, "/slurm_mkdir_test"); - if ((mkdir(tmp, 0755) < 0) && (errno != EEXIST)) { - fatal("mkdir(%s): %m", tmp); - return SLURM_ERROR; + /* + * If state save location does not exist, try to create it. + * Otherwise, ensure path is a directory as expected, and that + * we have permission to write to it. + */ + if (((rc = stat(path, &st)) < 0) && (errno == ENOENT)) { + if (mkdir(path, 0755) < 0) + fatal("mkdir(%s): %m", path); } - (void) unlink(tmp); - xfree(tmp); - - return SLURM_SUCCESS; + else if (rc < 0) + fatal("Unable to stat state save loc: %s: %m", path); + else if (!S_ISDIR(st.st_mode)) + fatal("State save loc: %s: Not a directory!", path); + else if (access(path, R_OK|W_OK|X_OK) < 0) + fatal("Incorrect permissions on state save loc: %s", path); } diff --git a/src/slurmctld/partition_mgr.c b/src/slurmctld/partition_mgr.c index 6bd647e22aba63b9016e8d0740c87438d6b39ff7..1119ecb196503f01eb6a2caec3f948e978333f2c 100644 --- a/src/slurmctld/partition_mgr.c +++ b/src/slurmctld/partition_mgr.c @@ -1053,9 +1053,8 @@ uid_t *_get_groups_members(char *group_names) */ uid_t *_get_group_members(char *group_name) { - size_t grp_bufsize; - char *grp_buffer; - char buf[BUF_SIZE]; + char grp_buffer[PW_BUF_SIZE]; + char pw_buffer[PW_BUF_SIZE]; struct group grp, *grp_result = NULL; struct passwd pw, *pwd_result = NULL; uid_t *group_uids, my_uid; @@ -1065,14 +1064,15 @@ uid_t *_get_group_members(char *group_name) FILE *fp = NULL; #endif - grp_bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); - grp_buffer = xmalloc(grp_bufsize); - if (getgrnam_r(group_name, &grp, grp_buffer, grp_bufsize, - &grp_result)) { + /* We need to check for !grp_result, since it appears some + * versions of this function do not return an error on failure. + */ + if (getgrnam_r(group_name, &grp, grp_buffer, PW_BUF_SIZE, + &grp_result) || (grp_result == NULL)) { error("Could not find configured group %s", group_name); - xfree(grp_buffer); return NULL; } + my_gid = grp_result->gr_gid; for (uid_cnt=0; ; uid_cnt++) { @@ -1092,14 +1092,13 @@ uid_t *_get_group_members(char *group_name) group_uids[j++] = my_uid; } } - xfree(grp_buffer); setpwent(); #ifdef HAVE_AIX - while (!getpwent_r(&pw, buf, BUF_SIZE, &fp)) { + while (!getpwent_r(&pw, pw_buffer, PW_BUF_SIZE, &fp)) { pwd_result = &pw; #else - while (!getpwent_r(&pw, buf, BUF_SIZE, &pwd_result)) { + while (!getpwent_r(&pw, pw_buffer, PW_BUF_SIZE, &pwd_result)) { #endif if (pwd_result->pw_gid != my_gid) continue; diff --git a/src/slurmctld/slurmctld.h b/src/slurmctld/slurmctld.h index cc519cd48695f54fe20ff0f9a00d8aa18dbb80c4..b8ab227157b76d5491006374243a224627a65944 100644 --- a/src/slurmctld/slurmctld.h +++ b/src/slurmctld/slurmctld.h @@ -1324,7 +1324,7 @@ extern void set_node_down (char *name, char *reason); /* * set_slurmctld_state_loc - create state directory as needed and "cd" to it */ -extern int set_slurmctld_state_loc(void); +extern void set_slurmctld_state_loc(void); /* set_slurmd_addr - establish the slurm_addr for the slurmd on each node * Uses common data structures. */ diff --git a/src/slurmd/slurmd/req.c b/src/slurmd/slurmd/req.c index 0f7f67ea2ef416a68093f4c4101b8891aa927d3d..19d660dff4ccc5d660d0f3d57ac62f8beae55dd1 100644 --- a/src/slurmd/slurmd/req.c +++ b/src/slurmd/slurmd/req.c @@ -70,6 +70,7 @@ #include "src/common/xstring.h" #include "src/common/xmalloc.h" #include "src/common/list.h" +#include "src/common/uid.h" #include "src/common/util-net.h" #include "src/common/forward.h" #include "src/common/read_config.h" @@ -332,8 +333,7 @@ _send_slurmstepd_init(int fd, slurmd_step_type_t type, void *req, int parent_rank, children, depth, max_depth; char *parent_alias = NULL; slurm_addr parent_addr = {0}; - size_t pwd_bufsize; - char *pwd_buffer; + char pwd_buffer[PW_BUF_SIZE]; struct passwd pwd, *pwd_result; slurm_msg_t_init(&msg); @@ -459,14 +459,11 @@ _send_slurmstepd_init(int fd, slurmd_step_type_t type, void *req, /* send cached group ids array for the relevant uid */ debug3("_send_slurmstepd_init: call to getpwuid_r"); - pwd_bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - pwd_buffer = xmalloc(pwd_bufsize); - if (getpwuid_r(uid, &pwd, pwd_buffer, pwd_bufsize, &pwd_result) || + if (getpwuid_r(uid, &pwd, pwd_buffer, PW_BUF_SIZE, &pwd_result) || (pwd_result == NULL)) { error("_send_slurmstepd_init getpwuid_r: %m"); len = 0; safe_write(fd, &len, sizeof(int)); - xfree(pwd_buffer); return -1; } debug3("_send_slurmstepd_init: return from getpwuid_r"); @@ -484,7 +481,6 @@ _send_slurmstepd_init(int fd, slurmd_step_type_t type, void *req, len = 0; safe_write(fd, &len, sizeof(int)); } - xfree(pwd_buffer); return 0; rwfail: @@ -904,10 +900,9 @@ _prolog_error(batch_job_launch_msg_t *req, int rc) static void _get_user_env(batch_job_launch_msg_t *req) { - struct passwd pwd, *pwd_ptr; - char *pwd_buf = NULL; + struct passwd pwd, *pwd_ptr = NULL; + char pwd_buf[PW_BUF_SIZE]; char **new_env; - size_t buf_size; int i; for (i=0; i<req->argc; i++) { @@ -917,9 +912,8 @@ _get_user_env(batch_job_launch_msg_t *req) if (i >= req->argc) return; /* don't need to load env */ - buf_size = sysconf(_SC_GETPW_R_SIZE_MAX); - pwd_buf = xmalloc(buf_size); - if (getpwuid_r(req->uid, &pwd, pwd_buf, buf_size, &pwd_ptr)) { + if (getpwuid_r(req->uid, &pwd, pwd_buf, PW_BUF_SIZE, &pwd_ptr) || + (pwd_ptr == NULL)) { error("getpwuid_r(%u):%m", req->uid); } else { verbose("get env for user %s here", pwd.pw_name); @@ -939,7 +933,6 @@ _get_user_env(batch_job_launch_msg_t *req) "running only with passed environment"); } } - xfree(pwd_buf); } /* The RPC currently contains a memory size limit, but we load the @@ -3198,11 +3191,12 @@ init_gids_cache(int cache) orig_gids = (gid_t *)xmalloc(ngids * sizeof(gid_t)); getgroups(ngids, orig_gids); - setpwent(); #ifdef HAVE_AIX + setpwent(&fp); while (!getpwent_r(&pw, buf, BUF_SIZE, &fp)) { pwd = &pw; #else + setpwent(); while (!getpwent_r(&pw, buf, BUF_SIZE, &pwd)) { #endif if (_gids_cache_lookup(pwd->pw_name, pwd->pw_gid)) @@ -3218,7 +3212,11 @@ init_gids_cache(int cache) continue; _gids_cache_register(pwd->pw_name, pwd->pw_gid, gids); } +#ifdef HAVE_AIX + endpwent_r(&fp); +#else endpwent(); +#endif setgroups(ngids, orig_gids); xfree(orig_gids); diff --git a/src/sreport/cluster_reports.c b/src/sreport/cluster_reports.c index 8c39260dc7c1814a2965b064d08f5a8640e69632..752eb59e787a7ad6cfbbc7bd6d7916710a03df81 100644 --- a/src/sreport/cluster_reports.c +++ b/src/sreport/cluster_reports.c @@ -265,6 +265,7 @@ extern int cluster_utilization(int argc, char *argv[]) List cluster_list = NULL; List format_list = list_create(slurm_destroy_char); + int field_count = 0; print_fields_list = list_create(destroy_print_field); @@ -285,11 +286,14 @@ extern int cluster_utilization(int argc, char *argv[]) print_fields_header(print_fields_list); + field_count = list_count(print_fields_list); + while((cluster = list_next(itr))) { cluster_accounting_rec_t *accting = NULL; cluster_accounting_rec_t total_acct; uint64_t total_reported = 0; uint64_t local_total_time = 0; + int curr_inx = 1; if(!cluster->accounting_list || !list_count(cluster->accounting_list)) @@ -317,45 +321,62 @@ extern int cluster_utilization(int argc, char *argv[]) switch(field->type) { case PRINT_CLUSTER_NAME: field->print_routine(field, - cluster->name); + cluster->name, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_CPUS: field->print_routine(field, - total_acct.cpu_count); + total_acct.cpu_count, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_ACPU: field->print_routine(field, total_acct.alloc_secs, - total_reported); + total_reported, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_DCPU: field->print_routine(field, total_acct.down_secs, - total_reported); + total_reported, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_ICPU: field->print_routine(field, total_acct.idle_secs, - total_reported); + total_reported, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_RCPU: field->print_routine(field, total_acct.resv_secs, - total_reported); + total_reported, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_OCPU: field->print_routine(field, total_acct.over_secs, - total_reported); + total_reported, + (curr_inx == + field_count)); break; case PRINT_CLUSTER_TOTAL: field->print_routine(field, total_reported, - local_total_time); + local_total_time, + (curr_inx == + field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); diff --git a/src/sreport/common.c b/src/sreport/common.c index 9df97591b305d113835d4b41d8be46034fb73660..256306c00e5229f74ad91b7c2f59217d15fe1baf 100644 --- a/src/sreport/common.c +++ b/src/sreport/common.c @@ -40,14 +40,18 @@ #include "sreport.h" extern void sreport_print_time(print_field_t *field, - uint64_t value, uint64_t total_time) + uint64_t value, uint64_t total_time, int last) { if(!total_time) total_time = 1; /* (value == unset) || (value == cleared) */ if((value == NO_VAL) || (value == INFINITE)) { - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + ; + else if(print_fields_parsable_print) printf("|"); else printf("%-*s ", field->len, " "); @@ -75,7 +79,11 @@ extern void sreport_print_time(print_field_t *field, break; } - if(print_fields_parsable_print) + if(print_fields_parsable_print + == PRINT_FIELDS_PARSABLE_NO_ENDING + && last) + printf("%s", output); + else if(print_fields_parsable_print) printf("%s|", output); else printf("%*s ", field->len, output); diff --git a/src/sreport/job_reports.c b/src/sreport/job_reports.c index 654ca7b02fa4c480f63908940f5b1297aa0a069b..d8d024530556fb81594ee4b867654f1e5d63b9fb 100644 --- a/src/sreport/job_reports.c +++ b/src/sreport/job_reports.c @@ -714,16 +714,18 @@ no_assocs: while((cluster_group = list_next(cluster_itr))) { acct_itr = list_iterator_create(cluster_group->acct_list); while((acct_group = list_next(acct_itr))) { + while((field = list_next(itr))) { switch(field->type) { case PRINT_JOB_CLUSTER: field->print_routine( field, - cluster_group->cluster); + cluster_group->cluster, 0); break; case PRINT_JOB_ACCOUNT: field->print_routine(field, - acct_group->acct); + acct_group->acct, + 0); break; default: break; @@ -748,7 +750,7 @@ no_assocs: list_iterator_destroy(local_itr); total_field.print_routine(&total_field, acct_group->cpu_secs, - cluster_group->cpu_secs); + cluster_group->cpu_secs, 1); printf("\n"); } diff --git a/src/sreport/sreport.c b/src/sreport/sreport.c index 08715ad0e8ea6ab9d5504a57a8cb17d264608c00..74e7153e891430f5968d5a011d17941de1a2ab3d 100644 --- a/src/sreport/sreport.c +++ b/src/sreport/sreport.c @@ -80,6 +80,7 @@ main (int argc, char *argv[]) {"immediate",0, 0, 'i'}, {"no_header", 0, 0, 'n'}, {"parsable", 0, 0, 'p'}, + {"parsable2", 0, 0, 'P'}, {"quiet", 0, 0, 'q'}, {"usage", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, @@ -94,7 +95,7 @@ main (int argc, char *argv[]) quiet_flag = 0; log_init("sreport", opts, SYSLOG_FACILITY_DAEMON, NULL); - while((opt_char = getopt_long(argc, argv, "ahnpqt:vV", + while((opt_char = getopt_long(argc, argv, "ahnpPqt:vV", long_options, &option_index)) != -1) { switch (opt_char) { case (int)'?': @@ -113,7 +114,12 @@ main (int argc, char *argv[]) print_fields_have_header = 0; break; case (int)'p': - print_fields_parsable_print = 1; + print_fields_parsable_print = + PRINT_FIELDS_PARSABLE_ENDING; + break; + case (int)'P': + print_fields_parsable_print = + PRINT_FIELDS_PARSABLE_NO_ENDING; break; case (int)'q': quiet_flag = 1; @@ -494,7 +500,8 @@ sreport [<OPTION>] [<COMMAND>] \n\ -h or --help: equivalent to \"help\" command \n\ -n or --no_header: equivalent to \"no_header\" command \n\ -q or --quiet: equivalent to \"quiet\" command \n\ - -p or --parsable: equivalent to \"parsable\" command \n\ + -p or --parsable: output will be '|' delimited with a '|' at the end \n\ + -P or --parsable2: output will be '|' delimited without a '|' at the end\n\ -v or --verbose: equivalent to \"verbose\" command \n\ -V or --version: equivalent to \"version\" command \n\ \n\ @@ -505,7 +512,9 @@ sreport [<OPTION>] [<COMMAND>] \n\ Valid <COMMAND> values are: \n\ exit terminate sreport \n\ help print this description of use. \n\ - quiet print no messages other than error messages. \n\ + parsable output will be | delimited with an ending '|'\n\ + parsable2 output will be | delimited without an ending '|'\n\ + quiet print no messages other than error messages. \n\ quit terminate this command. \n\ verbose enable detailed logging. \n\ version display tool version number. \n\ diff --git a/src/sreport/sreport.h b/src/sreport/sreport.h index d8f25640da3666761d2f6fb60b6267374fa90273..bd450fb78e737b24d3252fc9f963dd83cf603fed 100644 --- a/src/sreport/sreport.h +++ b/src/sreport/sreport.h @@ -103,7 +103,7 @@ extern uint32_t my_uid; extern int all_clusters_flag; extern void sreport_print_time(print_field_t *field, - uint64_t value, uint64_t total_time); + uint64_t value, uint64_t total_time, int last); extern int parse_option_end(char *option); extern char *strip_quotes(char *option, int *increased); extern int set_start_end_time(time_t *start, time_t *end); diff --git a/src/sreport/user_reports.c b/src/sreport/user_reports.c index a1496a48fe5e5b897fede185dc339829edc4cac9..4e2347787b4a15ecbdb890081e4692e9762aa349 100644 --- a/src/sreport/user_reports.c +++ b/src/sreport/user_reports.c @@ -282,6 +282,7 @@ extern int user_top(int argc, char *argv[]) local_user_rec_t *local_user = NULL; local_cluster_rec_t *local_cluster = NULL; print_field_t *field = NULL; + int field_count = 0; print_fields_list = list_create(destroy_print_field); @@ -423,6 +424,8 @@ extern int user_top(int argc, char *argv[]) itr2 = list_iterator_create(print_fields_list); print_fields_header(print_fields_list); + field_count = list_count(print_fields_list); + list_iterator_reset(cluster_itr); while((local_cluster = list_next(cluster_itr))) { list_sort(local_cluster->user_list, (ListCmpF)_sort_user_dec); @@ -430,6 +433,7 @@ extern int user_top(int argc, char *argv[]) itr = list_iterator_create(local_cluster->user_list); while((local_user = list_next(itr))) { int count = 0; + int curr_inx = 1; while((field = list_next(itr2))) { char *tmp_char = NULL; struct passwd *pwd = NULL; @@ -449,17 +453,21 @@ extern int user_top(int argc, char *argv[]) list_iterator_destroy(itr3); field->print_routine( field, - tmp_char); + tmp_char, + (curr_inx == field_count)); xfree(tmp_char); break; case PRINT_USER_CLUSTER: field->print_routine( field, - local_cluster->name); + local_cluster->name, + (curr_inx == field_count)); break; case PRINT_USER_LOGIN: field->print_routine(field, - local_user->name); + local_user->name, + (curr_inx == + field_count)); break; case PRINT_USER_PROPER: pwd = getpwnam(local_user->name); @@ -467,21 +475,25 @@ extern int user_top(int argc, char *argv[]) tmp_char = strtok(pwd->pw_gecos, ","); if(!tmp_char) - tmp_char = + tmp_char = pwd->pw_gecos; } field->print_routine(field, - tmp_char); + tmp_char, + (curr_inx == + field_count)); break; case PRINT_USER_USED: field->print_routine( field, local_user->cpu_secs, - local_cluster->cpu_secs); + local_cluster->cpu_secs, + (curr_inx == field_count)); break; default: break; } + curr_inx++; } list_iterator_reset(itr2); printf("\n"); diff --git a/testsuite/expect/README b/testsuite/expect/README index e1dba8ce456db60d32f98fb7bbd4eaa56577ba05..6d2bbda326dc661c4bbba3f1283253e323c3fdec 100644 --- a/testsuite/expect/README +++ b/testsuite/expect/README @@ -291,6 +291,8 @@ test7.9 Test that no files are open in spawned tasks (except stdin, stdout, and stderr) to insure successful checkpoint/restart. test7.10 Test if we can trick SLURM into using the wrong user ID through an LD_PRELOAD option. +test7.11 Test of SPANK plugin. + test8.# Test of Blue Gene specific functionality. ================================================= @@ -302,6 +304,7 @@ test8.5 Confirm we can make a 32, 128, and 512 cnode block. test8.6 Stress test Dynamic mode block creation. test8.7 Test of Blue Gene scheduling with sched/wik2 plugin. + test9.# System stress testing. Exercises all commands and daemons. ===================================================================== test9.1 Stress test of stdin broadcast. diff --git a/testsuite/expect/globals b/testsuite/expect/globals index c97adf14a1fc3e05462da8d68ff3877ef6aa8ab2..aac8121947dd10c8eb27beeda55824d4d7fa9c7e 100755 --- a/testsuite/expect/globals +++ b/testsuite/expect/globals @@ -814,7 +814,7 @@ proc test_super_user { } { wait } } - spawn $scontrol show control + spawn $scontrol show config set slurm_user "" expect { -re "SlurmUser *= ($alpha_numeric_under)" { diff --git a/testsuite/expect/test1.29 b/testsuite/expect/test1.29 index c055e47dcc2d49c4b9cb05acf6474b1d166afe6c..7da4c0dd001341e2c0502e13fc6f0afeb7d7e82a 100755 --- a/testsuite/expect/test1.29 +++ b/testsuite/expect/test1.29 @@ -61,7 +61,7 @@ if {[test_front_end] != 0 && [test_super_user] == 0} { # of the ulimit program is inconsistent across systems. # exec $bin_rm -f $file_prog_get $file_err $file_in $file_out -exec $bin_make -f /dev/null $file_prog_get +exec $bin_cc -O ${file_prog_get}.c -o $file_prog_get exec $bin_chmod 700 $file_prog_get # diff --git a/testsuite/expect/test1.32 b/testsuite/expect/test1.32 index 9275a8bee37f4a211638afa0cd2ad08c745ac543..c2957a4820e31a293820bf28a3b3326b4c11fb83 100755 --- a/testsuite/expect/test1.32 +++ b/testsuite/expect/test1.32 @@ -54,7 +54,7 @@ if { [test_xcpu] } { # Delete left-over program and rebuild it # exec $bin_rm -f $file_prog -exec $bin_make -f /dev/null $file_prog +exec $bin_cc -O ${file_prog}.c -o $file_prog exec $bin_chmod 700 $file_prog # diff --git a/testsuite/expect/test1.34 b/testsuite/expect/test1.34 index 9a7f0e83a767b0f33f8072bfca70f99291aa36ec..87485a9deeba64de31d648d6402f85629ab15fe6 100755 --- a/testsuite/expect/test1.34 +++ b/testsuite/expect/test1.34 @@ -58,9 +58,9 @@ set matches 0 set timeout $max_job_delay set srun_pid [spawn $srun -n1 -O $test_prog] expect { - -re "Segmentation.*core dumped" { - send_user "This error was expected, no worries\n" - incr matches + -re "Segmentation fault" { + send_user "\nThis error was expected, no worries\n" + set matches 1 exp_continue } timeout { diff --git a/testsuite/expect/test1.38 b/testsuite/expect/test1.38 index 3df3239762fd695035d8da70247f3c6e7d54edca..dcbc3b17d5aa5231aa1147e03fa55f7c09a79dbf 100755 --- a/testsuite/expect/test1.38 +++ b/testsuite/expect/test1.38 @@ -91,7 +91,7 @@ expect { exec $bin_kill -INT $srun_pid exp_continue } - -re "Force Terminated" { + -re "Force Terminated job $number" { incr matches exp_continue } diff --git a/testsuite/expect/test1.46 b/testsuite/expect/test1.46 index 57abc964a4d73224f07dfe5f51dab3f5360ae439..0938ed86bfae9ed9afc6031da990c5098cde61f0 100755 --- a/testsuite/expect/test1.46 +++ b/testsuite/expect/test1.46 @@ -66,7 +66,7 @@ main() close $fd # Add delay due to sporatic error "Clock skew detected" exec $bin_sleep 1 -exec $bin_make -f /dev/null $file_in +exec $bin_cc -O -o $file_in ${file_in}.c exec $bin_chmod 700 $file_in # diff --git a/testsuite/expect/test12.2 b/testsuite/expect/test12.2 index e4d9a66e344a89f804bc14aeea6f0a4c29fe69b0..2abedee55db0151cd75bdf4b57dd27aa611c305b 100755 --- a/testsuite/expect/test12.2 +++ b/testsuite/expect/test12.2 @@ -97,7 +97,7 @@ if {$supported_storage == 0} { # exec $bin_rm -f $file_prog exec $bin_rm -f $file_in $file_out $file_err -exec $bin_make -f /dev/null $file_prog +exec $bin_cc -O -o $file_prog ${file_prog}.c exec $bin_chmod 700 $file_prog make_bash_script $file_in " @@ -145,20 +145,24 @@ set mem_task -1 set ave_used -1 spawn $sstat --noheader --job=$job_id.0 --fields vsize expect { - -re "($float)(\[KM\]*)/.*($number) - ($float)(\[KM\]*)" { + -re "($float)(\[KMG\]*)/.*($number) - ($float)(\[KMG\]*)" { set mem_used $expect_out(1,string) set scale1 $expect_out(2,string) set mem_task $expect_out(3,string) set ave_used $expect_out(4,string) set scale2 $expect_out(5,string) - if {[string compare $scale1 "M"] == 0} { + if {[string compare $scale1 "G"] == 0} { + set mem_used [expr $mem_used * 1024 * 1024] + } elseif {[string compare $scale1 "M"] == 0} { set mem_used [expr $mem_used * 1024] } elseif {[string compare $scale1 "K"] == 0} { set mem_used [expr $mem_used * 1] } else { set mem_used [expr $mem_used / 1024] } - if {[string compare $scale2 "M"] == 0} { + if {[string compare $scale2 "G"] == 0} { + set ave_used [expr $ave_used * 1024 * 1024] + } elseif {[string compare $scale2 "M"] == 0} { set ave_used [expr $ave_used * 1024] } elseif {[string compare $scale2 "K"] == 0} { set ave_used [expr $ave_used * 1] @@ -280,20 +284,24 @@ set mem_task -1 set ave_used -1 spawn $sacct --noheader --job=$job_id.0 --fields vsize expect { - -re "($float)(\[KM\]*)/.*($number) - ($float)(\[KM\]*)" { + -re "($float)(\[KMG\]*)/.*($number) - ($float)(\[KMG\]*)" { set mem_used $expect_out(1,string) set scale1 $expect_out(2,string) set mem_task $expect_out(3,string) set ave_used $expect_out(4,string) set scale2 $expect_out(5,string) - if {[string compare $scale1 "M"] == 0} { + if {[string compare $scale1 "G"] == 0} { + set mem_used [expr $mem_used * 1024 * 1024] + } elseif {[string compare $scale1 "M"] == 0} { set mem_used [expr $mem_used * 1024] } elseif {[string compare $scale1 "K"] == 0} { set mem_used [expr $mem_used * 1] } else { set mem_used [expr $mem_used / 1024] } - if {[string compare $scale2 "M"] == 0} { + if {[string compare $scale2 "G"] == 0} { + set ave_used [expr $ave_used * 1024 * 1024] + } elseif {[string compare $scale2 "M"] == 0} { set ave_used [expr $ave_used * 1024] } elseif {[string compare $scale2 "K"] == 0} { set ave_used [expr $ave_used * 1] @@ -343,7 +351,7 @@ if {$aix == 1 && $exit_code == 1} { } if {$exit_code == 0} { - exec rm -f $file_prog + exec rm -f $file_prog $file_in $file_out $file_err send_user "\nSUCCESS\n" } exit $exit_code diff --git a/testsuite/expect/test16.4 b/testsuite/expect/test16.4 index eede3faef05f49b28dd05399046f16096adbacb0..217c4ed48fde3049458f3c778d90bac0fa5576ab 100755 --- a/testsuite/expect/test16.4 +++ b/testsuite/expect/test16.4 @@ -49,7 +49,7 @@ if { [test_xcpu] } { # Delete left-over program and rebuild it # exec $bin_rm -f $file_prog -exec $bin_make -f /dev/null $file_prog +exec $bin_cc -O -o $file_prog ${file_prog}.c exec $bin_chmod 700 $file_prog # diff --git a/testsuite/expect/test17.15 b/testsuite/expect/test17.15 index 2bfa3b89a240f61bb08d0d54b632b00316f3003c..7bbf9bb320e5916cbdb15fd2726f9677cc5c3a23 100755 --- a/testsuite/expect/test17.15 +++ b/testsuite/expect/test17.15 @@ -56,7 +56,7 @@ print_header $test_id # of the ulimit program is inconsistent across systems. # exec $bin_rm -f $file_prog_get $file_err $file_in $file_out -exec $bin_make -f /dev/null $file_prog_get +exec $bin_cc -O -o $file_prog_get ${file_prog_get}.c # # Get our current limits and adjust targets accordingly diff --git a/testsuite/expect/test21.14 b/testsuite/expect/test21.14 index 41146bf62193f3e4971964cd295d764d2c6076e2..9fc70080c5aa31a4b7edf4757a0b0db5a946f99f 100755 --- a/testsuite/expect/test21.14 +++ b/testsuite/expect/test21.14 @@ -1,7 +1,8 @@ #!/usr/bin/expect ############################################################################ # Purpose: Test of SLURM functionality -# sacctmgr modify multiple accounts +# sacctmgr modify accounts, descriptions, limits, +# and parents down and up the tree # # Output: "TEST: #.#" followed by "SUCCESS" if test was successful, OR # "FAILURE: ..." otherwise with an explanation of the failure, OR @@ -33,28 +34,6 @@ source ./globals set test_id "21.14" set exit_code 0 -set acmatches 0 -set aamatches 0 -set ammatches 0 -set almatches 0 -set aclmatches 0 -set lmatches 0 -set lamatches 0 -set damatches 0 -set dcmatches 0 -set not_support 0 -set add add -set lis list -set del delete -set mod modify -set nams Names -set nam Name -set fs Fairshare -set mc MaxCPUSecs -set mj MaxJobs -set mn MaxNodes -set mw MaxWall -set clu cluster set tc1 tcluster1 set tc2 tcluster2 set tc3 tcluster3 @@ -65,7 +44,7 @@ set mc2 700000 set mj1 50 set mj2 70 set mn1 300 -set mn2 70 +set mn2 700 set mw1 01:00:00 set mw2 00:07:00 set acc account @@ -86,6 +65,7 @@ set par parent print_header $test_id +set timeout 60 # # Check accounting config and bail if not found. @@ -94,247 +74,667 @@ if { [test_account_storage] == 0 } { send_user "\nWARNING: This test can't be run without a usable AccountStorageType\n" exit 0 } - + + # # Use sacctmgr to create a cluster -# -set sadd_pid [spawn $sacctmgr -i add $clu $nams=$tc1,$tc2 $fs=$fs1 $mc=$mc1 $mj=$mj1 $mn=$mn1 $mw=$mw1] -expect { - -re "Adding Cluster" { - incr acmatches - exp_continue +# +proc _add_cluster {name} { + global sacctmgr timeout + + set exit_code 0 + set matches 0 + + if { ![string length $name] } { + send_user "FAILURE: we need a name to add\n" + return 1 } + + set my_pid [spawn $sacctmgr -i add cluster $name] + expect { + -re "(There was a problem|Unknown condition|Bad format on|Bad MaxWall|Unknown option)" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "Problem getting" { + send_user "FAILURE: there was a problem getting information from the database\n" + incr exit_code 1 + } + -re "Problem adding" { + send_user "FAILURE: there was an unknwon problem\n" + incr exit_code 1 + } + -re "No associations" { + send_user "FAILURE: your command didn't return anything\n" + incr exit_code 1 + } + -re "Adding Cluster" { + incr matches + exp_continue + } timeout { - send_user "\nFAILURE: sacctmgr add not responding\n" - slow_kill $sadd_pid - set exit_code 1 + send_user "\nFAILURE: sacctmgr add not responding\n" + slow_kill $my_pid + exit_code 1 + } + eof { + wait + } } - eof { - wait + + if {$matches != 1} { + send_user "\nFAILURE: sacctmgr had a problem adding clusters + got $matches\n" + incr exit_code 1 } -} -if {$acmatches != 1} { - send_user "\nFAILURE: sacctmgr had a problem adding clusters - got $acmatches\n" - set exit_code 1 + if { ![check_acct_associations] } { + send_user "\nFAILURE: Our associations don't line up\n" + incr exit_code 1 + } + + return $exit_code } -if { ![check_acct_associations] } { - send_user "\nFAILURE: Our associations don't line up\n" - set exit_code 1 +# +# Use sacctmgr to remove the test cluster +# +proc _remove_cluster {name} { + global sacctmgr timeout + + set exit_code 0 + set matches 0 + set nothing 0 + + if { ![string length $name] } { + send_user "FAILURE: we need a name to remove\n" + return 1 + } + + set my_pid [spawn $sacctmgr -i delete cluster $name] + expect { + -re "(There was a problem|Unknown condition|Bad format on|Bad MaxWall|Unknown option)" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "Problem getting" { + send_user "FAILURE: there was a problem getting information from the database\n" + incr exit_code 1 + } + -re "Problem adding" { + send_user "FAILURE: there was an unknwon problem\n" + incr exit_code 1 + } + -re "No associations" { + send_user "FAILURE: your command didn't return anything\n" + incr exit_code 1 + } + -re "Deleting clusters" { + incr matches + exp_continue + } + -re " Nothing deleted" { + incr matches + set nothing 1 + exp_continue + } + timeout { + send_user "\nFAILURE: sacctmgr delete not responding\n" + slow_kill $my_pid + incr exit_code 1 + } + eof { + wait + } + } + + if {$matches != 1} { + send_user "\nFAILURE: sacctmgr had a problem deleting cluster got $matches\n" + incr exit_code 1 + } + if { !$nothing } { + if { ![check_acct_associations] } { + send_user "\nFAILURE: Our associations don't line up\n" + incr exit_code 1 + } + } + + return $exit_code } # # Use sacctmgr to add an account # -set sadel_pid [spawn $sacctmgr -i $add $acc $clu=$tc1,$tc2 $des="$ds1" $fs=$fs1 $mc=$mc1 $mj=$mj1 $mn=$mn1 $mw=$mw1 $nams=$nm1,$nm2,$nm3 $org="$or1" $qs=$qs1] -expect { - -re "Adding Account" { - incr aamatches - exp_continue +proc _add_acct { cluster name } { + global sacctmgr timeout + + set exit_code 0 + set matches 0 + + if { ![string length $name] } { + send_user "FAILURE: we need a name to add\n" + return 1 } - timeout { - send_user "\nFAILURE: sacctmgr add not responding\n" - slow_kill $sadd_pid - set exit_code 1 + + set command "$name" + + if { [string length $cluster] } { + set command "$command cluster=$cluster" } - eof { - wait + + set my_pid [eval spawn $sacctmgr -i add account $command] + expect { + -re "(There was a problem|Unknown condition|Bad format on|Bad MaxWall|Unknown option)" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "Problem getting" { + send_user "FAILURE: there was a problem getting information from the database\n" + incr exit_code 1 + } + -re "Problem adding" { + send_user "FAILURE: there was an unknwon problem\n" + incr exit_code 1 + } + -re "No associations" { + send_user "FAILURE: your command didn't return anything\n" + incr exit_code 1 + } + -re "Adding Account" { + incr matches + exp_continue + } + -re "Associations" { + incr matches + exp_continue + } + timeout { + send_user "\nFAILURE: sacctmgr add not responding\n" + slow_kill $my_pid + incr exit_code 1 + } + eof { + wait + } + } + + if {$matches != 2} { + send_user "\nFAILURE: sacctmgr had a problem adding account. + got $matches\n" + incr exit_code 1 + } + + if { ![check_acct_associations] } { + send_user "\nFAILURE: Our associations don't line up\n" + incr exit_code 1 } + return $exit_code } -if {$aamatches != 1} { - send_user "\nFAILURE: sacctmgr had a problem adding account. - got $aamatches\n" - set exit_code 1 +# +# Use sacctmgr to remove an account +# +proc _remove_acct { cluster name } { + global sacctmgr timeout + + set exit_code 0 + set matches 0 + set nothing 1 + set check "Deleting account" + + if { ![string length $name] } { + send_user "FAILURE: we need a name to remove\n" + return 1 + } + + set command "$name" + + if { [string length $cluster] } { + set command "$command cluster=$cluster" + set check "Deleting account associations" + } + + set my_pid [eval spawn $sacctmgr -i delete account $command] + expect { + -re "(There was a problem|Unknown condition|Bad format on|Bad MaxWall|Unknown option)" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "Problem getting" { + send_user "FAILURE: there was a problem getting information from the database\n" + incr exit_code 1 + } + -re "Problem adding" { + send_user "FAILURE: there was an unknwon problem\n" + incr exit_code 1 + } + -re "No associations" { + send_user "FAILURE: your command didn't return anything\n" + incr exit_code 1 + } + -re "$check" { + incr matches + exp_continue + } + -re " Nothing deleted" { + incr matches + set nothing 1 + exp_continue + } + timeout { + send_user "\nFAILURE: sacctmgr add not responding\n" + slow_kill $my_pid + incr exit_code 1 + } + eof { + wait + } + } + + if {$matches != 1} { + send_user "\nFAILURE: sacctmgr had a problem deleting account. + got $matches\n" + incr exit_code 1 + } + + if { !$nothing } { + if { ![check_acct_associations] } { + send_user "\nFAILURE: Our associations don't line up\n" + incr exit_code 1 + } + } + + return $exit_code } # -# Use sacctmgr to list the test accounts +# Use sacctmgr to modify an account # -set ac_list_pid [spawn $sacctmgr -n list $acc withassoc] -expect { - -re "$nm1 *$ds1 *$or1 *$qs1 *$tc1 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lmatches - exp_continue +proc _mod_acct { cluster name desc org parent fs maxcpu maxjob maxnodes maxwall wdesc worg} { + global sacctmgr timeout + + set exit_code 0 + set matches 0 + set expected 0 + set acct_stuff 0 + set assoc_stuff 0 + + if { ![string length $name] } { + send_user "FAILURE: we need a name to modify\n" + return 1 } - -re "$nm1 *$ds1 *$or1 *$qs1 *$tc2 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lmatches - exp_continue + + #set up the where + set wcommand "where $name" + + if { [string length $cluster] } { + set wcommand "$wcommand cluster=$cluster" } - -re "$nm2 *$ds1 *$or1 *$qs1 *$tc1 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lmatches - exp_continue + + if { [string length $wdesc] } { + set wcommand "$wcommand description='$wdesc'" } - -re "$nm2 *$ds1 *$or1 *$qs1 *$tc2 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lmatches - exp_continue + + if { [string length $worg] } { + set wcommand "$wcommand organization='$worg'" } - -re "$nm3 *$ds1 *$or1 *$qs1 *$tc1 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lmatches - exp_continue + + #set up the set + set scommand "set" + if { [string length $parent] } { + set scommand "$scommand parent=$parent" + set assoc_stuff 1 + } + + if { [string length $fs] } { + set scommand "$scommand fairshare=$fs" + set assoc_stuff 1 + } + + if { [string length $maxcpu] } { + set scommand "$scommand maxc=$maxcpu" + set assoc_stuff 1 + } + + if { [string length $maxjob] } { + set scommand "$scommand maxj=$maxjob" + set assoc_stuff 1 + } + + if { [string length $maxnodes] } { + set scommand "$scommand maxn=$maxnodes" + set assoc_stuff 1 + } + + if { [string length $maxwall] } { + set scommand "$scommand maxw=$maxwall" + set assoc_stuff 1 + } + + if { [string length $desc] } { + set scommand "$scommand description='$desc'" + set acct_stuff 1 + } + + if { [string length $org] } { + set scommand "$scommand organization='$org'" + set acct_stuff 1 + } + + incr expected $acct_stuff + incr expected $assoc_stuff + + set my_pid [eval spawn $sacctmgr -i modify account $scommand $wcommand ] + expect { + -re "(There was a problem|Unknown condition|Bad format on|Bad MaxWall|Unknown option)" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "Problem getting" { + send_user "FAILURE: there was a problem getting information from the database\n" + incr exit_code 1 + } + -re "Problem adding" { + send_user "FAILURE: there was an unknwon problem\n" + incr exit_code 1 + } + -re "No associations" { + send_user "FAILURE: your command didn't return anything\n" + incr exit_code 1 + } + -re "Modified accounts" { + incr matches + exp_continue + } + -re "Modified account associations" { + incr matches + exp_continue + } + timeout { + send_user "\nFAILURE: sacctmgr add not responding\n" + slow_kill $my_pid + incr exit_code 1 + } + eof { + wait + } + } + + if {$matches != $expected} { + send_user "\nFAILURE: sacctmgr had a problem modifying account. + got $matches needed $expected\n" + incr exit_code 1 + } + + if { ![check_acct_associations] } { + send_user "\nFAILURE: Our associations don't line up\n" + incr exit_code 1 } - -re "$nm3 *$ds1 *$or1 *$qs1 *$tc2 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lmatches + return $exit_code +} + +#make sure we have a clean system +_remove_cluster "$tc1,$tc2" +_remove_acct "" "$nm1,$nm2,$nm3" + +#add cluster +incr exit_code [_add_cluster "$tc1,$tc2"] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code +} + +#add accounts +incr exit_code [_add_acct "$tc1,$tc2" "$nm1,$nm2,$nm3"] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code +} + +# OK This is the real test, first test change the desc and org of the accounts +incr exit_code [_mod_acct "" "$nm1,$nm2,$nm3" $ds2 $or2 "" "" "" "" "" "" "" ""] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code +} + +# +# Use sacctmgr to list the test account modifications +# +set matches 0 +set my_pid [spawn $sacctmgr -n -p list account acc=$nm1,$nm2,$nm3 format="Account,Desc,Org"] +expect { + -re "There was a problem" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "($nm1|$nm2|$nm3)\\\|$ds2\\\|$or2\\\|" { + incr matches exp_continue } timeout { send_user "\nFAILURE: sacctmgr list associations not responding\n" - slow_kill $ac_list_pid - set exit_code 1 + slow_kill $my_pid + incr exit_code 1 } eof { wait } } - -if {$lmatches != 6} { - send_user "\nFAILURE: Accounts addition not correct.\n" - set exit_code 1 +if {$matches != 3} { + send_user "\nFAILURE: Account modification 1 incorrect with only $matches.\n" + incr exit_code 1 } -if { ![check_acct_associations] } { - send_user "\nFAILURE: Our associations don't line up\n" - set exit_code 1 +# Next, test change the limits of the accounts +incr exit_code [_mod_acct "" "$nm1,$nm2,$nm3" "" "" "" $fs2 $mc2 $mj2 $mn2 $mw2 "" ""] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code } # -# Use sacctmgr to modify an account +# Use sacctmgr to list the test account modifications # -set sadel_pid [spawn $sacctmgr -i $mod $acc set $des="$ds2" $fs=$fs2 $mc=$mc2 $mj=$mj2 $mn=$mn2 $mw=$mw2 $org="$or2" $par=$nm1 where $des="$ds1" $nams=$nm2,$nm3 $org="$or1" ] +set matches 0 +set my_pid [spawn $sacctmgr -n -p list assoc acc=$nm1,$nm2,$nm3 format="Account,Cluster,Fairshare,MaxC,MaxJ,MaxN,MaxW"] expect { - -re "Modified accounts" { - incr ammatches + -re "There was a problem" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "($nm1|$nm2|$nm3)\\\|($tc1|$tc2)\\\|$fs2\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\|" { + incr matches exp_continue } timeout { - send_user "\nFAILURE: sacctmgr add not responding\n" - slow_kill $sadd_pid - set exit_code 1 + send_user "\nFAILURE: sacctmgr list associations not responding\n" + slow_kill $my_pid + incr exit_code 1 } eof { wait } } - -if {$ammatches != 1} { - send_user "\nFAILURE: sacctmgr had a problem modifying account. - got $ammatches\n" - set exit_code 1 +if {$matches != 6} { + send_user "\nFAILURE: Account modification 2 incorrect with only $matches.\n" + incr exit_code 1 } -if { ![check_acct_associations] } { - send_user "\nFAILURE: Our associations don't line up\n" - set exit_code 1 +# Next, test change the desc and limits of the accounts +incr exit_code [_mod_acct "" "$nm1,$nm3" $ds1 $or1 "" -1 -1 -1 -1 -1 "" ""] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code } # # Use sacctmgr to list the test account modifications # -set ac_list_pid [spawn $sacctmgr -n list $acc withassoc] +set matches 0 +set my_pid [eval spawn $sacctmgr -n -p list acct withassoc acc=$nm1,$nm2,$nm3 format="Account,Desc,Org,Cluster,Fairshare,MaxC,MaxJ,MaxN,MaxW"] expect { - -re "$nm1 *$ds1 *$or1 *$qs1 *$tc1 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lamatches - exp_continue + -re "There was a problem" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 } - -re "$nm1 *$ds1 *$or1 *$qs1 *$tc2 *root *$fs1 *$mc1 *$mj1 *$mn1 *$mw1" { - incr lamatches + # Any time you use () around something you need to combine all + # those things together since you can miss some and they be thrown away + -re "(($nm1|$nm3)\\\|$ds1\\\|$or1\\\|($tc1|$tc2)\\\|1\\\|\\\|\\\|\\\|\\\||$nm2\\\|$ds2\\\|$or2\\\|($tc1|$tc2)\\\|$fs2\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\|)" { + incr matches exp_continue } - -re "$nm2 *$ds2 *$or2 *$qs1 *$tc1 *$nm1 *$fs2 *$mc2 *$mj2 *$mn2 *$mw2" { - incr lamatches - exp_continue + timeout { + send_user "\nFAILURE: sacctmgr list associations not responding\n" + slow_kill $my_pid + incr exit_code 1 } - -re "$nm2 *$ds2 *$or2 *$qs1 *$tc2 *$nm1 *$fs2 *$mc2 *$mj2 *$mn2 *$mw2" { - incr lamatches - exp_continue + eof { + wait } - -re "$nm3 *$ds2 *$or2 *$qs1 *$tc1 *$nm1 *$fs2 *$mc2 *$mj2 *$mn2 *$mw2" { - incr lamatches +} + +if {$matches != 6} { + send_user "\nFAILURE: Account modification 2 incorrect with $matches.\n" + incr exit_code 1 +} + +# Next, test change the parent of $n3 to be $n2 on $tc1 sibling to be a child +incr exit_code [_mod_acct "$tc1" "$nm3" "" "" "$nm2" "" "" "" "" "" "" ""] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code +} + +# +# Use sacctmgr to list the test account modifications +# +set matches 0 +set my_pid [eval spawn $sacctmgr -n -p list assoc acc=$nm3 format="Account,ParentN,Cluster,Fairshare,MaxC,MaxJ,MaxN,MaxW"] +expect { + -re "There was a problem" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "$nm3\\\|$nm2\\\|$tc1\\\|1\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\|" { + incr matches exp_continue } - -re "$nm3 *$ds2 *$or2 *$qs1 *$tc2 *$nm1 *$fs2 *$mc2 *$mj2 *$mn2 *$mw2" { - incr lamatches + -re "$nm3\\\|root\\\|$tc2\\\|1\\\|\\\|\\\|\\\|\\\|" { + incr matches exp_continue } timeout { send_user "\nFAILURE: sacctmgr list associations not responding\n" - slow_kill $ac_list_pid - set exit_code 1 + slow_kill $my_pid + incr exit_code 1 } eof { wait } } +if {$matches != 2} { + send_user "\nFAILURE: Account modification 3 incorrect with $matches.\n" + incr exit_code 1 +} -if {$lamatches != 6} { - send_user "\nFAILURE: Account modification incorrect.\n" - set exit_code 1 +# Next, test change the parent of $n2 to be $n3 on $tc1 +# making the child the parent +incr exit_code [_mod_acct "$tc1" "$nm2" "" "" "$nm3" "" "" "" "" "" "" ""] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code } # -# Use sacctmgr to delete the test account +# Use sacctmgr to list the test account modifications # -set sadel_pid [spawn $sacctmgr -i $del $acc $nm1,$nm2,$nm3] +set matches 0 +set my_pid [eval spawn $sacctmgr -n -p list assoc acc=$nm3,$nm2 format="Account,ParentN,Cluster,Fairshare,MaxC,MaxJ,MaxN,MaxW"] expect { - -re "Deleting account" { - incr damatches + -re "There was a problem" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "($nm2\\\|root\\\|$tc2\\\|$fs2\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\||$nm2\\\|$nm3\\\|$tc1\\\|$fs2\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\||$nm3\\\|root\\\|($tc1|$tc2)\\\|1\\\|\\\|\\\|\\\|\\\|)" { + incr matches exp_continue } timeout { - send_user "\nFAILURE: sacctmgr delete not responding\n" - slow_kill $sadel_pid - set exit_code 1 + send_user "\nFAILURE: sacctmgr list associations not responding\n" + slow_kill $my_pid + incr exit_code 1 } eof { wait } } - -if {$damatches != 1} { - send_user "\nFAILURE: sacctmgr had a problem deleting cluster got $damatches\n" - set exit_code 1 +if {$matches != 4} { + send_user "\nFAILURE: Account modification 3 incorrect with $matches.\n" + incr exit_code 1 } -if { ![check_acct_associations] } { - send_user "\nFAILURE: Our associations don't line up\n" - set exit_code 1 + +# Next, test change the parent of $n3 to be $n2 on $tc1 again +# only this time the parent will become the child instead of it being a sibling. +incr exit_code [_mod_acct "$tc1" "$nm3" "" "" "$nm2" "" "" "" "" "" "" ""] +if { $exit_code } { + _remove_acct "" "$nm1,$nm2,$nm3" + _remove_cluster "$tc1,$tc2" + exit $exit_code } # -# Use sacctmgr to delete the test cluster +# Use sacctmgr to list the test account modifications # -set sadel_pid [spawn $sacctmgr -i $del $clu $tc1,$tc2] +set matches 0 +set my_pid [eval spawn $sacctmgr -n -p list assoc acc=$nm3,$nm2 format="Account,ParentN,Cluster,Fairshare,MaxC,MaxJ,MaxN,MaxW"] expect { - -re "Deleting clusters" { - incr dcmatches + -re "There was a problem" { + send_user "FAILURE: there was a problem with the sacctmgr command\n" + incr exit_code 1 + } + -re "($nm2\\\|root\\\|($tc1|$tc2)\\\|$fs2\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\||$nm3\\\|$nm2\\\|$tc1\\\|1\\\|$mc2\\\|$mj2\\\|$mn2\\\|$mw2\\\||$nm3\\\|root\\\|$tc2\\\|1\\\|\\\|\\\|\\\|\\\|)" { + incr matches exp_continue } timeout { - send_user "\nFAILURE: sacctmgr delete not responding\n" - slow_kill $sadel_pid - set exit_code 1 + send_user "\nFAILURE: sacctmgr list associations not responding\n" + slow_kill $my_pid + incr exit_code 1 } eof { wait } } - -if {$dcmatches != 1} { - send_user "\nFAILURE: sacctmgr had a problem deleting cluster got $dcmatches\n" - set exit_code 1 +if {$matches != 4} { + send_user "\nFAILURE: Account modification 3 incorrect with $matches.\n" + incr exit_code 1 } -if { ![check_acct_associations] } { - send_user "\nFAILURE: Our associations don't line up\n" - set exit_code 1 -} + + + + + + +# This is the end below here + +incr exit_code [_remove_acct "$tc1,$tc2" "$nm1,$nm2,$nm3"] +incr exit_code [_remove_acct "" "$nm1,$nm2,$nm3"] +incr exit_code [_remove_cluster "$tc1,$tc2"] if {$exit_code == 0} { send_user "\nSUCCESS\n" - } else { +} else { send_user "\nFAILURE\n" - } - +} exit $exit_code + diff --git a/testsuite/expect/test21.17 b/testsuite/expect/test21.17 index 6eff09152b6b01abeaf0d7f0e3eff3dcc00669b2..013e5a60b25c92c1273bdf17217bd8f7fda59d9c 100755 --- a/testsuite/expect/test21.17 +++ b/testsuite/expect/test21.17 @@ -295,7 +295,7 @@ expect { } if {$dlumatches != 8} { - send_user "\nFAILURE: sacctmgr had a problem listing user got $dumatches\n" + send_user "\nFAILURE: sacctmgr had a problem listing user got $dumatches of 8\n" set exit_code 1 } @@ -383,8 +383,8 @@ if { ![check_acct_associations] } { if {$exit_code == 0} { send_user "\nSUCCESS\n" - } else { +} else { send_user "\nFAILURE\n" - } +} exit $exit_code diff --git a/testsuite/expect/test6.13 b/testsuite/expect/test6.13 index 9f41d43af601d79cc66e9524abf5dd4dedc29572..a2945d5bfbdc7281ed72eaf868b40efdde1bc39e 100755 --- a/testsuite/expect/test6.13 +++ b/testsuite/expect/test6.13 @@ -46,7 +46,7 @@ print_header $test_id # of the ulimit program is inconsistent across systems. # exec rm -f $file_prog $file_in $file_out -exec cc -o $file_prog $file_prog.c +exec $bin_cc -O -o $file_prog ${file_prog}.c make_bash_script $file_in " $srun ./$file_prog " diff --git a/testsuite/expect/test7.1 b/testsuite/expect/test7.1 index ab4923b0fd6ea4c2da6ed246ea3612da9f59b42f..0c47af57e09f180f71b8680d168d2ccc01cb9e61 100755 --- a/testsuite/expect/test7.1 +++ b/testsuite/expect/test7.1 @@ -54,7 +54,7 @@ expect { exp_continue } timeout { - send_user "\nFAILURE: srun not responding\n" + send_user "\nFAILURE: sbatch not responding\n" slow_kill $sbatch_pid exit 1 } @@ -69,7 +69,7 @@ expect { exp_continue } timeout { - send_user "\nFAILURE: srun not responding\n" + send_user "\nFAILURE: sbatch not responding\n" slow_kill $sbatch_pid exit 1 } diff --git a/testsuite/expect/test7.11 b/testsuite/expect/test7.11 new file mode 100755 index 0000000000000000000000000000000000000000..fc8998ba80fba6434822d37a65b9561d85d2886a --- /dev/null +++ b/testsuite/expect/test7.11 @@ -0,0 +1,253 @@ +#!/usr/bin/expect +############################################################################ +# Purpose: Test of SLURM functionality +# Test of SPANK plugin +# +# Output: "TEST: #.#" followed by "SUCCESS" if test was successful, OR +# "FAILURE: ..." otherwise with an explanation of the failure, OR +# anything else indicates a failure mode that must be investigated. +############################################################################ +# Copyright (C) 2008 Lawrence Livermore National Security. +# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). +# Written by Morris Jette <jette1@llnl.gov> +# LLNL-CODE-402394. +# +# This file is part of SLURM, a resource management program. +# For details, see <http://www.llnl.gov/linux/slurm/>. +# +# SLURM is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# SLURM is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with SLURM; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +############################################################################ +source ./globals + +set test_id "7.11" +set cwd "[$bin_pwd]" +set exit_code 0 +set file_in "${cwd}/test${test_id}.in" +set file_out "${cwd}/test${test_id}.out" +set file_prog "${cwd}/test${test_id}.prog" +set orig_spank_conf "${cwd}/test${test_id}.orig_conf" +set new_spank_conf "${cwd}/test${test_id}.new_conf" +set spank_out "${cwd}/test${test_id}.spank.out" + +print_header $test_id + +if {[test_super_user] == 0} { + send_user "\nWARNING: This test must be run as SlurmUser\n" + exit 0 +} +if {[test_aix] == 1} { + send_user "WARNING: Test is incompatible with AIX\n" + exit 0 +} + +# +# Build the plugin +# +exec $bin_rm -f ${file_prog}.so +exec $bin_cc -shared -I${slurm_dir}/include -o ${file_prog}.so ${file_prog}.c + +# +# Locate slurm.conf's directory, copy the original plugstack.conf file +# and create an updated one using our new plugin +# +log_user 0 +set config_dir "" +spawn $scontrol show config +expect { + -re "SLURM_CONFIG_FILE.*= (/.*)/slurm.conf" { + set config_dir $expect_out(1,string) + exp_continue + } + eof { + wait + } +} +log_user 1 +if {[string compare $config_dir ""] == 0} { + send_user "\nFAILURE: Could not locate slurm.conf directory\n" + exit 1 +} +set spank_conf_file ${config_dir}/plugstack.conf +exec $bin_rm -f $orig_spank_conf $new_spank_conf $file_out $spank_out +if {[file exists $spank_conf_file]} { + spawn $bin_cat $spank_conf_file + expect { + -re "test${test_id}" { + send_user "\nFAILURE: spank plugin includes vestigial test${test_id}\n" + send_user " You probably should manually remove it from $spank_conf_file.\n" + send_user " It was probably left over from some previous test failure.\n" + exit 1 + } + eof { + wait + } + } + + exec $bin_cp $spank_conf_file $orig_spank_conf + exec $bin_cp $spank_conf_file $new_spank_conf +} else { + exec $bin_cp /dev/null $new_spank_conf +} + +exec $bin_echo "required ${file_prog}.so ${spank_out}" >>$new_spank_conf +spawn $bin_cp $new_spank_conf $spank_conf_file +expect { + -re "Permission denied" { + send_user "\nWARNING: User lacks permission to update plugstack_conf file\n" + exit 0 + } + eof { + wait + } +} + +# +# Test of srun help message +# +set matches 0 +set srun_pid [spawn $srun --help] +expect { + -re "Component of slurm test suite" { + incr matches + exp_continue + } + timeout { + send_user "\nFAILURE: srun not responding\n" + slow_kill $srun_pid + set exit_code 1 + } + eof { + wait + } +} +if {$matches != 1} { + send_user "\nFAILURE: spank help message not in srun help message\n" + set exit_code 1 +} + +# +# Test of locally logged messages(). +# We update the plugstatck.conf in this script since NFS delays may +# prevent it from having the same state as the submit host. +# +make_bash_script $file_in " + $bin_cp $new_spank_conf $spank_conf_file + $srun --test_suite=5 $bin_uname + if test -f $orig_spank_conf + then + $bin_cp $orig_spank_conf $spank_conf_file + fi +" +spawn $sbatch -N1 -t1 -o $file_out $file_in +expect { + -re timeout { + send_user "\nFAILURE: sbatch not responding\n" + set exit_code 1 + } + eof { + wait + } +} + +# NOTE: spank logs from sbatch and srun would be intermingled here +if {[wait_for_file $file_out] == 0} { + send_user "\n\n" + set match1 0 + set match2 0 + set match3 0 + spawn $bin_cat $file_out + expect { + -re "error" { + send_user "\nFAILURE: some error happened\n" + set exit_code 1 + exp_continue + } + -re "_test_opt_process: test_suite: opt_arg=5" { + set match1 1 + exp_continue + } + -re "slurm_spank_local_user_init" { + set match2 1 + exp_continue + } + -re "slurm_spank_exit: opt_arg=5" { + set match3 1 + exp_continue + } + eof { + wait + } + } + if {[expr $match1 + $match2 + $match3] != 3} { + send_user "\nFAILURE: local (srun) spank plugin failure\n" + set exit_code 1 + } else { + send_user "\nlocal (srun) spank plugin success\n" + } +} else { + set exit_code 1 +} + +# +# Test for slurmd output in file +# +if {[wait_for_file $spank_out] == 0} { + send_user "\n\n" + set matches 0 + spawn $bin_cat $spank_out + expect { + -re "slurm_spank_task_init: opt_arg=5" { + incr matches + exp_continue + } + -re "spank_get_item: my_uid=" { + incr matches + exp_continue + } + -re "slurm_spank_exit: opt_arg=5" { + incr matches + exp_continue + } + eof { + wait + } + } + if {$matches != 3} { + send_user "\nFAILURE: remote (slurmd) spank plugin failure\n" + set exit_code 1 + } else { + send_user "\n remote (slurmd) spank plugin success\n" + } +} else { + send_user "\nWARNING: This can be caused by the plugstack.conf file not\n" + send_user " being propagated to the compute node or not being in a\n" + send_user " shared file system.\n" + set exit_code 1 +} + +# +# Restore the original plugstack +# +if {[file exists $orig_spank_conf]} { + exec $bin_cp $orig_spank_conf $spank_conf_file +} else { + exec $bin_rm -f $spank_conf_file +} + +if {$exit_code == 0} { + exec $bin_rm -f $orig_spank_conf $new_spank_conf $file_out $spank_out ${file_prog}.so + send_user "\nSUCCESS\n" +} +exit $exit_code diff --git a/testsuite/expect/test7.11.prog.c b/testsuite/expect/test7.11.prog.c new file mode 100644 index 0000000000000000000000000000000000000000..91496061745cce14356d3fb7060853a9e57188da --- /dev/null +++ b/testsuite/expect/test7.11.prog.c @@ -0,0 +1,120 @@ +/*****************************************************************************\ + * prog7.11.prog.c - SPANK plugin for testing purposes + ***************************************************************************** + * Copyright (C) 2008 Lawrence Livermore National Security. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Morris Jette <jette1@llnl.gov> + * LLNL-CODE-402394. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +\*****************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/resource.h> +#include <sys/types.h> + +#include <slurm/spank.h> + +/* + * All spank plugins must define this macro for the SLURM plugin loader. + */ +SPANK_PLUGIN(test_suite, 1); + +static int opt_arg = 0; +static char *opt_out_file = NULL; + +static int _test_opt_process(int val, const char *optarg, int remote); + +/* + * Provide a --renice=[prio] option to srun: + */ +struct spank_option spank_options[] = +{ + { "test_suite", "[opt_arg]", "Component of slurm test suite.", 2, 0, + _test_opt_process + }, + SPANK_OPTIONS_TABLE_END +}; + +static int _test_opt_process(int val, const char *optarg, int remote) +{ + opt_arg = atoi(optarg); + if (!remote) + slurm_info("_test_opt_process: test_suite: opt_arg=%d", opt_arg); + + return (0); +} + +/* Called from both srun and slurmd */ +int slurm_spank_init(spank_t sp, int ac, char **av) +{ + if (spank_remote(sp) && (ac == 1)) + opt_out_file = strdup(av[0]); + + return (0); +} + +/* Called from both srun and slurmd, not tested here +int slurm_spank_init_post_opt(spank_t sp, int ac, char **av) */ + +/* Called from srun only */ +slurm_spank_local_user_init(spank_t sp, int ac, char **av) +{ + slurm_info("slurm_spank_local_user_init"); + + return (0); +} + +/* Called from slurmd only */ +int slurm_spank_task_init(spank_t sp, int ac, char **av) +{ + uid_t my_uid; + + if (opt_out_file && opt_arg) { + FILE *fp = fopen(opt_out_file, "a"); + if (!fp) + return (-1); + fprintf(fp, "slurm_spank_task_init: opt_arg=%d\n", opt_arg); + if (spank_get_item(sp, S_JOB_UID, &my_uid) == ESPANK_SUCCESS) + fprintf(fp, "spank_get_item: my_uid=%d\n", my_uid); + fclose(fp); + } + return (0); +} + +/* Called from slurmd only, not tested here +int slurm_spank_task_post_fork(spank_t sp, int ac, char **av) */ + +/* Called from slurmd only, not tested here +int slurm_spank_task_exit(spank_t sp, int ac, char **av) */ + +/* Called from both srun and slurmd */ +int slurm_spank_exit(spank_t sp, int ac, char **av) +{ + if (opt_out_file && opt_arg) { + FILE *fp = fopen(opt_out_file, "a"); + if (!fp) + return (-1); + fprintf(fp, "slurm_spank_exit: opt_arg=%d\n", opt_arg); + fclose(fp); + } else if (opt_arg) + slurm_info("slurm_spank_exit: opt_arg=%d", opt_arg); + return (0); +} diff --git a/testsuite/expect/test7.3 b/testsuite/expect/test7.3 index 2fe04f5df123caf17d041353461470dc06a3416d..03619fb34fb74d02318710567bd3d8d24cde98d5 100755 --- a/testsuite/expect/test7.3 +++ b/testsuite/expect/test7.3 @@ -50,7 +50,7 @@ if {[test_front_end] != 0} { # file delete $io_prog $test_prog -exec $bin_make -f /dev/null $io_prog +exec $bin_cc -O -o $io_prog ${io_prog}.c exec $bin_chmod 700 $io_prog send_user "slurm_dir is $slurm_dir\n" diff --git a/testsuite/expect/test7.9 b/testsuite/expect/test7.9 index e58d5243a5952d95a26a3f5024c35d2136354ea0..1915f4d2dd34b7b480331187be70755f03b87485 100755 --- a/testsuite/expect/test7.9 +++ b/testsuite/expect/test7.9 @@ -92,7 +92,7 @@ if {$invalid == 1} { # of the ulimit program is inconsistent across systems. # exec $bin_rm -f $file_prog $file_in $file_out -exec $bin_make -f /dev/null $file_prog +exec $bin_cc -O -o $file_prog ${file_prog}.c make_bash_script $file_in " $bin_echo 'testing within script'