1c9e2be55Smrg/* $XConsortium: command.c,v 2.49 95/04/05 19:59:06 kaleb Exp $ */ 2c9e2be55Smrg/* $XFree86: xc/programs/xmh/command.c,v 3.8 2001/12/09 15:48:36 herrb Exp $ */ 3c9e2be55Smrg 4c9e2be55Smrg/* 5c9e2be55Smrg * COPYRIGHT 1987, 1989 6c9e2be55Smrg * DIGITAL EQUIPMENT CORPORATION 7c9e2be55Smrg * MAYNARD, MASSACHUSETTS 8c9e2be55Smrg * ALL RIGHTS RESERVED. 9c9e2be55Smrg * 10c9e2be55Smrg * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND 11c9e2be55Smrg * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. 12c9e2be55Smrg * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR 13c9e2be55Smrg * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. 14c9e2be55Smrg * 15c9e2be55Smrg * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT 16c9e2be55Smrg * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN 17c9e2be55Smrg * ADDITION TO THAT SET FORTH ABOVE. 18c9e2be55Smrg * 19c9e2be55Smrg * 20c9e2be55Smrg * Permission to use, copy, modify, and distribute this software and its 21c9e2be55Smrg * documentation for any purpose and without fee is hereby granted, provided 22c9e2be55Smrg * that the above copyright notice appear in all copies and that both that 23c9e2be55Smrg * copyright notice and this permission notice appear in supporting 24c9e2be55Smrg * documentation, and that the name of Digital Equipment Corporation not be 25c9e2be55Smrg * used in advertising or publicity pertaining to distribution of the software 26c9e2be55Smrg * without specific, written prior permission. 27c9e2be55Smrg */ 28c9e2be55Smrg 29c9e2be55Smrg/* command.c -- interface to exec mh commands. */ 30c9e2be55Smrg 31c9e2be55Smrg#include "xmh.h" 32c9e2be55Smrg#include <X11/Xpoll.h> 33c9e2be55Smrg#include <sys/ioctl.h> 34c9e2be55Smrg#include <signal.h> 35c9e2be55Smrg#include <sys/wait.h> 36d859ff80Smrg#if defined(SVR4) 37c9e2be55Smrg#include <sys/filio.h> 38c9e2be55Smrg#endif 39c9e2be55Smrg 40c9e2be55Smrg/* number of user input events to queue before malloc */ 41c9e2be55Smrg#define TYPEAHEADSIZE 20 42c9e2be55Smrg 43d859ff80Smrg#ifndef HAVE_WORKING_VFORK 44d859ff80Smrg#define vfork fork 45c9e2be55Smrg#else 46d859ff80Smrg#ifdef HAVE_VFORK_H 47c9e2be55Smrg#include <vfork.h> 48c9e2be55Smrg#endif 49c9e2be55Smrg#endif 50c9e2be55Smrg 51c9e2be55Smrgtypedef struct _CommandStatus { 52c9e2be55Smrg Widget popup; /* must be first; see PopupStatus */ 53c9e2be55Smrg struct _LastInput lastInput; /* must be second; ditto */ 54c9e2be55Smrg char* shell_command; /* must be third; for XmhShellCommand */ 55c9e2be55Smrg int child_pid; 56c9e2be55Smrg XtInputId output_inputId; 57c9e2be55Smrg XtInputId error_inputId; 58c9e2be55Smrg int output_pipe[2]; 59c9e2be55Smrg int error_pipe[2]; 60c9e2be55Smrg char* output_buffer; 61c9e2be55Smrg int output_buf_size; 62c9e2be55Smrg char* error_buffer; 63c9e2be55Smrg int error_buf_size; 64c9e2be55Smrg} CommandStatusRec, *CommandStatus; 65c9e2be55Smrg 66c9e2be55Smrgtypedef char* Pointer; 67c9e2be55Smrgstatic void FreeStatus(XMH_CB_ARGS); 68c9e2be55Smrgstatic void CheckReadFromPipe(int, char **, int *, Bool); 69c9e2be55Smrg 7066d665a3Smrgstatic void SystemError(const char* text) 71c9e2be55Smrg{ 72c9e2be55Smrg char msg[BUFSIZ]; 7366d665a3Smrg snprintf( msg, sizeof(msg), "%s; errno = %d %s", text, errno, 74c9e2be55Smrg strerror(errno)); 75c9e2be55Smrg XtWarning( msg ); 76c9e2be55Smrg} 77c9e2be55Smrg 78c9e2be55Smrg 79c9e2be55Smrg/* Return the full path name of the given mh command. */ 80c9e2be55Smrg 8166d665a3Smrgstatic char *FullPathOfCommand(const char *str) 82c9e2be55Smrg{ 83c9e2be55Smrg static char result[100]; 8466d665a3Smrg snprintf(result, sizeof(result), "%s/%s", app_resources.mh_path, str); 85c9e2be55Smrg return result; 86c9e2be55Smrg} 87c9e2be55Smrg 88c9e2be55Smrg 89c9e2be55Smrg/*ARGSUSED*/ 90c9e2be55Smrgstatic void ReadStdout( 91c9e2be55Smrg XtPointer closure, 92c9e2be55Smrg int *fd, 93c9e2be55Smrg XtInputId *id) /* unused */ 94c9e2be55Smrg{ 95c9e2be55Smrg register CommandStatus status = (CommandStatus)closure; 96c9e2be55Smrg CheckReadFromPipe(*fd, &status->output_buffer, &status->output_buf_size, 97c9e2be55Smrg False); 98c9e2be55Smrg} 99c9e2be55Smrg 100c9e2be55Smrg 101c9e2be55Smrg/*ARGSUSED*/ 102c9e2be55Smrgstatic void ReadStderr( 103c9e2be55Smrg XtPointer closure, 104c9e2be55Smrg int *fd, 105c9e2be55Smrg XtInputId *id) /* unused */ 106c9e2be55Smrg{ 107c9e2be55Smrg register CommandStatus status = (CommandStatus)closure; 108c9e2be55Smrg CheckReadFromPipe(*fd, &status->error_buffer, &status->error_buf_size, 109c9e2be55Smrg False); 110c9e2be55Smrg} 111c9e2be55Smrg 112c9e2be55Smrg 113c9e2be55Smrgstatic volatile int childdone; /* Gets nonzero when the child process 114c9e2be55Smrg finishes. */ 115c9e2be55Smrg/* ARGSUSED */ 116c9e2be55Smrgstatic void 117c9e2be55SmrgChildDone(int n) 118c9e2be55Smrg{ 119c9e2be55Smrg childdone++; 120c9e2be55Smrg} 121c9e2be55Smrg 122c9e2be55Smrg/* Execute the given command, and wait until it has finished. While the 123c9e2be55Smrg command is executing, watch the X socket and cause Xlib to read in any 124c9e2be55Smrg incoming data. This will prevent the socket from overflowing during 125c9e2be55Smrg long commands. Returns 0 if stderr empty, -1 otherwise. */ 126c9e2be55Smrg 127c9e2be55Smrgstatic int _DoCommandToFileOrPipe( 12866d665a3Smrg char * const *argv, /* The command to execute, and its args. */ 129c9e2be55Smrg int inputfd, /* Input stream for command. */ 130c9e2be55Smrg int outputfd, /* Output stream; /dev/null if == -1 */ 131c9e2be55Smrg char **bufP, /* output buffer ptr if outputfd == -2 */ 132c9e2be55Smrg int *lenP) /* output length ptr if outputfd == -2 */ 133c9e2be55Smrg{ 134c9e2be55Smrg XtAppContext appCtx = XtWidgetToApplicationContext(toplevel); 135c9e2be55Smrg int return_status; 136c9e2be55Smrg int old_stdin = 0, old_stdout = 0, old_stderr = 0; 137c9e2be55Smrg int pid; 138c9e2be55Smrg fd_set readfds, fds; 139c9e2be55Smrg Boolean output_to_pipe = False; 140c9e2be55Smrg CommandStatus status = XtNew(CommandStatusRec); 141c9e2be55Smrg FD_ZERO(&fds); 142c9e2be55Smrg FD_SET(ConnectionNumber(theDisplay), &fds); 143c9e2be55Smrg DEBUG1("Executing %s ...", argv[0]) 144c9e2be55Smrg 145c9e2be55Smrg if (inputfd != -1) { 146c9e2be55Smrg old_stdin = dup(fileno(stdin)); 147c9e2be55Smrg (void) dup2(inputfd, fileno(stdin)); 148c9e2be55Smrg close(inputfd); 149c9e2be55Smrg } 150c9e2be55Smrg 151c9e2be55Smrg if (outputfd == -1) { 152c9e2be55Smrg if (!app_resources.debug) { /* Throw away stdout. */ 153c9e2be55Smrg outputfd = open( "/dev/null", O_WRONLY, 0 ); 154c9e2be55Smrg } 155c9e2be55Smrg } 156c9e2be55Smrg else if (outputfd == -2) { /* make pipe */ 157c9e2be55Smrg if (pipe(status->output_pipe) /*failed*/) { 158c9e2be55Smrg SystemError( "couldn't re-direct standard output" ); 159c9e2be55Smrg status->output_pipe[0]=0; 160c9e2be55Smrg } 161c9e2be55Smrg else { 162c9e2be55Smrg outputfd = status->output_pipe[1]; 163c9e2be55Smrg FD_SET(status->output_pipe[0], &fds); 164c9e2be55Smrg status->output_inputId = 165c9e2be55Smrg XtAppAddInput( appCtx, 166c9e2be55Smrg status->output_pipe[0], (XtPointer)XtInputReadMask, 167c9e2be55Smrg ReadStdout, (XtPointer)status 168c9e2be55Smrg ); 169c9e2be55Smrg status->output_buffer = NULL; 170c9e2be55Smrg status->output_buf_size = 0; 171c9e2be55Smrg output_to_pipe = True; 172c9e2be55Smrg } 173c9e2be55Smrg } 174c9e2be55Smrg 175c9e2be55Smrg if (pipe(status->error_pipe) /*failed*/) { 176c9e2be55Smrg SystemError( "couldn't re-direct standard error" ); 177c9e2be55Smrg status->error_pipe[0]=0; 178c9e2be55Smrg } 179c9e2be55Smrg else { 180c9e2be55Smrg old_stderr = dup(fileno(stderr)); 181c9e2be55Smrg (void) dup2(status->error_pipe[1], fileno(stderr)); 182c9e2be55Smrg close(status->error_pipe[1]); 183c9e2be55Smrg FD_SET(status->error_pipe[0], &fds); 184c9e2be55Smrg status->error_inputId = 185c9e2be55Smrg XtAppAddInput( appCtx, 186c9e2be55Smrg status->error_pipe[0], (XtPointer)XtInputReadMask, 187c9e2be55Smrg ReadStderr, (XtPointer)status 188c9e2be55Smrg ); 189c9e2be55Smrg } 190c9e2be55Smrg if (outputfd != -1) { 191c9e2be55Smrg old_stdout = dup(fileno(stdout)); 192c9e2be55Smrg (void) dup2(outputfd, fileno(stdout)); 193c9e2be55Smrg close(outputfd); 194c9e2be55Smrg } 195c9e2be55Smrg childdone = FALSE; 196c9e2be55Smrg status->popup = (Widget)NULL; 197c9e2be55Smrg status->lastInput = lastInput; 198c9e2be55Smrg status->error_buffer = NULL; 199c9e2be55Smrg status->error_buf_size = 0; 200c9e2be55Smrg (void) signal(SIGCHLD, ChildDone); 201c9e2be55Smrg pid = vfork(); 202c9e2be55Smrg if (inputfd != -1) { 203c9e2be55Smrg if (pid != 0) dup2(old_stdin, fileno(stdin)); 204c9e2be55Smrg close(old_stdin); 205c9e2be55Smrg } 206c9e2be55Smrg if (outputfd != -1) { 207c9e2be55Smrg if (pid != 0) dup2(old_stdout, fileno(stdout)); 208c9e2be55Smrg close(old_stdout); 209c9e2be55Smrg } 210c9e2be55Smrg if (status->error_pipe[0]) { 211c9e2be55Smrg if (pid != 0) dup2(old_stderr, fileno(stderr)); 212c9e2be55Smrg close(old_stderr); 213c9e2be55Smrg } 214c9e2be55Smrg 215c9e2be55Smrg if (pid == -1) Punt("Couldn't fork!"); 216c9e2be55Smrg if (pid) { /* We're the parent process. */ 217c9e2be55Smrg XEvent typeAheadQueue[TYPEAHEADSIZE], *eventP = typeAheadQueue; 218c9e2be55Smrg XEvent *altQueue = NULL; 219c9e2be55Smrg int type_ahead_count = 0, alt_queue_size = 0, alt_queue_count = 0; 220c9e2be55Smrg XtAppContext app = XtWidgetToApplicationContext(toplevel); 221c9e2be55Smrg int num_fds = ConnectionNumber(theDisplay)+1; 222c9e2be55Smrg if (output_to_pipe && status->output_pipe[0] >= num_fds) 223c9e2be55Smrg num_fds = status->output_pipe[0]+1; 224c9e2be55Smrg if (status->error_pipe[0] >= num_fds) 225c9e2be55Smrg num_fds = status->error_pipe[0]+1; 226c9e2be55Smrg status->child_pid = pid; 227c9e2be55Smrg DEBUG1( " pid=%d ", pid ) 228c9e2be55Smrg subProcessRunning = True; 229c9e2be55Smrg while (!childdone) { 230c9e2be55Smrg while (!(XtAppPending(app) & XtIMXEvent)) { 231c9e2be55Smrg /* this is gross, but the only other way is by 232c9e2be55Smrg * polling on timers or an extra pipe, since we're not 233c9e2be55Smrg * guaranteed to be able to malloc in a signal handler. 234c9e2be55Smrg */ 235c9e2be55Smrg readfds = fds; 236c9e2be55Smrg if (childdone) break; 237c9e2be55Smrg DEBUG("blocking.\n") 238c9e2be55Smrg (void) Select(num_fds, &readfds, NULL, NULL, NULL); 239c9e2be55Smrg DEBUG1("unblocked; child%s done.\n", childdone ? "" : " not") 240c9e2be55Smrg if (childdone) break; 241c9e2be55Smrg if (!FD_ISSET(ConnectionNumber(theDisplay), &readfds)) { 242c9e2be55Smrg DEBUG("reading alternate input...") 243c9e2be55Smrg XtAppProcessEvent(appCtx, (unsigned)XtIMAlternateInput); 244c9e2be55Smrg DEBUG("read.\n") 245c9e2be55Smrg } 246c9e2be55Smrg } 247c9e2be55Smrg if (childdone) break; 248c9e2be55Smrg XtAppNextEvent(app, eventP); 249c9e2be55Smrg switch(eventP->type) { 250c9e2be55Smrg case LeaveNotify: 251c9e2be55Smrg if (type_ahead_count) { 252c9e2be55Smrg /* do compress_enterleave here to save memory */ 253c9e2be55Smrg XEvent *prevEvent; 254c9e2be55Smrg if (alt_queue_size && (alt_queue_count == 0)) 255c9e2be55Smrg prevEvent = &typeAheadQueue[type_ahead_count-1]; 256c9e2be55Smrg else 257c9e2be55Smrg prevEvent = eventP - 1; 258c9e2be55Smrg if (prevEvent->type == EnterNotify 259c9e2be55Smrg && prevEvent->xany.display == eventP->xany.display 260c9e2be55Smrg && prevEvent->xany.window == eventP->xany.window) { 261c9e2be55Smrg eventP = prevEvent; 262c9e2be55Smrg if (alt_queue_count > 0) 263c9e2be55Smrg alt_queue_count--; 264c9e2be55Smrg else 265c9e2be55Smrg type_ahead_count--; 266c9e2be55Smrg break; 267c9e2be55Smrg } 268c9e2be55Smrg } 269c9e2be55Smrg /* fall through */ 270c9e2be55Smrg case KeyPress: 271c9e2be55Smrg case KeyRelease: 272c9e2be55Smrg case EnterNotify: 273c9e2be55Smrg case ButtonPress: 274c9e2be55Smrg case ButtonRelease: 275c9e2be55Smrg case MotionNotify: 276c9e2be55Smrg if (type_ahead_count < TYPEAHEADSIZE) { 277c9e2be55Smrg if (++type_ahead_count == TYPEAHEADSIZE) { 27866d665a3Smrg altQueue = XtMallocArray( 27966d665a3Smrg (Cardinal)TYPEAHEADSIZE, sizeof(XEvent) ); 280c9e2be55Smrg alt_queue_size = TYPEAHEADSIZE; 281c9e2be55Smrg eventP = altQueue; 282c9e2be55Smrg } 283c9e2be55Smrg else 284c9e2be55Smrg eventP++; 285c9e2be55Smrg } 286c9e2be55Smrg else { 287c9e2be55Smrg if (++alt_queue_count == alt_queue_size) { 288c9e2be55Smrg alt_queue_size += TYPEAHEADSIZE; 28966d665a3Smrg altQueue = XtReallocArray(altQueue, 29066d665a3Smrg (Cardinal)alt_queue_size, sizeof(XEvent) ); 291c9e2be55Smrg eventP = &altQueue[alt_queue_count]; 292c9e2be55Smrg } 293c9e2be55Smrg else 294c9e2be55Smrg eventP++; 295c9e2be55Smrg } 296c9e2be55Smrg break; 297c9e2be55Smrg 298c9e2be55Smrg default: 299c9e2be55Smrg XtDispatchEvent(eventP); 300c9e2be55Smrg } 301c9e2be55Smrg } 302c9e2be55Smrg (void) wait(0); 303c9e2be55Smrg 304c9e2be55Smrg DEBUG("done\n") 305c9e2be55Smrg subProcessRunning = False; 306c9e2be55Smrg if (output_to_pipe) { 307c9e2be55Smrg CheckReadFromPipe( status->output_pipe[0], 308c9e2be55Smrg &status->output_buffer, 309c9e2be55Smrg &status->output_buf_size, 310c9e2be55Smrg True 311c9e2be55Smrg ); 312c9e2be55Smrg *bufP = status->output_buffer; 313c9e2be55Smrg *lenP = status->output_buf_size; 314c9e2be55Smrg close( status->output_pipe[0] ); 315c9e2be55Smrg XtRemoveInput( status->output_inputId ); 316c9e2be55Smrg } 317c9e2be55Smrg if (status->error_pipe[0]) { 318c9e2be55Smrg CheckReadFromPipe( status->error_pipe[0], 319c9e2be55Smrg &status->error_buffer, 320c9e2be55Smrg &status->error_buf_size, 321c9e2be55Smrg True 322c9e2be55Smrg ); 323c9e2be55Smrg close( status->error_pipe[0] ); 324c9e2be55Smrg XtRemoveInput( status->error_inputId ); 325c9e2be55Smrg } 326c9e2be55Smrg if (status->error_buffer != NULL) { 327c9e2be55Smrg /* special case for arbitrary shell commands: capture command */ 328c9e2be55Smrg if ((strcmp(argv[0], "/bin/sh") == 0) && 329c9e2be55Smrg (strcmp(argv[1], "-c") == 0)) { 330c9e2be55Smrg status->shell_command = XtNewString(argv[2]); 331c9e2be55Smrg } else status->shell_command = (char*) NULL; 332d859ff80Smrg 333c9e2be55Smrg while (status->error_buffer[status->error_buf_size-1] == '\0') 334c9e2be55Smrg status->error_buf_size--; 335c9e2be55Smrg while (status->error_buffer[status->error_buf_size-1] == '\n') 336c9e2be55Smrg status->error_buffer[--status->error_buf_size] = '\0'; 337c9e2be55Smrg DEBUG1( "stderr = \"%s\"\n", status->error_buffer ) 338c9e2be55Smrg PopupNotice( status->error_buffer, FreeStatus, (Pointer)status ); 339c9e2be55Smrg return_status = -1; 340c9e2be55Smrg } 341c9e2be55Smrg else { 342c9e2be55Smrg XtFree( (Pointer)status ); 343c9e2be55Smrg return_status = 0; 344c9e2be55Smrg } 345c9e2be55Smrg for (;alt_queue_count;alt_queue_count--) { 346c9e2be55Smrg XPutBackEvent(theDisplay, --eventP); 347c9e2be55Smrg } 348c9e2be55Smrg if (type_ahead_count) { 349c9e2be55Smrg if (alt_queue_size) eventP = &typeAheadQueue[type_ahead_count]; 350c9e2be55Smrg for (;type_ahead_count;type_ahead_count--) { 351c9e2be55Smrg XPutBackEvent(theDisplay, --eventP); 352c9e2be55Smrg } 353c9e2be55Smrg } 354c9e2be55Smrg } else { /* We're the child process. */ 355c9e2be55Smrg /* take it from the user's path, else fall back to the mhPath */ 356c9e2be55Smrg (void) execvp(argv[0], argv); 357c9e2be55Smrg (void) execv(FullPathOfCommand(argv[0]), argv); 358c9e2be55Smrg progName = argv[0]; /* for Punt message */ 359c9e2be55Smrg Punt("(cannot execvp it)"); 360c9e2be55Smrg return_status = -1; 361c9e2be55Smrg } 362c9e2be55Smrg return return_status; 363c9e2be55Smrg} 364c9e2be55Smrg 365c9e2be55Smrg 366c9e2be55Smrgstatic void 367c9e2be55SmrgCheckReadFromPipe( 368c9e2be55Smrg int fd, 369c9e2be55Smrg char **bufP, 370c9e2be55Smrg int *lenP, 371c9e2be55Smrg Bool waitEOF) 372c9e2be55Smrg{ 373c9e2be55Smrg int nread; 374c9e2be55Smrg/* DEBUG2( " CheckReadFromPipe #%d,len=%d,", fd, *lenP ) */ 375c9e2be55Smrg#ifdef FIONREAD 376c9e2be55Smrg if (!ioctl( fd, FIONREAD, &nread )) { 377c9e2be55Smrg/* DEBUG1( "nread=%d ...", nread ) */ 378c9e2be55Smrg if (nread) { 379c9e2be55Smrg int old_end = *lenP; 380c9e2be55Smrg *bufP = XtRealloc( *bufP, (Cardinal) ((*lenP += nread) + 1) ); 381c9e2be55Smrg read( fd, *bufP+old_end, nread ); 382c9e2be55Smrg (*bufP)[old_end+nread] = '\0'; 383c9e2be55Smrg } 384c9e2be55Smrg return; 385c9e2be55Smrg } 386c9e2be55Smrg#endif 387c9e2be55Smrg do { 388c9e2be55Smrg char buf[512]; 389c9e2be55Smrg int old_end = *lenP; 390c9e2be55Smrg nread = read( fd, buf, 512 ); 391c9e2be55Smrg if (nread <= 0) 392c9e2be55Smrg break; 393c9e2be55Smrg *bufP = XtRealloc( *bufP, (Cardinal) ((*lenP += nread) + 1) ); 394c9e2be55Smrg memmove( *bufP+old_end, buf, (int) nread ); 395c9e2be55Smrg (*bufP)[old_end+nread] = '\0'; 396c9e2be55Smrg } while (waitEOF); 397c9e2be55Smrg} 398c9e2be55Smrg 399c9e2be55Smrg 400c9e2be55Smrg/* ARGSUSED */ 401c9e2be55Smrgstatic void FreeStatus( 402c9e2be55Smrg Widget w, /* unused */ 403c9e2be55Smrg XtPointer closure, 404c9e2be55Smrg XtPointer call_data) /* unused */ 405c9e2be55Smrg{ 406c9e2be55Smrg CommandStatus status = (CommandStatus)closure; 407c9e2be55Smrg if (status->popup != (Widget)NULL) { 408c9e2be55Smrg XtPopdown( status->popup ); 409c9e2be55Smrg XtDestroyWidget( status->popup ); 410c9e2be55Smrg } 411c9e2be55Smrg if (status->error_buffer != NULL) XtFree(status->error_buffer); 412c9e2be55Smrg XtFree( closure ); 413c9e2be55Smrg} 414c9e2be55Smrg 415c9e2be55Smrg/* Execute the given command, waiting until it's finished. Put the output 416c9e2be55Smrg in the specified file path. Returns 0 if stderr empty, -1 otherwise */ 417c9e2be55Smrg 418c9e2be55Smrgint DoCommand( 41966d665a3Smrg char * const *argv, /* The command to execute, and its args. */ 42066d665a3Smrg const char *inputfile, /* Input file for command. */ 42166d665a3Smrg const char *outputfile) /* Output file for command. */ 422c9e2be55Smrg{ 423c9e2be55Smrg int fd_in, fd_out; 424c9e2be55Smrg int status; 425c9e2be55Smrg 426c9e2be55Smrg if (inputfile != NULL) { 427c9e2be55Smrg FILEPTR file = FOpenAndCheck(inputfile, "r"); 428c9e2be55Smrg fd_in = dup(fileno(file)); 429c9e2be55Smrg myfclose(file); 430c9e2be55Smrg } 431c9e2be55Smrg else 432c9e2be55Smrg fd_in = -1; 433c9e2be55Smrg 434c9e2be55Smrg if (outputfile) { 435c9e2be55Smrg FILEPTR file = FOpenAndCheck(outputfile, "w"); 436c9e2be55Smrg fd_out = dup(fileno(file)); 437c9e2be55Smrg myfclose(file); 438c9e2be55Smrg } 439c9e2be55Smrg else 440c9e2be55Smrg fd_out = -1; 441c9e2be55Smrg 442c9e2be55Smrg status = _DoCommandToFileOrPipe( argv, fd_in, fd_out, (char **) NULL, 443c9e2be55Smrg (int *) NULL ); 444c9e2be55Smrg return status; 445c9e2be55Smrg} 446c9e2be55Smrg 447c9e2be55Smrg/* Execute the given command, waiting until it's finished. Put the output 448c9e2be55Smrg in a newly mallocced string, and return a pointer to that string. */ 449c9e2be55Smrg 45066d665a3Smrgchar *DoCommandToString(char * const *argv) 451c9e2be55Smrg{ 452c9e2be55Smrg char *result = NULL; 453c9e2be55Smrg int len = 0; 454c9e2be55Smrg _DoCommandToFileOrPipe( argv, -1, -2, &result, &len ); 455c9e2be55Smrg if (result == NULL) result = XtMalloc((Cardinal) 1); 456c9e2be55Smrg result[len] = '\0'; 457c9e2be55Smrg DEBUG1("('%s')\n", result) 458c9e2be55Smrg return result; 459c9e2be55Smrg} 460d859ff80Smrg 461c9e2be55Smrg 462c9e2be55Smrg/* Execute the command to a temporary file, and return the name of the file. */ 463c9e2be55Smrg 46466d665a3Smrgchar *DoCommandToFile(char * const *argv) 465c9e2be55Smrg{ 466c9e2be55Smrg char *name; 467c9e2be55Smrg FILEPTR file; 468c9e2be55Smrg int fd; 469c9e2be55Smrg name = MakeNewTempFileName(); 470c9e2be55Smrg file = FOpenAndCheck(name, "w"); 471c9e2be55Smrg fd = dup(fileno(file)); 472c9e2be55Smrg myfclose(file); 473c9e2be55Smrg _DoCommandToFileOrPipe(argv, -1, fd, (char **) NULL, (int *) NULL); 474c9e2be55Smrg return name; 475c9e2be55Smrg} 476