]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/execvms.cpp
2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
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)
16 * execvms.c - execute a shell script, ala VMS.
18 * The approach is this:
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.
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.
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
53 #define MIN( a, b ) ((a) < (b) ? (a) : (b))
55 #define CHAR_DQUOTE '"'
57 #define VMS_PATH_MAX 1024
58 #define VMS_COMMAND_MAX 1024
65 char commandbuf
[ VMS_COMMAND_MAX
] = { 0 };
68 static int get_status(int vms_status
);
69 static clock_t get_cpu_time();
72 * exec_check() - preprocess and validate the command.
77 string
const * command
,
79 int32_t * error_length
,
80 int32_t * error_max_length
83 int const is_raw_cmd
= 1;
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.
88 if ( !command
->size
&& ( is_raw_cmd
|| list_empty( *pShell
) ) )
89 return EXEC_CHECK_NOOP
;
93 : check_cmd_for_too_long_lines( command
->value
, shell_maxline(), error_length
,
99 * exec_cmd() - execute system command.
104 string
const * command
,
106 ExecCmdCallback func
,
116 int rstat
= EXEC_CMD_OK
;
117 int exit_reason
= EXIT_OK
;
118 timing_info time_info
;
120 struct tms start_time
;
122 char * cmd_string
= command
->value
;
125 /* Start the command */
127 timestamp_current( &time_info
.start
);
128 times( &start_time
);
130 /* See if command is more than one line discounting leading/trailing white
133 for ( s
= cmd_string
; *s
&& isspace( *s
); ++s
);
135 e
= p
= strchr( s
, '\n' );
137 while ( p
&& isspace( *p
) )
140 /* If multi line or long, write to com file. Otherwise, exec directly. */
141 if ( ( p
&& *p
) || ( e
- s
> WRTLEN
) )
145 /* Create temp file invocation. */
149 OBJECT
* tmp_filename
= 0;
151 tmp_filename
= path_tmpfile();
154 /* Get tmp file name is VMS-format. */
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
);
165 strncat( commandbuf
+ 1, object_str( tmp_filename
),
166 VMS_COMMAND_MAX
- 2);
171 if ( !( f
= fopen( commandbuf
+ 1, "w" ) ) )
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
;
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.;
186 (*func
)( closure
, rstat
, &time_info
, "" , "", exit_reason
);
191 /* Running from TMP, so explicitly set default to CWD. */
194 int cwd_buf_size
= VMS_PATH_MAX
;
196 while ( !(cwd
= getcwd( NULL
, cwd_buf_size
) ) /* alloc internally */
199 cwd_buf_size
+= VMS_PATH_MAX
;
204 errno_puts( "can not get current working directory" );
205 b2::clean_exit( EXITBAD
);
208 fprintf( f
, "$ SET DEFAULT %s\n", cwd
);
214 /* For each line of the command. */
215 while ( *cmd_string
)
217 char * s
= strchr( cmd_string
,'\n' );
218 int len
= s
? s
+ 1 - cmd_string
: strlen( cmd_string
);
222 /* For each chunk of a line that needs to be split. */
225 char * q
= cmd_string
;
226 char * qe
= cmd_string
+ MIN( len
, WRTLEN
);
230 /* Look for matching "s -- expected in the same line. */
231 for ( ; q
< qe
; ++q
)
232 if ( ( *q
== CHAR_DQUOTE
) && ( quote
= !quote
) )
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.
241 if ( len
> WRTLEN
&& quote
)
245 if ( q
== cmd_string
)
247 for ( q
= qe
; q
< ( cmd_string
+ len
)
248 && *q
!= CHAR_DQUOTE
; ++q
) {}
249 q
= ( *q
== CHAR_DQUOTE
) ? ( q
+ 1 ) : ( cmd_string
+ len
);
253 fwrite( cmd_string
, ( q
- cmd_string
), 1, f
);
255 len
-= ( q
- cmd_string
);
271 char buf
[ WRTLEN
+ 1 ] = { 0 };
273 if ( (f
= fopen( commandbuf
+ 1, "r" ) ) )
276 printf( "Command file: %s\n", commandbuf
+ 1 );
280 nbytes
= fread( buf
, sizeof( buf
[0] ), sizeof( buf
) - 1, f
);
282 if ( nbytes
) fwrite(buf
, sizeof( buf
[0] ), nbytes
, stdout
);
290 /* Execute command file */
291 vms_status
= system( commandbuf
);
292 status
= get_status( vms_status
);
294 unlink( commandbuf
+ 1 );
298 /* Execute single line command. Strip trailing newline before execing.
299 * TODO:Call via popen() with capture of the output may be better here.
303 status
= VMS_SUCCESS
; /* success on empty command */
306 vms_status
= system( s
);
307 status
= get_status( vms_status
);
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.;
321 /* Fail for error or fatal error. OK on OK, warning or info exit. */
322 if ( ( status
== VMS_ERROR
) || ( status
== VMS_FATAL
) )
324 rstat
= EXEC_CMD_FAIL
;
325 exit_reason
= EXIT_FAIL
;
328 (*func
)( closure
, rstat
, &time_info
, "" , "", exit_reason
);
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
342 int get_status( int vms_status
)
344 #define VMS_STATUS_DCL_IVVERB 0x00038090
350 case VMS_STATUS_DCL_IVVERB
:
355 status
= vms_status
& 0x07; /* $SEVERITY bits */
362 #define __NEW_STARLET 1
373 #include <lib$routines.h>
378 * get_cpu_time() - returns CPU time in CLOCKS_PER_SEC since process start.
379 * on error returns (clock_t)-1.
381 * Intended to emulate (system + user) result of *NIX times(), if CRTL times()
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.
389 clock_t get_cpu_time()
391 clock_t result
= (clock_t) 0;
399 { sizeof( cputime
), JPI$_CPUTIM
, &cputime
, NULL
}, /* longword int, 10ms */
403 status
= sys$
getjpiw (EFN$C_ENF
, 0, 0, jpi_items
, &iosb
, 0, 0);
405 if ( !$
VMS_STATUS_SUCCESS( status
) )
407 lib$
signal( status
);
409 result
= (clock_t) -1;
414 result
= ( cputime
/ 100 ) * CLOCKS_PER_SEC
;
419 int32_t shell_maxline()