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