]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/execvms.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / tools / build / src / engine / execvms.c
1 /*
2 * Copyright 1993, 1995 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7 /* This file is ALSO:
8 * Copyright 2001-2004 David Abrahams.
9 * Copyright 2015 Artur Shepilko.
10 * Distributed under the Boost Software License, Version 1.0.
11 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
12 */
13
14
15 /*
16 * execvms.c - execute a shell script, ala VMS.
17 *
18 * The approach is this:
19 *
20 * If the command is a single line, and shorter than WRTLEN (what we believe to
21 * be the maximum line length), we just system() it.
22 *
23 * If the command is multi-line, or longer than WRTLEN, we write the command
24 * block to a temp file, splitting long lines (using "-" at the end of the line
25 * to indicate contiuation), and then source that temp file. We use special
26 * logic to make sure we do not continue in the middle of a quoted string.
27 *
28 * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
29 * 12/20/96 (seiwald) - rewritten to handle multi-line commands well
30 * 01/14/96 (seiwald) - do not put -'s between "'s
31 * 01/19/15 (shepilko)- adapt for jam-3.1.19
32 */
33
34 #include "jam.h"
35 #include "lists.h"
36 #include "execcmd.h"
37 #include "output.h"
38
39 #ifdef OS_VMS
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <ctype.h>
45 #include <times.h>
46 #include <unistd.h>
47 #include <errno.h>
48
49
50 #define WRTLEN 240
51
52 #define MIN( a, b ) ((a) < (b) ? (a) : (b))
53
54 #define CHAR_DQUOTE '"'
55
56 #define VMS_PATH_MAX 1024
57 #define VMS_COMMAND_MAX 1024
58
59 #define VMS_WARNING 0
60 #define VMS_SUCCESS 1
61 #define VMS_ERROR 2
62 #define VMS_FATAL 4
63
64 char commandbuf[ VMS_COMMAND_MAX ] = { 0 };
65
66
67 static int get_status(int vms_status);
68 static clock_t get_cpu_time();
69
70 /*
71 * exec_check() - preprocess and validate the command.
72 */
73
74 int exec_check
75 (
76 string const * command,
77 LIST * * pShell,
78 int * error_length,
79 int * error_max_length
80 )
81 {
82 int const is_raw_cmd = 1;
83
84 /* We allow empty commands for non-default shells since we do not really
85 * know what they are going to do with such commands.
86 */
87 if ( !command->size && ( is_raw_cmd || list_empty( *pShell ) ) )
88 return EXEC_CHECK_NOOP;
89
90 return is_raw_cmd
91 ? EXEC_CHECK_OK
92 : check_cmd_for_too_long_lines( command->value, MAXLINE, error_length,
93 error_max_length );
94 }
95
96
97 /*
98 * exec_cmd() - execute system command.
99 */
100
101 void exec_cmd
102 (
103 string const * command,
104 ExecCmdCallback func,
105 void * closure,
106 LIST * shell
107 )
108 {
109 char * s;
110 char * e;
111 char * p;
112 int vms_status;
113 int status;
114 int rstat = EXEC_CMD_OK;
115 int exit_reason = EXIT_OK;
116 timing_info time_info;
117 timestamp start_dt;
118 struct tms start_time;
119 struct tms end_time;
120 char * cmd_string = command->value;
121
122
123 /* Start the command */
124
125 timestamp_current( &time_info.start );
126 times( &start_time );
127
128 /* See if command is more than one line discounting leading/trailing white
129 * space.
130 */
131 for ( s = cmd_string; *s && isspace( *s ); ++s );
132
133 e = p = strchr( s, '\n' );
134
135 while ( p && isspace( *p ) )
136 ++p;
137
138 /* If multi line or long, write to com file. Otherwise, exec directly. */
139 if ( ( p && *p ) || ( e - s > WRTLEN ) )
140 {
141 FILE * f;
142
143 /* Create temp file invocation. */
144
145 if ( !*commandbuf )
146 {
147 OBJECT * tmp_filename = 0;
148
149 tmp_filename = path_tmpfile();
150
151
152 /* Get tmp file name is VMS-format. */
153 {
154 string os_filename[ 1 ];
155 string_new( os_filename );
156 path_translate_to_os( object_str( tmp_filename ), os_filename );
157 object_free( tmp_filename );
158 tmp_filename = object_new( os_filename->value );
159 string_free( os_filename );
160 }
161
162 commandbuf[0] = '@';
163 strncat( commandbuf + 1, object_str( tmp_filename ),
164 VMS_COMMAND_MAX - 2);
165 }
166
167
168 /* Open tempfile. */
169 if ( !( f = fopen( commandbuf + 1, "w" ) ) )
170 {
171 printf( "can't open cmd_string file\n" );
172 rstat = EXEC_CMD_FAIL;
173 exit_reason = EXIT_FAIL;
174
175 times( &end_time );
176
177 timestamp_current( &time_info.end );
178 time_info.system = (double)( end_time.tms_cstime -
179 start_time.tms_cstime ) / 100.;
180 time_info.user = (double)( end_time.tms_cutime -
181 start_time.tms_cutime ) / 100.;
182
183 (*func)( closure, rstat, &time_info, "" , "", exit_reason );
184 return;
185 }
186
187
188 /* Running from TMP, so explicitly set default to CWD. */
189 {
190 char * cwd = NULL;
191 int cwd_buf_size = VMS_PATH_MAX;
192
193 while ( !(cwd = getcwd( NULL, cwd_buf_size ) ) /* alloc internally */
194 && errno == ERANGE )
195 {
196 cwd_buf_size += VMS_PATH_MAX;
197 }
198
199 if ( !cwd )
200 {
201 perror( "can not get current working directory" );
202 exit( EXITBAD );
203 }
204
205 fprintf( f, "$ SET DEFAULT %s\n", cwd);
206
207 free( cwd );
208 }
209
210
211 /* For each line of the command. */
212 while ( *cmd_string )
213 {
214 char * s = strchr( cmd_string,'\n' );
215 int len = s ? s + 1 - cmd_string : strlen( cmd_string );
216
217 fputc( '$', f );
218
219 /* For each chunk of a line that needs to be split. */
220 while ( len > 0 )
221 {
222 char * q = cmd_string;
223 char * qe = cmd_string + MIN( len, WRTLEN );
224 char * qq = q;
225 int quote = 0;
226
227 /* Look for matching "s -- expected in the same line. */
228 for ( ; q < qe; ++q )
229 if ( ( *q == CHAR_DQUOTE ) && ( quote = !quote ) )
230 qq = q;
231
232 /* When needs splitting and is inside an open quote,
233 * back up to opening quote and split off at it.
234 * When the quoted string spans over a chunk,
235 * pass string as a whole.
236 * If no matching quote found, dump the rest of command.
237 */
238 if ( len > WRTLEN && quote )
239 {
240 q = qq;
241
242 if ( q == cmd_string )
243 {
244 for ( q = qe; q < ( cmd_string + len )
245 && *q != CHAR_DQUOTE ; ++q) {}
246 q = ( *q == CHAR_DQUOTE) ? ( q + 1 ) : ( cmd_string + len );
247 }
248 }
249
250 fwrite( cmd_string, ( q - cmd_string ), 1, f );
251
252 len -= ( q - cmd_string );
253 cmd_string = q;
254
255 if ( len )
256 {
257 fputc( '-', f );
258 fputc( '\n', f );
259 }
260 }
261 }
262
263 fclose( f );
264
265 if ( DEBUG_EXECCMD )
266 {
267 FILE * f;
268 char buf[ WRTLEN + 1 ] = { 0 };
269
270 if ( (f = fopen( commandbuf + 1, "r" ) ) )
271 {
272 int nbytes;
273 printf( "Command file: %s\n", commandbuf + 1 );
274
275 do
276 {
277 nbytes = fread( buf, sizeof( buf[0] ), sizeof( buf ) - 1, f );
278
279 if ( nbytes ) fwrite(buf, sizeof( buf[0] ), nbytes, stdout);
280 }
281 while ( !feof(f) );
282
283 fclose(f);
284 }
285 }
286
287 /* Execute command file */
288 vms_status = system( commandbuf );
289 status = get_status( vms_status );
290
291 unlink( commandbuf + 1 );
292 }
293 else
294 {
295 /* Execute single line command. Strip trailing newline before execing.
296 * TODO:Call via popen() with capture of the output may be better here.
297 */
298 if ( e ) *e = 0;
299
300 status = VMS_SUCCESS; /* success on empty command */
301 if ( *s )
302 {
303 vms_status = system( s );
304 status = get_status( vms_status );
305 }
306 }
307
308
309 times( &end_time );
310
311 timestamp_current( &time_info.end );
312 time_info.system = (double)( end_time.tms_cstime -
313 start_time.tms_cstime ) / 100.;
314 time_info.user = (double)( end_time.tms_cutime -
315 start_time.tms_cutime ) / 100.;
316
317
318 /* Fail for error or fatal error. OK on OK, warning or info exit. */
319 if ( ( status == VMS_ERROR ) || ( status == VMS_FATAL ) )
320 {
321 rstat = EXEC_CMD_FAIL;
322 exit_reason = EXIT_FAIL;
323 }
324
325 (*func)( closure, rstat, &time_info, "" , "", exit_reason );
326 }
327
328
329 void exec_wait()
330 {
331 return;
332 }
333
334
335 /* get_status() - returns status of the VMS command execution.
336 - Map VMS status to its severity (lower 3-bits)
337 - W-DCL-IVVERB is returned on unrecognized command -- map to general ERROR
338 */
339 int get_status( int vms_status )
340 {
341 #define VMS_STATUS_DCL_IVVERB 0x00038090
342
343 int status;
344
345 switch (vms_status)
346 {
347 case VMS_STATUS_DCL_IVVERB:
348 status = VMS_ERROR;
349 break;
350
351 default:
352 status = vms_status & 0x07; /* $SEVERITY bits */
353 }
354
355 return status;
356 }
357
358
359 #define __NEW_STARLET 1
360
361 #include <stdio.h>
362 #include <stdlib.h>
363 #include <time.h>
364 #include <ssdef.h>
365 #include <stsdef.h>
366 #include <jpidef.h>
367 #include <efndef.h>
368 #include <iosbdef.h>
369 #include <iledef.h>
370 #include <lib$routines.h>
371 #include <starlet.h>
372
373
374 /*
375 * get_cpu_time() - returns CPU time in CLOCKS_PER_SEC since process start.
376 * on error returns (clock_t)-1.
377 *
378 * Intended to emulate (system + user) result of *NIX times(), if CRTL times()
379 * is not available.
380 * However, this accounts only for the current process. To account for child
381 * processes, these need to be directly spawned/forked via exec().
382 * Moreover, child processes should be running a C main program or a program
383 * that calls VAXC$CRTL_INIT or DECC$CRTL_INIT.
384 */
385
386 clock_t get_cpu_time()
387 {
388 clock_t result = (clock_t) 0;
389
390 IOSB iosb;
391 int status;
392 long cputime = 0;
393
394
395 ILE3 jpi_items[] = {
396 { sizeof( cputime ), JPI$_CPUTIM, &cputime, NULL }, /* longword int, 10ms */
397 { 0 },
398 };
399
400 status = sys$getjpiw (EFN$C_ENF, 0, 0, jpi_items, &iosb, 0, 0);
401
402 if ( !$VMS_STATUS_SUCCESS( status ) )
403 {
404 lib$signal( status );
405
406 result = (clock_t) -1;
407 return result;
408 }
409
410
411 result = ( cputime / 100 ) * CLOCKS_PER_SEC;
412
413 return result;
414 }
415
416
417 # endif /* VMS */
418