/* $Id$ */
/*
* HPC-BASH - part of the DRMAA utilities library
* Poznan Supercomputing and Networking Center Copyright (C) 2010
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_CONFIG_H
# include
#endif
#define HPC_BASH_EXIT_OK (0)
#define HPC_BASH_EXIT_ERROR (5)
#define HPC_BASH_SCRIPT_NAME_TEMPLATE "/tmp/hpc-bash.XXXXXX"
typedef struct hpc_batch_job_s {
char *walltime;
char *native;
} hpc_batch_job_t;
static char *translate_hpc_bash_script(const char *orginal_script_name);
int main(int argc, char **argv)
{
char *tmp_script_file_name = NULL;
int child_pid = -1;
if (argc < 2) {
fprintf(stderr, "Missing script file\n");
exit(HPC_BASH_EXIT_ERROR);
}
if ((tmp_script_file_name = translate_hpc_bash_script(argv[1])) == NULL) {
exit(HPC_BASH_EXIT_ERROR);
}
if ((child_pid = fork()) > 0) {
int status = -1;
/* parent process*/
if (waitpid(child_pid, &status, 0) == -1) {
perror("waitpid() failed");
exit(HPC_BASH_EXIT_ERROR);
}
/* remove temporary script file */
/*unlink(tmp_script_file_name);*/
if (WIFEXITED(status)) {
exit(WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
exit(128 + WTERMSIG(status));
} else {
fprintf(stderr, "Ilegall wait status = %d\n", status);
exit(HPC_BASH_EXIT_ERROR);
}
} else if (child_pid == 0) {
/* child process */
/*shift arguments by one */
argv++;
argc--;
execv(tmp_script_file_name, argv);
perror("execv() failed");
exit(127);
} else {
perror("fork() failed");
}
return 1;
}
#define WRITE_STR2(str,length) \
do { \
if (write(out_fd, str, length) != length) { \
perror("write() failed"); \
goto out; \
} \
} while (0)
#define WRITE_STR(str) \
do { \
WRITE_STR2(str, strlen(str)); \
} while (0)
char *
translate_hpc_bash_script(const char *orginal_script_name)
{
char script_template[32] = HPC_BASH_SCRIPT_NAME_TEMPLATE;
char *tmp_script_file = NULL;
char line_buf[1024] = "";
int out_fd = -1;
int line_counter = 1;
bool in_for_loop = false;
bool in_batch_job = false;
bool after_done = false;
FILE *in_file = NULL;
hpc_batch_job_t batch_job;
memset(&batch_job, 0, sizeof(batch_job));
/** TODO use RAGEL !!! **/
if ((out_fd = mkstemp(script_template)) == -1) {
perror("mkstemp() failed");
goto out;
}
if ((fchmod(out_fd, S_IXUSR | S_IRUSR | S_IWUSR)) == -1 ) {
perror("fchmod() failed");
goto out;
}
if ((in_file = fopen(orginal_script_name, "r")) == NULL) {
perror("fopen() failed");
goto out;
}
while (fgets(line_buf, sizeof(line_buf), in_file) != NULL) {
int line_length = strlen(line_buf);
if (line_length > 0 && line_buf[line_length - 1] != '\n') {
fprintf(stderr, "line %d: line to long or no NEW line at the end of file", line_counter);
goto out;
}
if (line_counter == 1) {
if (strstr(line_buf, "hpc-bash"))
WRITE_STR("#!/bin/bash\n");
else {
fprintf(stderr,"WARNING: no hpc-bash shebang found!");
WRITE_STR2(line_buf, line_length);
}
} else if (strstr(line_buf, "#pragma hpc-bash parallel for")) {
in_for_loop = true;
} else if (strstr(line_buf, "#pragma hpc-bash batch-job")){
in_batch_job = true;
} else {
if (in_batch_job) {
WRITE_STR("\t" DRMAA_DIR_BIN "/drmaa-run ");
in_batch_job = false;
}
if (in_for_loop && strstr(line_buf,"done")) {
WRITE_STR("\t}&\n");
in_for_loop = false;
after_done = true;
}
WRITE_STR2(line_buf, line_length);
if (after_done) {
WRITE_STR("wait\n");
after_done = false;
}
if (in_for_loop && strstr(line_buf,"do")) {
WRITE_STR("\t{\n");
}
}
line_counter++;
}
tmp_script_file = strdup(script_template);
out:
if (out_fd != -1) {
close(out_fd);
out_fd = -1;
}
if (in_file) {
fclose(in_file);
in_file = NULL;
}
if (!tmp_script_file) /* on fault delete partially generated file */
unlink(script_template);
return tmp_script_file;
}