/* * Copyright 1993, 1995 Christopher Seiwald. * * This file is part of Jam - see jam.c for Copyright information. */ /* * execas400.c - execute a command on an AS/400 system. * * The AS/400 implementation of system(3) is pretty lame. It returns * only -1, 0, or 1 so you can't easily spot interruptions. To get * that information you need to use spawn() or spawnp() which don't * block signals to the parent process; but of course you have to * manage the process creation in much more detail. * * External routines: * execcmd() - launch an async command execution * execwait() - wait and drive at most one execution completion * * Internal routines: * onintr() - bump intr to note command interruption * * * 06/08/05 (tony smith) - First implementation */ # include "jam.h" # include "lists.h" # include "execcmd.h" # ifdef OS_AS400 # define AS400_EXEC_SPAWN # include <stdio.h> # include <string.h> # include <stdlib.h> # ifdef AS400_EXEC_SPAWN # include <spawn.h> # endif extern char **environ; static int intr = 0; # ifdef AS400_EXEC_SPAWN /* * This implementation uses the spawnp() interface on AS/400 to execute * commands. This allows us to get a real exit status from the child * instead of the lame return value from system() on AS/400. */ static void onintr( int sig ) { printf( "...interrupted\n" ); intr++; } void execcmd( char *string, void (*func)( void *closure, int status ), void *closure, LIST *shell ) { int rstat = EXEC_CMD_FAIL; void (*old_handler)( int ); int fd_map[4]; int pipefds[ 2 ]; pid_t child_pid; int wait_status; int len; char *argv[4] = { 0 }; char buf[128]; struct inheritance inherit = { 0 }; /* * Command to run. We use qsh to invoke the compiler, */ char *qsh = "qsh"; /* Skip leading whitespace */ for( ; string; string++ ) if( !isspace( *string ) ) break; argv[ 0 ] = qsh; argv[ 1 ] = "-c"; argv[ 2 ] = string; /* * Allocate a pipe so we can talk to the child process. */ if( pipe( pipefds ) ) { fprintf( stderr, "Unable to create a pipe\n" ); goto done; } /* * Install our signal handler */ old_handler = signal( SIGINT, onintr ); /* * Connect the pipe fds up to the child processes stdin,stdout,stderr */ fd_map[ 0 ] = pipefds[ 0 ]; fd_map[ 1 ] = pipefds[ 1 ]; fd_map[ 2 ] = pipefds[ 1 ]; /* * Make sure that spawn() will set up stdin, stdout and stderr in * the child properly. This initializes the environ pointer so we * must call it before we spawn. */ putenv( "QIBM_USE_DESCRIPTOR_STDIO=Y" ); /* Now execute it */ child_pid = spawnp( qsh, 3, fd_map, &inherit, argv, environ ); if( child_pid < 0 ) { fprintf( stderr, "Error spawning sub-process\n" ); goto cleanup; } /* Read and print the child's output from the pipe */ close( pipefds[ 1 ] ); while( ( len = read( pipefds[ 0 ], buf, sizeof( buf ) - 1 ) ) > 0 ) { buf[ len ] = 0; printf( "%s", buf ); } /* Wait for the child to exit */ if( waitpid( child_pid, &wait_status, 0 ) < 0 ) { fprintf( stderr, "Failed to wait for child process...\n" ); goto cleanup; } /* * Examine the child's exit status */ if( intr ) rstat = EXEC_CMD_INTR; else if( WIFEXITED( wait_status ) && !WEXITSTATUS( wait_status ) ) rstat = EXEC_CMD_OK; else rstat = EXEC_CMD_FAIL; cleanup: signal( SIGINT, old_handler ); close( pipefds[ 0 ] ); close( pipefds[ 1 ] ); done: (*func)( closure, rstat ); } # else /* * On AS/400 we can also use the system() interface to execute commands, the * problem with doing this is that the AS/400 implementation of system only * returns zero, 1 or -1 and doesn't tell us the reason for failure. */ void execcmd( char *string, void (*func)( void *closure, int status ), void *closure, LIST *shell ) { char *s; int rstat = EXEC_CMD_OK; int status; /* * Command to run. We use qsh to invoke the compiler, but we * can't tell if it worked or not really because the return value * of system() is too vague. We also can't easily tell if we've * been interrupted. */ const char *qsh = "qsh -c"; /* Strip leading whitespace */ for( ; string && isspace( *string ); string++ ) ; /* Build Q-Shell command */ s = malloc( strlen( string ) + strlen( qsh ) + 16 ); sprintf( s, "%s \"%s\"", qsh, string ); /* Now execute it */ status = system( s ); free( s ); if( status ) rstat = EXEC_CMD_FAIL; (*func)( closure, rstat ); } #endif /* AS400_EXEC_SPAWN */ int execwait() { return 0; } int execmax() { return MAXLINE; } # endif /* AS400 */
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 9906 | tony |
AS/400 Porting changes. Static variable intr wasn't declared on AS/400. This was the only change required to build Jam on that platform. Porting change only. p4transfer.py: Transferred from production |
||
#1 | 9905 | tony |
jam and 2004.2 p4 client for AS/400. Built on AS/400 V5R2 with native ILE C/C++ compiler. Note, this build reports itself as P4/AS400/2004.2/76944 but this change contains porting changes that were required to make the build work so the changelist number is incorrect. This can be resolved with a clean build for 2005.1 at a later date. p4.sav and jam.sav are AS/400 "Save Files" that can be used to install the software on an AS/400 machine. The p4.sav file includes the p4.cmd and p4sync.cmd files we distributed with our older AS/400 builds. These files define a forms-type interface for supplying the parameters to the commands when you run them. Porting change only. No functional change. p4transfer.py: Transferred from production |