Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libjcl/run.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2003-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
/*
23
* jcl program exec and script loop
24
*/
25
26
#include "jcllib.h"
27
28
#include <coshell.h>
29
#include <errno.h>
30
#include <ls.h>
31
#include <tm.h>
32
#include <tmx.h>
33
34
/*
35
* if name contains invalid export id chars then
36
* return a new name with those chars converted to '_<XX>_'
37
*/
38
39
static char*
40
fmtexport(const char* name)
41
{
42
register int c;
43
register const char* s;
44
register char* t;
45
register int n;
46
char* b;
47
48
s = name;
49
c = *s++;
50
if (isalpha(c) || c == '_')
51
do
52
{
53
if (!(c = *s++))
54
return (char*)name;
55
} while (isalnum(c) || c == '_');
56
n = 1;
57
while (c = *s++)
58
if (!isalnum(c) && c != '_')
59
n++;
60
t = b = fmtbuf(strlen(name) + 4 * n + 1);
61
for (s = name; c = *s++;)
62
if (!isalnum(c) && c != '_')
63
t += sfsprintf(t, 5, "_%02X_", c);
64
else
65
*t++ = c;
66
*t = 0;
67
return b;
68
}
69
70
/*
71
* output dd dsname with &path => /tmp file map
72
*/
73
74
static char*
75
dsn(Jcl_t* jcl, Jcldd_t* dd, const char* path, int mark)
76
{
77
char* s;
78
79
if (mark && dd->disp[0] == JCL_DISP_MOD && !(dd->flags & JCL_DD_DIR))
80
sfprintf(jcl->vp, "+");
81
if (*path == '&')
82
{
83
if (*++path == '&')
84
path++;
85
sfprintf(jcl->vp, jcl->tmp);
86
}
87
sfprintf(jcl->vp, "%s", fmtquote(path, "\"", "\"", strlen(path), FMT_SHELL|FMT_PARAM));
88
if (!(s = sfstruse(jcl->vp)))
89
nospace(jcl, NiL);
90
return s;
91
}
92
93
/*
94
* create dd dir if it doesn't exist
95
*/
96
97
static void
98
checkdir(Jcl_t* jcl, Jcldd_t* dd)
99
{
100
register char* s;
101
Jcldir_t* dir;
102
103
if (!dtmatch(jcl->outdir, dd->path))
104
{
105
if (dir = vmnewof(jcl->vm, NiL, Jcldir_t, 1, strlen(dd->path)))
106
{
107
strcpy(dir->name, dd->path);
108
dtinsert(jcl->outdir, dir);
109
}
110
s = dsn(jcl, dd, dd->path, 0);
111
sfprintf(jcl->tp, "[[ ! -d %s && ! -f %s ]] && mkdir -p %s\n", s, s, s);
112
}
113
}
114
115
/*
116
* execution loop
117
*/
118
119
int
120
jclrun(Jcl_t* scope)
121
{
122
register Jcl_t* jcl;
123
register Jclstep_t* step;
124
register Jcldd_t* dd;
125
register Jclcat_t* cat;
126
register Jclsym_t* sym;
127
register char* s;
128
char* arg;
129
char* t;
130
Coshell_t* co;
131
Cojob_t* cj;
132
Jcldd_t* xx;
133
Jcldd_t* std[4];
134
Dtlink_t k;
135
Jcl_t* top;
136
int code;
137
int del;
138
int n;
139
int i;
140
double pct;
141
double real;
142
double user;
143
double sys;
144
Time_t start;
145
unsigned long flags;
146
char subdir[64];
147
148
if (!(jcl = jclopen(scope, scope->step->command, scope->flags|scope->step->flags, scope->disc)))
149
return -1;
150
if (jcl->flags & JCL_EXEC)
151
{
152
if (!(co = coopen(pathshell(), (jcl->flags & (JCL_EXEC|JCL_TRACE)) == (JCL_EXEC|JCL_TRACE) ? CO_ANY : (CO_ANY|CO_SILENT), NiL)))
153
{
154
if (jcl->disc->errorf)
155
(*jcl->disc->errorf)(NiL, jcl->disc, 2, "%s: cannot connect to coshell", jcl->name);
156
jclclose(jcl);
157
return -1;
158
}
159
start = tmxgettime();
160
user = co->user;
161
sys = co->sys;
162
}
163
code = 0;
164
if (jcl->name && (!scope || !scope->scope || (scope->scope->flags & JCL_SCOPE)))
165
{
166
top = jcl;
167
if (!(jcl->flags & JCL_EXEC))
168
{
169
if (jcl->flags & JCL_VERBOSE)
170
sfprintf(sfstdout, ": JOB %s\nexport %sJOBNAME=%s\ncode=0\n", jcl->name, JCL_AUTO, jcl->name);
171
if (jcl->flags & JCL_TRACE)
172
sfprintf(sfstderr, "+ : JOB %s\n", jcl->name);
173
}
174
if (jcl->flags & JCL_SUBDIR)
175
{
176
if (jcl->flags & JCL_EXEC)
177
{
178
t = fmttime("%y-%m-%d", time(NiL));
179
n = 0;
180
for (;;)
181
{
182
sfsprintf(subdir, sizeof(subdir), "%s.%s.%d", jcl->name, t, ++n);
183
if (!mkdir(subdir, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH))
184
break;
185
if (errno != EEXIST)
186
{
187
if (jcl->disc->errorf)
188
(*jcl->disc->errorf)(NiL, jcl->disc, ERROR_SYSTEM|2, "%s: cannot create job subdirectory", subdir);
189
jclclose(jcl);
190
return -1;
191
}
192
}
193
if (chdir(subdir))
194
{
195
if (jcl->disc->errorf)
196
(*jcl->disc->errorf)(NiL, jcl->disc, ERROR_SYSTEM|2, "%s: cannot run in job subdirectory", subdir);
197
jclclose(jcl);
198
return -1;
199
}
200
sfsync(sfstdout);
201
sfsync(sfstderr);
202
for (i = 0; i < elementsof(redirect); i++)
203
if (jcl->redirect[i] > 0)
204
{
205
close(redirect[i].fd);
206
if ((n = open(redirect[i].file, O_CREAT|O_TRUNC|O_WRONLY|O_APPEND|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != redirect[i].fd)
207
{
208
close(n);
209
dup2(jcl->redirect[i], redirect[i].fd);
210
}
211
}
212
sfset(sfstdout, SF_LINE, 1);
213
sfset(sfstderr, SF_LINE, 1);
214
if (jcl->flags & JCL_TRACE)
215
sfprintf(sfstderr, "+ mkdir %s\n+ cd %s\n", subdir, subdir);
216
if (jcl->flags & JCL_VERBOSE)
217
sfprintf(sfstdout, "STARTED AT %s\n", fmttime("%K", time(NiL)));
218
}
219
else if (jcl->flags & JCL_VERBOSE)
220
{
221
sfprintf(sfstdout, "n=0\nt=$(date +%%y-%%m-%%d)\nwhile :\ndo d=%s.$t.$((++n))\n [[ -d $d ]] || break\ndone\nmkdir $d && cd $d || exit 1\n", jcl->name);
222
sfputr(sfstdout, "exec > SYSOUT 2> SYSERR\nTIMEFORMAT='USAGE CPU=%P%% REAL=%R USR=%U SYS=%S'\ntime {\ndate +'STARTED AT %K'", '\n');
223
}
224
}
225
}
226
else
227
for (top = scope; !top->name && !(top->flags & JCL_SCOPE) && top->scope; top = top->scope);
228
while (step = jclstep(jcl))
229
{
230
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
231
if (dd->flags & JCL_DD_ALIAS)
232
{
233
dd->flags &= ~JCL_DD_ALIAS;
234
xx = 0;
235
t = fmtbuf(n = strlen(step->name) + strlen(dd->path) + 2);
236
sfsprintf(t, n, "%s.%s", step->name, dd->path);
237
for (scope = jcl; scope; scope = scope->scope)
238
if ((xx = (Jcldd_t*)dtmatch(scope->step->dd, t)) ||
239
(xx = (Jcldd_t*)dtmatch(scope->step->dd, dd->path)))
240
break;
241
if (!xx)
242
{
243
if (jcl->disc->errorf)
244
(*jcl->disc->errorf)(NiL, jcl->disc, 2, "%s: DD not defined", dd->path);
245
code = -1;
246
goto bad;
247
}
248
k = dd->link;
249
s = dd->name;
250
*dd = *xx;
251
dd->link = k;
252
dd->name = s;
253
}
254
if (!jcl->tmp)
255
{
256
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
257
{
258
if (dd->path && *dd->path == '&')
259
break;
260
for (cat = dd->cat; cat; cat = cat->next)
261
if (cat->path && *cat->path == '&')
262
break;
263
}
264
if (dd)
265
{
266
if (jcl->flags & JCL_EXEC)
267
{
268
if (!(s = getenv("TMPDIR")))
269
s = "/tmp";
270
sfprintf(jcl->vp, "%s/job.%s.%lu.", s, jcl->name, (unsigned long)getpid());
271
}
272
else
273
sfprintf(jcl->vp, "${TMPDIR:-/tmp}/job.%s.$$.", jcl->name);
274
if (!(s = sfstruse(jcl->vp)))
275
nospace(jcl, NiL);
276
jcl->tmp = stash(jcl, jcl->vm, s, 0);
277
if ((jcl->flags & (JCL_VERBOSE|JCL_EXEC)) == JCL_VERBOSE)
278
sfprintf(sfstdout, "trap 'code=$?; rm -rf %s*; exit $code' 0 1 2\n", jcl->tmp);
279
}
280
}
281
jcl->steps++;
282
if (jcl->flags & (JCL_LISTEXEC|JCL_LISTINPUTS|JCL_LISTOUTPUTS|JCL_LISTPROGRAMS|JCL_LISTSCRIPTS))
283
{
284
if (jcl->flags & JCL_LISTEXEC)
285
uniq(jcl->name, step->command, 0, jcl->disc);
286
else if (jcl->flags & (JCL_LISTINPUTS|JCL_LISTOUTPUTS))
287
{
288
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
289
{
290
flags = dd->disp[0] == JCL_DISP_NEW ? JCL_LISTOUTPUTS : JCL_LISTINPUTS;
291
if (dd->path && *dd->path != '&')
292
uniq(dd->path, NiL, flags, jcl->disc);
293
for (cat = dd->cat; cat; cat = cat->next)
294
if (*cat->path != '&')
295
uniq(cat->path, NiL, flags, jcl->disc);
296
}
297
}
298
else if (jcl->flags & JCL_LISTPROGRAMS)
299
{
300
if (step->flags & JCL_PGM)
301
uniq(step->command, NiL, 0, jcl->disc);
302
}
303
else if (jcl->flags & JCL_LISTSCRIPTS)
304
{
305
if (!(step->flags & JCL_PGM) && (s = jclfind(jcl, step->command, 0, 0, NiL)))
306
uniq(s, NiL, 0, jcl->disc);
307
}
308
}
309
if (!jcleval(jcl, jcl->cond, code))
310
break;
311
if (jcleval(jcl, step->cond, code))
312
{
313
if (step->flags & JCL_PGM)
314
{
315
std[0] = std[1] = std[2] = std[3] = 0;
316
sfprintf(jcl->tp, ": %s\n", step->name);
317
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
318
switch (dd->flags & (JCL_DD_DIR|JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE))
319
{
320
case JCL_DD_DIR:
321
if (dd->disp[0] == JCL_DISP_NEW || dd->disp[0] == JCL_DISP_MOD)
322
checkdir(jcl, dd);
323
break;
324
case JCL_DD_SYSIN:
325
if (dd->path)
326
std[0] = dd;
327
if (dd->here)
328
std[3] = dd;
329
break;
330
case JCL_DD_SYSOUT:
331
std[1] = dd;
332
break;
333
case JCL_DD_SYSERR:
334
std[2] = dd;
335
break;
336
default:
337
if (!(dd->flags & JCL_DD_DUMMY) && (jcl->flags & (JCL_EXEC|JCL_VERBOSE)) && dd->path && *dd->path != '&' && dd->disp[0] == JCL_DISP_NEW && (*dd->path != '$' || *(dd->path + 1) != '(') && (s = strrchr(dd->path, '/')))
338
{
339
*s = 0;
340
checkdir(jcl, dd);
341
*s = '/';
342
}
343
break;
344
}
345
for (dd = (Jcldd_t*)dtfirst(jcl->dd); dd; dd = (Jcldd_t*)dtnext(jcl->dd, dd))
346
if ((dd->flags & (JCL_DD_MARKED|JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)) == JCL_DD_MARKED && (dd->disp[0] == JCL_DISP_NEW || dd->disp[0] == JCL_DISP_MOD))
347
{
348
s = dsn(jcl, dd, dd->path, 0);
349
sfprintf(jcl->tp, "[[ -e %s ]] || > %s\n", s, s);
350
}
351
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
352
if ((dd->flags & (JCL_DD_MARKED|JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)) == JCL_DD_MARKED && (dd->disp[0] == JCL_DISP_NEW || dd->disp[0] == JCL_DISP_MOD))
353
{
354
s = dsn(jcl, dd, dd->path, 0);
355
sfprintf(jcl->tp, "[[ -e %s ]] || > %s\n", s, s);
356
}
357
if ((dd = std[0]) && dd->cat)
358
{
359
std[0] = std[3] = 0;
360
sfprintf(jcl->tp, "cat %s", dsn(jcl, dd, dd->path, 0));
361
for (cat = dd->cat; cat; cat = cat->next)
362
sfprintf(jcl->tp, " \\\n\t%s", dsn(jcl, dd, cat->path, 0));
363
sfprintf(jcl->tp, " |\n");
364
}
365
if (jcl->flags & JCL_EXEC)
366
sfprintf(jcl->tp, "%sJOBNAME=%s ", JCL_AUTO, top->name);
367
sfprintf(jcl->tp, "%s=%s", fmtexport("STEP"), step->name);
368
s = " \\\n";
369
for (dd = (Jcldd_t*)dtfirst(jcl->dd); dd; dd = (Jcldd_t*)dtnext(jcl->dd, dd))
370
if (!(dd->flags & JCL_DD_REFERENCE))
371
{
372
sfprintf(jcl->tp, "%s%s=%s", s, fmtexport(dd->name), dsn(jcl, dd, dd->path, 1));
373
for (cat = dd->cat; cat; cat = cat->next)
374
sfprintf(jcl->tp, "'\n\t'%s", dsn(jcl, dd, cat->path, 1));
375
}
376
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
377
if (dd->path && !(dd->flags & (JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)))
378
{
379
sfprintf(jcl->tp, "%s%s=%s", s, fmtexport(dd->name), dsn(jcl, dd, dd->path, 1));
380
for (cat = dd->cat; cat; cat = cat->next)
381
sfprintf(jcl->tp, "'\n\t'%s", dsn(jcl, dd, cat->path, 1));
382
s = " \\\n";
383
}
384
del = 0;
385
sfprintf(jcl->tp, "%sDDIN='", s);
386
s = "";
387
for (dd = (Jcldd_t*)dtfirst(jcl->dd); dd; dd = (Jcldd_t*)dtnext(jcl->dd, dd))
388
if (!(dd->flags & (JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)) && dd->disp[0] != JCL_DISP_NEW && dd->disp[0] != JCL_DISP_MOD)
389
{
390
sfprintf(jcl->tp, "%s%s", s, fmtexport(dd->name));
391
s = " ";
392
}
393
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
394
if (!(dd->flags & (JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)) && dd->disp[0] != JCL_DISP_NEW && dd->disp[0] != JCL_DISP_MOD)
395
{
396
sfprintf(jcl->tp, "%s%s", s, fmtexport(dd->name));
397
s = " ";
398
}
399
sfprintf(jcl->tp, "' \\\nDDOUT='");
400
s = "";
401
for (dd = (Jcldd_t*)dtfirst(jcl->dd); dd; dd = (Jcldd_t*)dtnext(jcl->dd, dd))
402
if (!(dd->flags & (JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)) && (dd->disp[0] == JCL_DISP_NEW || dd->disp[0] == JCL_DISP_MOD))
403
{
404
sfprintf(jcl->tp, "%s%s", s, fmtexport(dd->name));
405
s = " ";
406
}
407
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
408
{
409
if (!(dd->flags & (JCL_DD_SYSIN|JCL_DD_SYSOUT|JCL_DD_SYSERR|JCL_DD_REFERENCE)) && (dd->disp[0] == JCL_DISP_NEW || dd->disp[0] == JCL_DISP_MOD))
410
{
411
sfprintf(jcl->tp, "%s%s", s, fmtexport(dd->name));
412
s = " ";
413
}
414
if (dd->disp[1] == JCL_DISP_DELETE)
415
del |= 1;
416
if (dd->disp[2] == JCL_DISP_DELETE)
417
del |= 2;
418
}
419
sfprintf(jcl->tp, "' \\\n%s", step->command);
420
if (s = step->parm)
421
{
422
if (*s == '(')
423
{
424
arg = strcpy(fmtbuf(strlen(s) + 1), s);
425
while (s = jclparm(&arg))
426
sfprintf(jcl->vp, ",%s", s);
427
if (!(s = sfstruse(jcl->vp)))
428
nospace(jcl, NiL);
429
if (*s == ',')
430
s++;
431
for (t = s + strlen(s); t > s && *--t == ' ';);
432
if (*t == ')')
433
*++t = 0;
434
else if (*t == ',')
435
*t = 0;
436
}
437
sfprintf(jcl->tp, " %s", fmtquote(s, "$'", "'", strlen(s), FMT_SHELL));
438
}
439
for (sym = (Jclsym_t*)dtfirst(step->syms); sym; sym = (Jclsym_t*)dtnext(step->syms, sym))
440
sfprintf(jcl->tp, " %s=%s", fmtquote(sym->name, "'", "'", strlen(sym->name), FMT_SHELL), fmtquote(sym->value, "$'", "'", strlen(sym->value), 0));
441
if (dd = std[0])
442
{
443
sfprintf(jcl->tp, " < %s", dsn(jcl, dd, dd->path, 0));
444
std[3] = 0;
445
}
446
if (dd = std[1])
447
sfprintf(jcl->tp, " > %s", dsn(jcl, dd, dd->path, 0));
448
if (dd = std[2])
449
sfprintf(jcl->tp, " 2> %s", dsn(jcl, dd, dd->path, 0));
450
if (dd = std[3])
451
sfprintf(jcl->tp, " <<%s\n%s%s", fmtquote(dd->dlm, "'", "'", strlen(dd->dlm), 1), dd->here, dd->dlm);
452
sfprintf(jcl->tp, "\ncode=$?\n");
453
if (del)
454
{
455
if (del & 1)
456
{
457
sfprintf(jcl->tp, "if (( ! $code ))\nthen\n\trm -rf");
458
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
459
if (dd->disp[1] == JCL_DISP_DELETE)
460
sfprintf(jcl->tp, " %s", dsn(jcl, dd, dd->path, 0));
461
}
462
if (del & 2)
463
{
464
if (del & 1)
465
sfprintf(jcl->tp, "\nelse\n");
466
else
467
sfprintf(jcl->tp, "\nif (( $code ))\nthen\n");
468
sfprintf(jcl->tp, "\trm -rf");
469
for (dd = (Jcldd_t*)dtfirst(step->dd); dd; dd = (Jcldd_t*)dtnext(step->dd, dd))
470
if (dd->disp[2] == JCL_DISP_DELETE)
471
sfprintf(jcl->tp, " %s", dsn(jcl, dd, dd->path, 0));
472
}
473
sfprintf(jcl->tp, "\nfi\n");
474
}
475
if (jcl->flags & JCL_EXEC)
476
sfprintf(jcl->tp, "exit $code\n");
477
if (!(s = sfstruse(jcl->tp)))
478
nospace(jcl, NiL);
479
}
480
else if ((jcl->flags & (JCL_VERBOSE|JCL_EXEC)) == JCL_VERBOSE)
481
sfprintf(sfstdout, ": %s PROC %s\n", step->name, step->command);
482
else if ((jcl->flags & (JCL_TRACE|JCL_EXEC)) == (JCL_TRACE|JCL_EXEC))
483
sfprintf(sfstderr, "+ : %s PROC %s\n", step->name, step->command);
484
if (step->flags & JCL_PGM)
485
{
486
if ((jcl->flags & (JCL_VERBOSE|JCL_EXEC)) == JCL_VERBOSE)
487
sfputr(sfstdout, s, -1);
488
if (sfsync(sfstdout))
489
{
490
if (jcl->disc->errorf)
491
(*jcl->disc->errorf)(NiL, jcl->disc, 2, "write error");
492
code = -1;
493
break;
494
}
495
if (!(jcl->flags & JCL_EXEC))
496
code = 0;
497
else if (!(cj = coexec(co, s, CO_APPEND, redirect[0].file, redirect[1].file, NiL)) || !(cj = cowait(co, cj, -1)))
498
code = 127;
499
else
500
code = cj->status;
501
}
502
else if (jcl->flags & JCL_RECURSE)
503
code = jclrun(jcl);
504
else
505
code = 0;
506
if (code)
507
jcl->failed++;
508
else
509
jcl->passed++;
510
if (jclrc(jcl, step, code) < 0)
511
break;
512
}
513
}
514
bad:
515
if (jcl->tmp && (jcl->flags & JCL_EXEC))
516
{
517
sfprintf(jcl->tp, "rm -rf %s*\n", jcl->tmp);
518
if (!(s = sfstruse(jcl->tp)))
519
nospace(jcl, NiL);
520
if (cj = coexec(co, s, CO_APPEND, redirect[0].file, redirect[1].file, NiL))
521
cowait(co, cj, -1);
522
}
523
if (jcl == top)
524
{
525
if (jcl->flags & JCL_GDG)
526
{
527
s = "gdgupdate";
528
if (!(jcl->flags & JCL_EXEC))
529
sfputr(sfstdout, s, '\n');
530
else if (cj = coexec(co, s, CO_APPEND, redirect[0].file, redirect[1].file, NiL))
531
cowait(co, cj, -1);
532
}
533
if ((jcl->flags & (JCL_SUBDIR|JCL_VERBOSE)) == (JCL_SUBDIR|JCL_VERBOSE))
534
{
535
if (jcl->flags & JCL_EXEC)
536
sfprintf(sfstdout, "COMPLETED AT %s\n", fmttime("%K", time(NiL)));
537
else
538
sfputr(sfstdout, "date +'COMPLETED AT %K'\n}", '\n');
539
}
540
if ((jcl->flags & (JCL_EXEC|JCL_SUBDIR)) == (JCL_EXEC|JCL_SUBDIR) && chdir("..") && jcl->disc->errorf)
541
(*jcl->disc->errorf)(NiL, jcl->disc, ERROR_SYSTEM|2, "%s: cannot chdir to job subdirectory parent", subdir);
542
if ((jcl->flags & (JCL_EXEC|JCL_VERBOSE)) == (JCL_EXEC|JCL_VERBOSE))
543
{
544
start = tmxgettime() - start;
545
user = (co->user - user) / CO_QUANT;
546
sys = (co->sys - sys) / CO_QUANT;
547
if (pct = (real = (double)start / 1e9))
548
pct = 100.0 * ((user + sys) / pct);
549
sfprintf(sfstdout, "USAGE CPU=%.2f%% REAL=%.2f USR=%.2f SYS=%.2f\n", pct, real, user, sys);
550
}
551
}
552
code = jclclose(jcl);
553
if (scope)
554
jclrc(scope, NiL, code);
555
return code;
556
}
557
558