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