Skip to content
Snippets Groups Projects
Commit b70918a5 authored by Moe Jette's avatar Moe Jette
Browse files
parent 08e73a57
No related branches found
No related tags found
No related merge requests found
...@@ -130,6 +130,7 @@ documents those changes that are of interest to users and admins. ...@@ -130,6 +130,7 @@ documents those changes that are of interest to users and admins.
-- Avoid printing negative job run time in squeue due to clock skew. -- Avoid printing negative job run time in squeue due to clock skew.
-- In sched/wiki and sched/wiki2, add support for wiki.conf option -- In sched/wiki and sched/wiki2, add support for wiki.conf option
HidePartitionJobs (see man pages for details). HidePartitionJobs (see man pages for details).
-- Update to srun/sbatch --get-user-env option logic (needed by Moab).
* Changes in SLURM 1.2.21 * Changes in SLURM 1.2.21
========================= =========================
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* This program must execute as user root. * This program must execute as user root.
***************************************************************************** *****************************************************************************
* Copyright (C) 2007 The Regents of the University of California. * Copyright (C) 2007-2008 The Regents of the University of California.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Morris Jette <jette1@llnl.gov>. * Written by Morris Jette <jette1@llnl.gov>.
* UCRL-CODE-226842. * UCRL-CODE-226842.
...@@ -53,16 +53,18 @@ ...@@ -53,16 +53,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#define DEBUG 0 #define _DEBUG 0
#define SU_WAIT_MSEC 8000 #define SU_WAIT_MSEC 8000
static long int _build_cache(char *user_name, char *cache_dir); static long int _build_cache(char *user_name, char *cache_dir);
static int _get_cache_dir(char *buffer, int buf_size); static int _get_cache_dir(char *buffer, int buf_size);
static void _parse_line(char *in_line, char **user_name, int *user_id); static int _parse_line(char *in_line, char **user_name, int *user_id);
main (int argc, char **argv) main (int argc, char **argv)
{ {
...@@ -80,19 +82,17 @@ main (int argc, char **argv) ...@@ -80,19 +82,17 @@ main (int argc, char **argv)
exit(1); exit(1);
strncat(cache_dir, "/env_cache", sizeof(cache_dir)); strncat(cache_dir, "/env_cache", sizeof(cache_dir));
if (mkdir(cache_dir, 0500) && (errno != EEXIST)) { if (mkdir(cache_dir, 0500) && (errno != EEXIST)) {
printf("Could not create cache directory %s: %s", cache_dir, printf("Could not create cache directory %s: %s\n", cache_dir,
strerror(errno)); strerror(errno));
exit(1); exit(1);
} }
#if DEBUG
printf("cache_dir=%s\n", cache_dir); printf("cache_dir=%s\n", cache_dir);
#endif
for (i=1; i<argc; i++) { for (i=1; i<argc; i++) {
delta_t = _build_cache(argv[i], cache_dir); delta_t = _build_cache(argv[i], cache_dir);
#if DEBUG if (delta_t < ((SU_WAIT_MSEC * 0.8) * 1000))
printf("user %-8s time %ld usec\n", argv[i], delta_t); continue;
#endif printf("WARNING: user %-8s time %ld usec\n", argv[i], delta_t);
} }
if (i > 1) if (i > 1)
exit(0); exit(0);
...@@ -104,52 +104,76 @@ main (int argc, char **argv) ...@@ -104,52 +104,76 @@ main (int argc, char **argv)
} }
while (fgets(in_line, sizeof(in_line), passwd_fd)) { while (fgets(in_line, sizeof(in_line), passwd_fd)) {
_parse_line(in_line, &user_name, &user_id); if (_parse_line(in_line, &user_name, &user_id) < 0)
continue;
if (user_id <= 100) if (user_id <= 100)
continue; continue;
delta_t = _build_cache(user_name, cache_dir); delta_t = _build_cache(user_name, cache_dir);
#if DEBUG
if (delta_t < ((SU_WAIT_MSEC * 0.8) * 1000)) if (delta_t < ((SU_WAIT_MSEC * 0.8) * 1000))
continue; continue;
printf("user %-8s time %ld usec\n", user_name, delta_t); printf("WARNING: user %-8s time %ld usec\n", user_name, delta_t);
#endif
} }
fclose(passwd_fd); fclose(passwd_fd);
} }
/* Given a line from /etc/passwd, return the user_name and user_id */ /* Given a line from /etc/passwd, sets the user_name and user_id
static void _parse_line(char *in_line, char **user_name, int *user_id) * RET -1 if user can't login, 0 otherwise */
static int _parse_line(char *in_line, char **user_name, int *user_id)
{ {
char *tok; char *tok, *shell;
/* user name */
*user_name = strtok(in_line, ":"); *user_name = strtok(in_line, ":");
(void) strtok(NULL, ":"); (void) strtok(NULL, ":");
/* uid */
tok = strtok(NULL, ":"); tok = strtok(NULL, ":");
if (tok) if (tok)
*user_id = atoi(tok); *user_id = atoi(tok);
else { else {
printf("error parsing /etc/passwd: %s\n", in_line); printf("ERROR: parsing /etc/passwd: %s\n", in_line);
*user_id = 0; *user_id = 0;
} }
(void) strtok(NULL, ":"); /* gid */
(void) strtok(NULL, ":"); /* name */
(void) strtok(NULL, ":"); /* home */
shell = strtok(NULL, ":");
if (shell) {
tok = strchr(shell, '\n');
if (tok)
tok[0] = '\0';
if ((strcmp(shell, "/sbin/nologin") == 0) ||
(strcmp(shell, "/bin/false") == 0))
return -1;
}
return 0;
} }
/* For a given user_name, get his environment variable by executing /* For a given user_name, get his environment variable by executing
* "su - <user_name> -c env" and store the result in * "su - <user_name> -c env" and store the result in
* cache_dir/env_<user_name> * cache_dir/env_<user_name>
* Returns time to perform the operation in usec * Returns time to perform the operation in usec or -1 on error
*/ */
static long int _build_cache(char *user_name, char *cache_dir) static long int _build_cache(char *user_name, char *cache_dir)
{ {
FILE *su, *cache; FILE *cache;
char line[BUFSIZ], name[BUFSIZ], value[BUFSIZ], out_file[BUFSIZ]; char *line, *last, out_file[BUFSIZ], buffer[64 * 1024];
char *starttoken = "XXXXSLURMSTARTPARSINGHEREXXXX"; char *starttoken = "XXXXSLURMSTARTPARSINGHEREXXXX";
char *stoptoken = "XXXXSLURMSTOPPARSINGHEREXXXXX"; char *stoptoken = "XXXXSLURMSTOPPARSINGHEREXXXXX";
int fildes[2], found, fval, len, rc, timeleft; int fildes[2], found, fval, len, rc, timeleft;
int buf_read, buf_rem;
pid_t child; pid_t child;
struct timeval begin, now; struct timeval begin, now;
struct pollfd ufds; struct pollfd ufds;
long int delta_t; long int delta_t;
gettimeofday(&begin, NULL);
if (pipe(fildes) < 0) { if (pipe(fildes) < 0) {
perror("pipe"); perror("pipe");
return -1; return -1;
...@@ -166,13 +190,14 @@ static long int _build_cache(char *user_name, char *cache_dir) ...@@ -166,13 +190,14 @@ static long int _build_cache(char *user_name, char *cache_dir)
dup2(fildes[1], 1); dup2(fildes[1], 1);
close(2); close(2);
open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY);
snprintf(line, sizeof(line), snprintf(buffer, sizeof(buffer),
"echo; echo; echo; echo %s; env; echo %s", "/bin/echo; /bin/echo; /bin/echo; "
"/bin/echo %s; /bin/env; /bin/echo %s",
starttoken, stoptoken); starttoken, stoptoken);
#ifdef LOAD_ENV_NO_LOGIN #ifdef LOAD_ENV_NO_LOGIN
execl("/bin/su", "su", user_name, "-c", line, NULL); execl("/bin/su", "su", user_name, "-c", buffer, NULL);
#else #else
execl("/bin/su", "su", "-", user_name, "-c", line, NULL); execl("/bin/su", "su", "-", user_name, "-c", buffer, NULL);
#endif #endif
exit(1); exit(1);
} }
...@@ -180,30 +205,30 @@ static long int _build_cache(char *user_name, char *cache_dir) ...@@ -180,30 +205,30 @@ static long int _build_cache(char *user_name, char *cache_dir)
close(fildes[1]); close(fildes[1]);
if ((fval = fcntl(fildes[0], F_GETFL, 0)) >= 0) if ((fval = fcntl(fildes[0], F_GETFL, 0)) >= 0)
fcntl(fildes[0], F_SETFL, fval | O_NONBLOCK); fcntl(fildes[0], F_SETFL, fval | O_NONBLOCK);
su = fdopen(fildes[0], "r");
gettimeofday(&begin, NULL);
ufds.fd = fildes[0]; ufds.fd = fildes[0];
ufds.events = POLLIN; ufds.events = POLLIN;
ufds.revents = 0;
/* First look for the start token in the output */ /* Read all of the output from /bin/su into buffer */
len = strlen(starttoken);
found = 0; found = 0;
while (!found) { buf_read = 0;
bzero(buffer, sizeof(buffer));
while (1) {
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
timeleft = SU_WAIT_MSEC * 10; timeleft = SU_WAIT_MSEC * 10;
timeleft -= (now.tv_sec - begin.tv_sec) * 1000; timeleft -= (now.tv_sec - begin.tv_sec) * 1000;
timeleft -= (now.tv_usec - begin.tv_usec) / 1000; timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
if (timeleft <= 0) { if (timeleft <= 0) {
#if DEBUG #if _DEBUG
printf("timeout1\n"); printf("timeout1 for %s\n", user_name);
#endif #endif
break; break;
} }
if ((rc = poll(&ufds, 1, timeleft)) <= 0) { if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
if (rc == 0) { if (rc == 0) {
#if DEBUG #if _DEBUG
printf("timeout2\n"); printf("timeout2 for %s\n, user_name");
#endif #endif
break; break;
} }
...@@ -213,88 +238,97 @@ static long int _build_cache(char *user_name, char *cache_dir) ...@@ -213,88 +238,97 @@ static long int _build_cache(char *user_name, char *cache_dir)
break; break;
} }
if (!(ufds.revents & POLLIN)) { if (!(ufds.revents & POLLIN)) {
perror("POLLERR|POLLHUP"); if (ufds.revents & POLLHUP) { /* EOF */
#if _DEBUG
printf("POLLHUP for %s\n", user_name);
#endif
found = 1; /* success */
} else if (ufds.revents & POLLERR) {
printf("ERROR: POLLERR for %s\n", user_name);
} else {
printf("ERROR: poll() revents=%d for %s\n",
ufds.revents, user_name);
}
break; break;
} }
while (fgets(line, BUFSIZ, su)) { buf_rem = sizeof(buffer) - buf_read;
if (!strncmp(line, starttoken, len)) { if (buf_rem == 0) {
found = 1; printf("ERROR: buffer overflow for %s\n", user_name);
break; break;
} }
rc = read(fildes[0], &buffer[buf_read], buf_rem);
if (rc > 0)
buf_read += rc;
else if (rc == 0) { /* EOF */
#if _DEBUG
printf("EOF for %s\n", user_name);
#endif
found = 1; /* success */
break;
} else { /* error */
perror("read");
break;
} }
} }
close(fildes[0]);
if (!found) { if (!found) {
printf("Failed to get current user environment variables " printf("ERROR: Failed to load current user environment "
"for %s\n", user_name); "variables for %s\n", user_name);
close(fildes[0]); return -1;
gettimeofday(&now, NULL); }
delta_t = now.tv_sec - begin.tv_sec * 1000000;
delta_t += now.tv_usec - begin.tv_usec; /* First look for the start token in the output */
if (delta_t < (SU_WAIT_MSEC * 1000)) len = strlen(starttoken);
return (SU_WAIT_MSEC * 1000); found = 0;
return delta_t; line = strtok_r(buffer, "\n", &last);
while (!found && line) {
if (!strncmp(line, starttoken, len)) {
found = 1;
break;
}
line = strtok_r(NULL, "\n", &last);
}
if (!found) {
printf("ERROR: Failed to get current user environment "
"variables for %s\n", user_name);
return -1;
} }
snprintf(out_file, sizeof(out_file), "%s/%s", cache_dir, user_name); snprintf(out_file, sizeof(out_file), "%s/%s", cache_dir, user_name);
cache = fopen(out_file, "w"); cache = fopen(out_file, "w");
if (!cache) { if (!cache) {
printf("Could not create cache file %s: %s\n", out_file, printf("ERROR: Could not create cache file %s for %s: %s\n",
strerror(errno)); out_file, user_name, strerror(errno));
return -1;
} }
chmod(out_file, 0600);
/* Process environment variables until we find the stop token */
len = strlen(stoptoken); len = strlen(stoptoken);
found = 0; found = 0;
while (!found && cache) { line = strtok_r(NULL, "\n", &last);
gettimeofday(&now, NULL); while (!found && line) {
timeleft = SU_WAIT_MSEC * 10; if (!strncmp(line, stoptoken, len)) {
timeleft -= (now.tv_sec - begin.tv_sec) * 1000;
timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
if (timeleft <= 0) {
#if DEBUG
printf("timeout3\n");
#endif
break;
}
if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
if (rc == 0) {
#if DEBUG
printf("timeout4\n");
#endif
break;
}
if ((errno == EINTR) || (errno == EAGAIN))
continue;
perror("poll");
break;
}
if (!(ufds.revents & POLLIN)) {
perror("POLLERR|POLLHUP");
break;
}
/* stop at the line containing the stoptoken string */
if ((fgets(line, BUFSIZ, su) == 0) ||
(!strncmp(line, stoptoken, len))) {
found = 1; found = 1;
break; break;
} }
if (fprintf(cache, "%s\n",line) < 0) {
if (fputs(line, cache) == EOF) { printf("ERROR: Could not write cache file %s "
printf("Could not write cache file %s: %s\n", "for %s: %s\n",
out_file, strerror(errno)); out_file, user_name, strerror(errno));
found = 1; /* quit now */ found = 1; /* quit now */
} }
line = strtok_r(NULL, "\n", &last);
} }
close(fildes[0]); fclose(cache);
if (cache)
fclose(cache);
waitpid(-1, NULL, WNOHANG); waitpid(-1, NULL, WNOHANG);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
delta_t = (now.tv_sec - begin.tv_sec) * 1000000; delta_t = (now.tv_sec - begin.tv_sec) * 1000000;
delta_t += now.tv_usec - begin.tv_usec; delta_t += now.tv_usec - begin.tv_usec;
if (!found) { if (!found) {
printf("Failed to get current user environment variables " printf("ERROR: Failed to write all user environment "
"for %s\n", user_name); "variables for %s\n", user_name);
if (delta_t < (SU_WAIT_MSEC * 1000)) if (delta_t < (SU_WAIT_MSEC * 1000))
return (SU_WAIT_MSEC * 1000); return (SU_WAIT_MSEC * 1000);
} }
...@@ -349,7 +383,7 @@ static int _get_cache_dir(char *buffer, int buf_size) ...@@ -349,7 +383,7 @@ static int _get_cache_dir(char *buffer, int buf_size)
} }
close(fildes[0]); close(fildes[0]);
if (!buffer[0]) { if (!buffer[0]) {
printf("Failed to get StateSaveLocation\n"); printf("ERROR: Failed to get StateSaveLocation\n");
close(fildes[0]); close(fildes[0]);
return -1; return -1;
} }
......
...@@ -1300,15 +1300,14 @@ char **_load_env_cache(const char *username) ...@@ -1300,15 +1300,14 @@ char **_load_env_cache(const char *username)
*/ */
char **env_array_user_default(const char *username, int timeout, int mode) char **env_array_user_default(const char *username, int timeout, int mode)
{ {
FILE *su; char *line, *last, name[128], value[ENV_BUFSIZE];
char line[ENV_BUFSIZE]; char buffer[ENV_BUFSIZE];
char name[128];
char value[ENV_BUFSIZE];
char **env = NULL; char **env = NULL;
char *starttoken = "XXXXSLURMSTARTPARSINGHEREXXXX"; char *starttoken = "XXXXSLURMSTARTPARSINGHEREXXXX";
char *stoptoken = "XXXXSLURMSTOPPARSINGHEREXXXXX"; char *stoptoken = "XXXXSLURMSTOPPARSINGHEREXXXXX";
char cmdstr[256]; char cmdstr[256];
int fildes[2], found, fval, len, rc, timeleft; int fildes[2], found, fval, len, rc, timeleft;
int buf_read, buf_rem;
pid_t child; pid_t child;
struct timeval begin, now; struct timeval begin, now;
struct pollfd ufds; struct pollfd ufds;
...@@ -1335,7 +1334,8 @@ char **env_array_user_default(const char *username, int timeout, int mode) ...@@ -1335,7 +1334,8 @@ char **env_array_user_default(const char *username, int timeout, int mode)
close(2); close(2);
open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY);
snprintf(cmdstr, sizeof(cmdstr), snprintf(cmdstr, sizeof(cmdstr),
"/bin/echo; /bin/echo; /bin/echo; /bin/echo %s; /bin/env; /bin/echo %s", "/bin/echo; /bin/echo; /bin/echo; "
"/bin/echo %s; /bin/env; /bin/echo %s",
starttoken, stoptoken); starttoken, stoptoken);
if (mode == 1) if (mode == 1)
execl("/bin/su", "su", username, "-c", cmdstr, NULL); execl("/bin/su", "su", username, "-c", cmdstr, NULL);
...@@ -1354,25 +1354,24 @@ char **env_array_user_default(const char *username, int timeout, int mode) ...@@ -1354,25 +1354,24 @@ char **env_array_user_default(const char *username, int timeout, int mode)
close(fildes[1]); close(fildes[1]);
if ((fval = fcntl(fildes[0], F_GETFL, 0)) >= 0) if ((fval = fcntl(fildes[0], F_GETFL, 0)) >= 0)
fcntl(fildes[0], F_SETFL, fval | O_NONBLOCK); fcntl(fildes[0], F_SETFL, fval | O_NONBLOCK);
su= fdopen(fildes[0], "r");
gettimeofday(&begin, NULL); gettimeofday(&begin, NULL);
ufds.fd = fildes[0]; ufds.fd = fildes[0];
ufds.events = POLLIN; ufds.events = POLLIN;
/* First look for the start token in the output */ /* Read all of the output from /bin/su into buffer */
len = strlen(starttoken);
found = 0; found = 0;
while (!found) { buf_read = 0;
bzero(buffer, sizeof(buffer));
while (1) {
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if (timeout > 0) timeleft = SU_WAIT_MSEC;
timeleft = timeout * 1000;
else
timeleft = SU_WAIT_MSEC;
timeleft -= (now.tv_sec - begin.tv_sec) * 1000; timeleft -= (now.tv_sec - begin.tv_sec) * 1000;
timeleft -= (now.tv_usec - begin.tv_usec) / 1000; timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
if (timeleft <= 0) if (timeleft <= 0) {
verbose("timeout waiting for /bin/su to complete");
break; break;
}
if ((rc = poll(&ufds, 1, timeleft)) <= 0) { if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
if (rc == 0) { if (rc == 0) {
verbose("timeout waiting for /bin/su to complete"); verbose("timeout waiting for /bin/su to complete");
...@@ -1380,64 +1379,76 @@ char **env_array_user_default(const char *username, int timeout, int mode) ...@@ -1380,64 +1379,76 @@ char **env_array_user_default(const char *username, int timeout, int mode)
} }
if ((errno == EINTR) || (errno == EAGAIN)) if ((errno == EINTR) || (errno == EAGAIN))
continue; continue;
error("poll: %m"); error("poll(): %m");
break; break;
} }
if (!(ufds.revents & POLLIN)) if (!(ufds.revents & POLLIN)) {
break; if (ufds.revents & POLLHUP) { /* EOF */
while (fgets(line, sizeof(line), su)) { found = 1; /* success */
if (!strncmp(line, starttoken, len)) { } else if (ufds.revents & POLLERR) {
found = 1; error("POLLERR");
break; } else {
error("poll() revents=%d", ufds.revents);
} }
break;
}
buf_rem = sizeof(buffer) - buf_read;
if (buf_rem == 0) {
error("buffer overflow loading env vars");
break;
}
rc = read(fildes[0], &buffer[buf_read], buf_rem);
if (rc > 0)
buf_read += rc;
else if (rc == 0) { /* EOF */
found = 1; /* success */
break;
} else { /* error */
error("read(env pipe): %m");
break;
}
}
close(fildes[0]);
if (!found) {
error("Failed to load current user environment variables");
_load_env_cache(username);
}
/* First look for the start token in the output */
len = strlen(starttoken);
found = 0;
line = strtok_r(buffer, "\n", &last);
while (!found && line) {
if (!strncmp(line, starttoken, len)) {
found = 1;
break;
} }
line = strtok_r(NULL, "\n", &last);
} }
if (!found) { if (!found) {
error("Failed to get current user environment variables"); error("Failed to get current user environment variables");
close(fildes[0]);
return _load_env_cache(username); return _load_env_cache(username);
} }
/* Now read in the environment variable strings. */ /* Process environment variables until we find the stop token */
env = env_array_create();
len = strlen(stoptoken); len = strlen(stoptoken);
found = 0; found = 0;
while (!found) { env = env_array_create();
gettimeofday(&now, NULL); line = strtok_r(NULL, "\n", &last);
if (timeout > 0) while (!found && line) {
timeleft = timeout * 1000; if (!strncmp(line, stoptoken, len)) {
else
timeleft = SU_WAIT_MSEC;
timeleft -= (now.tv_sec - begin.tv_sec) * 1000;
timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
if (timeleft <= 0)
break;
if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
if (rc == 0) {
verbose("timeout waiting for /bin/su to complete");
break;
}
if ((errno == EINTR) || (errno == EAGAIN))
continue;
error("poll: %m");
break;
}
/* stop at the line containing the stoptoken string */
if (!(ufds.revents & POLLIN))
break;
if ((fgets(line, sizeof(line), su) == 0) ||
(!strncmp(line, stoptoken, len))) {
found = 1; found = 1;
break; break;
} }
if (_env_array_entry_splitter(line, name, sizeof(name),
_strip_cr_nl(line);
if (_env_array_entry_splitter(line, name, sizeof(name),
value, sizeof(value))) value, sizeof(value)))
env_array_overwrite(&env, name, value); env_array_overwrite(&env, name, value);
line = strtok_r(NULL, "\n", &last);
}
if (!found) {
error("Failed to get all user environment variables");
return _load_env_cache(username);
} }
close(fildes[0]);
return env; return env;
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment