1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
10
* Sun Industry Standards Source License Version 1.2
11
* =================================================
12
* The contents of this file are subject to the Sun Industry Standards
13
* Source License Version 1.2 (the "License"); You may not use this file
14
* except in compliance with the License. You may obtain a copy of the
15
* License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
17
* Software provided under this License is provided on an "AS IS" basis,
18
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
19
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
20
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
21
* See the License for the specific provisions governing your rights and
22
* obligations concerning the Software.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2001 by Sun Microsystems, Inc.
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
37
#include <sys/types.h>
42
#include "lck/sge_mtutil.h"
44
#include "rmon/sgermon.h"
46
#include "uti/setup_path.h"
47
#include "uti/sge_log.h"
48
#include "uti/sge_uidgid.h"
49
#include "uti/sge_prog.h"
50
#include "uti/sge_stdio.h"
51
#include "uti/sge_string.h"
53
#include "sgeobj/sge_answer.h"
54
#include "sgeobj/config.h"
55
#include "sgeobj/sge_conf.h"
57
#include "gdi/sge_gdi.h"
58
#include "gdi/sge_gdi_ctx.h"
60
#include "sge_qtcsh.h"
62
#include "msg_common.h"
65
/* module global variables */
66
static pthread_mutex_t qtask_mutex = PTHREAD_MUTEX_INITIALIZER;
67
static lList *task_config = NULL;
68
static int mode_verbose = 0;
69
static int mode_remote = 1;
70
static int force_remote = 0;
71
static int mode_immediate = 1;
73
static int init_qtask_config(sge_gdi_ctx_class_t *ctx, lList **alpp, print_func_t ostream);
75
/****** sge_qtcsh/init_qtask_config() ******************************************
77
* init_qtask_config() -- ???
80
* static int init_qtask_config(lList **alpp, print_func_t ostream)
86
* sge_gdi_ctx_class_t *ctx - ???
88
* print_func_t ostream - ???
91
* static int - 0 - success
98
* MT-NOTES: init_qtask_config() is not MT safe as it uses global variables
105
*******************************************************************************/
106
static int init_qtask_config(
107
sge_gdi_ctx_class_t *ctx,
112
char fname[SGE_PATH_MAX + 1];
115
lList *clp_cluster = NULL, *clp_user = NULL;
116
lListElem *nxt, *cep_dest, *cep, *next;
117
const char *task_name;
118
struct passwd pw_struct;
119
const char* user_name = ctx->get_username(ctx);
120
const char* cell_root = ctx->get_cell_root(ctx);
122
/* cell global settings */
123
sprintf(fname, "%s/common/qtask", cell_root);
125
if (!(fp = fopen(fname, "r")) && errno != ENOENT) {
126
SGE_ADD_MSG_ID(sprintf(SGE_EVENT, MSG_SGETEXT_CANT_OPEN_SS, fname, strerror(errno)));
127
answer_list_add(alpp, SGE_EVENT, STATUS_EDISK, ANSWER_QUALITY_ERROR);
128
(*ostream)("%s", SGE_EVENT);
132
/* read in config file */
133
if (read_config_list(fp, &clp_cluster, alpp, CF_Type, CF_name, CF_value,
134
CF_sublist, NULL, RCL_NO_VALUE, buffer, sizeof(buffer)-1)) {
141
/* skip tasknames containing '/' */
142
nxt = lFirst(clp_cluster);
145
if (strrchr(lGetString(cep, CF_name), '/'))
146
lRemoveElem(clp_cluster, &cep);
150
pwd = sge_getpwnam_r(user_name, &pw_struct, buffer, sizeof(buffer));
154
SGE_ADD_MSG_ID(sprintf(SGE_EVENT, MSG_USER_INVALIDNAMEX_S , user_name));
155
answer_list_add(alpp, SGE_EVENT, STATUS_ENOSUCHUSER, ANSWER_QUALITY_ERROR);
156
(*ostream)("%s", SGE_EVENT);
160
SGE_ADD_MSG_ID(sprintf(SGE_EVENT, MSG_USER_NOHOMEDIRFORUSERX_S , user_name));
161
answer_list_add(alpp, SGE_EVENT, STATUS_EDISK, ANSWER_QUALITY_ERROR);
162
(*ostream)("%s", SGE_EVENT);
165
sprintf(fname, "%s/.qtask", pwd->pw_dir);
167
if (!(fp = fopen(fname, "r")) && errno != ENOENT) {
168
SGE_ADD_MSG_ID(sprintf(SGE_EVENT, MSG_SGETEXT_CANT_OPEN_SS, fname, strerror(errno)));
169
answer_list_add(alpp, SGE_EVENT, STATUS_EDISK, ANSWER_QUALITY_ERROR);
170
(*ostream)("%s", SGE_EVENT);
174
/* read in config file */
175
if (read_config_list(fp, &clp_user, alpp, CF_Type, CF_name, CF_value,
176
CF_sublist, NULL, RCL_NO_VALUE, buffer, sizeof(buffer)-1)) {
183
/* skip tasknames containing '/' */
184
nxt = lFirst(clp_user);
187
if (strrchr(lGetString(cep, CF_name), '/'))
188
lRemoveElem(clp_user, &cep);
193
for_each (cep, clp_user) {
194
(*ostream) ("info: user: command %s request %s\n", lGetString(cep, CF_name), (s=lGetString(cep, CF_value))?s:"");
197
(*ostream) ("info: empty user task list\n");
200
/* merge contents of user list into cluster list */
201
next = lFirst(clp_user);
205
task_name = lGetString(cep, CF_name);
207
/* build task name with leading '!' for search operation */
208
ro_task_name = (char *)malloc(strlen(task_name) + 2);
209
ro_task_name[0] = '!';
210
strcpy(&ro_task_name[1], task_name);
212
if ((cep_dest=lGetElemStr(clp_cluster, CF_name, ro_task_name))) {
213
/* do not override cluster global task entry */
214
lRemoveElem(clp_user, &cep);
215
} else if ((cep_dest=lGetElemStr(clp_cluster, CF_name, task_name))) {
216
/* override cluster global task entry */
217
lSetString(cep_dest, CF_value, lGetString(cep, CF_value));
218
lRemoveElem(clp_user, &cep);
220
/* no entry in cluster global task list
221
use entry from user task list */
222
lDechainElem(clp_user, cep);
224
clp_cluster = lCreateList("cluster config", CF_Type);
225
lAppendElem(clp_cluster, cep);
230
lFreeList(&clp_user);
233
lFreeList(&task_config);
234
task_config = clp_cluster;
236
/* remove leading '!' from command names */
237
for_each (cep, clp_cluster) {
238
task_name = lGetString(cep, CF_name);
239
if (task_name[0] == '!') {
240
char *t = (char *)malloc(strlen(task_name));
241
strcpy(t, &task_name[1]);
242
lSetString(cep, CF_name, t);
250
for_each (cep, task_config) {
251
(*ostream) ("info: session: command %s request %s\n", lGetString(cep, CF_name), (s=lGetString(cep, CF_value))?s:"");
254
(*ostream) ("info: empty task list\n");
261
lFreeList(&clp_cluster);
262
lFreeList(&clp_user);
267
char *path, /* this is how tcsh tries to start the command */
269
char *expath, /* this is how user typed in the command */
270
int close_stdin /* use of qrsh's -nostdin option */
273
char *taskname = NULL;
274
lListElem *task = NULL;
278
int newargv_size = 0;
279
char **argv_iter = NULL;
280
char **newargv = NULL;
281
/* TODO: This should be SGE_PATH_MAX. */
282
char qrsh_path[2048];
284
/* remote execution only for commands without any path information */
285
if (!strchr(expath, '/')) {
290
fprintf(stderr, "sge_execv(path = %s, taskname = %s, expath = %s, close_stdin = %d)\n",
291
path, taskname?taskname:"<no remote execution>", expath, close_stdin);
296
!(task=lGetElemStr(task_config, CF_name, taskname))) {
298
fprintf(stderr, "local execution of "SFQ"\n", expath);
299
return execv(path, argv);
302
if ((value = lGetString(task, CF_value))) {
303
narg_resreq = sge_quick_count_num_args (value);
306
for (argv_iter=argv; argv_iter[0] != NULL; argv_iter++) {
312
(close_stdin?1:0) + /* -nostdin */
313
(mode_verbose?1:0) + /* -verbose */
315
narg_resreq + /* resource requests to qrsh */
316
narg_argv + /* argv of command to be started */
318
newargv = (char **)malloc(sizeof(char *) * newargv_size);
319
memset(newargv, 0, newargv_size);
321
/* build argv for qrsh */
323
newargv[i++] = strdup("qrsh");
326
newargv[i++] = strdup("-nostdin");
329
newargv[i++] = strdup("-verbose");
331
if (mode_immediate) {
332
newargv[i++] = strdup("-now");
333
newargv[i++] = strdup("y");
335
newargv[i++] = strdup("-now");
336
newargv[i++] = strdup("n");
339
/* add optional qrsh arguments from qtask file */
341
sge_parse_args (value, &newargv[i]);
345
/* add command's arguments */
346
for (argv_iter=argv; argv_iter[0] != NULL; argv_iter++) {
347
newargv[i++] = argv_iter[0];
352
sprintf(qrsh_path, "%s/bin/%s/qrsh", sge_get_root_dir(1, NULL, 0, 1), sge_get_arch());
354
return execvp(qrsh_path, newargv);
357
/* This method counts the number of arguments in the string using a quick and
358
* dirty algorithm. The algorithm may incorrectly report the number of arguments
359
* to be too large because it does not parse quotations correctly.
360
* MT-NOTE: sge_quick_count_num_args() is MT safe
362
int sge_quick_count_num_args (
363
const char* args /* The argument string to count by whitespace tokens */
366
char *resreq = (char *)malloc (strlen (args)+1);
368
struct saved_vars_s *context = NULL;
370
DENTER (TOP_LAYER, "count_num_qtask_args");
372
/* This function may return a larger number than required since it does not
373
* parse quotes. This is ok, however, since it's current usage is for
374
* mallocing arrays, and a little too big is fine. */
375
strcpy(resreq, args);
376
for (s=sge_strtok_r(resreq, " \t", &context); s; s=sge_strtok_r(NULL, " \t", &context))
379
sge_free_saved_vars(context);
385
/* This method should probably be moved out of this file into somewhere more
386
* common so that other routines can use it. */
387
void sge_parse_args (
388
const char* args, /* The argument string to parse by whitespace and quotes */
389
char** pargs /* The array to contain the parsed arguments */
396
int finished, count = 0;
398
DENTER (TOP_LAYER, "sge_parse_args");
400
resreq = malloc (strlen (args) + 1);
407
if(*s == '"' || *s == '\'') { /* copy quoted arguments */
408
quote = *s++; /* without quotes */
409
while(*s && *s != quote)
415
if(*s == 0) finished = 1; /* line end ? */
417
if(finished || isspace(*s)) { /* found delimiter or line end */
418
*d++ = 0; /* terminate token */
419
pargs[count++] = strdup(start); /* assign argument */
421
while(isspace(*(++s))); /* skip any number whitespace */
423
start = d; /* assign start of next token */
425
*d++ = *s++; /* copy one character */
433
/****** QTCSH/sge_get_qtask_args() *********************************************
435
* sge_get_qtask_args() -- get args for a qtask entry
438
* char** sge_get_qtask_args(void *ctx, char *taskname, lList **answer_list)
441
* This function reads the qtask files and returns an array of args for the
442
* given qtask entry. Calling this function will initialize the qtask
443
* framework, if it has not already been initialized.
446
* void *ctx - the communication context (sge_gdi_ctx_class_t *)
447
* char *taskname - The name of the entry for which to look in the qtask
449
* lList **answer_list - For returning error information
452
* char ** A NULL-terminated array of args for the given qtask
456
* MT-NOTE: sge_get_qtask_args() is MT safe with respect to itself, but it is
457
* not thread safe to use this function in conjuction with the
458
* init_qtask_config() or sge_init() functions or accessing the
459
* task_config global variable.
461
*******************************************************************************/
462
char **sge_get_qtask_args(void *context, char *taskname, lList **answer_list)
464
const char *value = NULL;
466
lListElem *task = NULL;
468
sge_gdi_ctx_class_t *ctx = (sge_gdi_ctx_class_t *)context;
470
DENTER (TOP_LAYER, "sge_get_qtask_args");
473
fprintf(stderr, "sge_get_qtask_args(taskname = %s)\n", taskname);
476
/* If the task_config has not been filled yet, fill it. We call
477
* init_qtask_config() instead of sge_init() because we don't need to setup
478
* the GDI. We just need the qtask arguments. */
479
/* We lock this part because multi-threaded DRMAA apps can have problems
480
* here. Once we're past this part, qtask_config's read-only, so we don't
481
* have any more problems. */
482
sge_mutex_lock("qtask_mutex", SGE_FUNC, __LINE__, &qtask_mutex);
484
if (task_config == NULL) {
485
/* Just using printf here since we don't really have an exciting function
486
* like xprintf to pass in. This was really meant for use with qtsch. */
487
if (init_qtask_config(ctx, answer_list, (print_func_t)printf) != 0) {
488
sge_mutex_unlock("qtask_mutex", SGE_FUNC, __LINE__, &qtask_mutex);
494
sge_mutex_unlock("qtask_mutex", SGE_FUNC, __LINE__, &qtask_mutex);
496
task = lGetElemStr(task_config, CF_name, taskname);
503
value = lGetString(task, CF_value);
506
num_args = sge_quick_count_num_args(value);
509
args = (char **)malloc(sizeof(char *) * (num_args + 1));
510
memset(args, 0, sizeof(char *) * (num_args + 1));
511
sge_parse_args (value, args);
521
sge_gdi_ctx_class_t *ctx = NULL;
524
* sge_gdi_param(SET_EXIT_ON_ERROR, 0, NULL);
526
if (sge_gdi2_setup(&ctx, QTCSH, MAIN_THREAD, NULL) == AE_OK) {
527
if (init_qtask_config(ctx, &alp, ostream) != 0 ) {
530
/* Remote execution is default.
532
Turn off remote execution only in case we were
533
started in the context of an already running job.
534
This is done to prevent recursive
536
qrsh -> qtcsh -> qrsh -> qtcsh -> ...
538
submission via SGE/SGE in case qtcsh
539
is the login shell at the execution server.
541
if ( mode_remote != 0 ) {
542
mode_remote = force_remote?mode_remote:!getenv("JOB_ID");
544
/* (*ostream) ("mode_remote = %d\n", mode_remote); */
549
/* (*ostream) ("no $SGE_ROOT, running as normal tcsh\n"); */
560
case CATCH_EXEC_MODE_REMOTE:
563
case CATCH_EXEC_MODE_VERBOSE:
564
mode_verbose = value;
566
case CATCH_EXEC_MODE_IMMEDIATE:
567
mode_immediate = value;
569
case CATCH_EXEC_MODE_FORCE_REMOTE:
570
force_remote = value;
584
case CATCH_EXEC_MODE_REMOTE:
587
case CATCH_EXEC_MODE_VERBOSE:
588
value = mode_verbose;
590
case CATCH_EXEC_MODE_IMMEDIATE:
591
value = mode_immediate;