command.c revision d859ff80
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 70c9e2be55Smrgstatic void SystemError(char* text) 71c9e2be55Smrg{ 72c9e2be55Smrg char msg[BUFSIZ]; 73d859ff80Smrg sprintf( 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 81c9e2be55Smrgstatic char *FullPathOfCommand(char *str) 82c9e2be55Smrg{ 83c9e2be55Smrg static char result[100]; 84c9e2be55Smrg (void) sprintf(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( 128c9e2be55Smrg char **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) { 278c9e2be55Smrg altQueue = (XEvent*)XtMalloc( 279d859ff80Smrg (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; 289c9e2be55Smrg altQueue = (XEvent*)XtRealloc( 290c9e2be55Smrg (char*)altQueue, 291c9e2be55Smrg (Cardinal)alt_queue_size*sizeof(XEvent) ); 292c9e2be55Smrg eventP = &altQueue[alt_queue_count]; 293c9e2be55Smrg } 294c9e2be55Smrg else 295c9e2be55Smrg eventP++; 296c9e2be55Smrg } 297c9e2be55Smrg break; 298c9e2be55Smrg 299c9e2be55Smrg default: 300c9e2be55Smrg XtDispatchEvent(eventP); 301c9e2be55Smrg } 302c9e2be55Smrg } 303c9e2be55Smrg (void) wait(0); 304c9e2be55Smrg 305c9e2be55Smrg DEBUG("done\n") 306c9e2be55Smrg subProcessRunning = False; 307c9e2be55Smrg if (output_to_pipe) { 308c9e2be55Smrg CheckReadFromPipe( status->output_pipe[0], 309c9e2be55Smrg &status->output_buffer, 310c9e2be55Smrg &status->output_buf_size, 311c9e2be55Smrg True 312c9e2be55Smrg ); 313c9e2be55Smrg *bufP = status->output_buffer; 314c9e2be55Smrg *lenP = status->output_buf_size; 315c9e2be55Smrg close( status->output_pipe[0] ); 316c9e2be55Smrg XtRemoveInput( status->output_inputId ); 317c9e2be55Smrg } 318c9e2be55Smrg if (status->error_pipe[0]) { 319c9e2be55Smrg CheckReadFromPipe( status->error_pipe[0], 320c9e2be55Smrg &status->error_buffer, 321c9e2be55Smrg &status->error_buf_size, 322c9e2be55Smrg True 323c9e2be55Smrg ); 324c9e2be55Smrg close( status->error_pipe[0] ); 325c9e2be55Smrg XtRemoveInput( status->error_inputId ); 326c9e2be55Smrg } 327c9e2be55Smrg if (status->error_buffer != NULL) { 328c9e2be55Smrg /* special case for arbitrary shell commands: capture command */ 329c9e2be55Smrg if ((strcmp(argv[0], "/bin/sh") == 0) && 330c9e2be55Smrg (strcmp(argv[1], "-c") == 0)) { 331c9e2be55Smrg status->shell_command = XtNewString(argv[2]); 332c9e2be55Smrg } else status->shell_command = (char*) NULL; 333d859ff80Smrg 334c9e2be55Smrg while (status->error_buffer[status->error_buf_size-1] == '\0') 335c9e2be55Smrg status->error_buf_size--; 336c9e2be55Smrg while (status->error_buffer[status->error_buf_size-1] == '\n') 337c9e2be55Smrg status->error_buffer[--status->error_buf_size] = '\0'; 338c9e2be55Smrg DEBUG1( "stderr = \"%s\"\n", status->error_buffer ) 339c9e2be55Smrg PopupNotice( status->error_buffer, FreeStatus, (Pointer)status ); 340c9e2be55Smrg return_status = -1; 341c9e2be55Smrg } 342c9e2be55Smrg else { 343c9e2be55Smrg XtFree( (Pointer)status ); 344c9e2be55Smrg return_status = 0; 345c9e2be55Smrg } 346c9e2be55Smrg for (;alt_queue_count;alt_queue_count--) { 347c9e2be55Smrg XPutBackEvent(theDisplay, --eventP); 348c9e2be55Smrg } 349c9e2be55Smrg if (type_ahead_count) { 350c9e2be55Smrg if (alt_queue_size) eventP = &typeAheadQueue[type_ahead_count]; 351c9e2be55Smrg for (;type_ahead_count;type_ahead_count--) { 352c9e2be55Smrg XPutBackEvent(theDisplay, --eventP); 353c9e2be55Smrg } 354c9e2be55Smrg } 355c9e2be55Smrg } else { /* We're the child process. */ 356c9e2be55Smrg /* take it from the user's path, else fall back to the mhPath */ 357c9e2be55Smrg (void) execvp(argv[0], argv); 358c9e2be55Smrg (void) execv(FullPathOfCommand(argv[0]), argv); 359c9e2be55Smrg progName = argv[0]; /* for Punt message */ 360c9e2be55Smrg Punt("(cannot execvp it)"); 361c9e2be55Smrg return_status = -1; 362c9e2be55Smrg } 363c9e2be55Smrg return return_status; 364c9e2be55Smrg} 365c9e2be55Smrg 366c9e2be55Smrg 367c9e2be55Smrgstatic void 368c9e2be55SmrgCheckReadFromPipe( 369c9e2be55Smrg int fd, 370c9e2be55Smrg char **bufP, 371c9e2be55Smrg int *lenP, 372c9e2be55Smrg Bool waitEOF) 373c9e2be55Smrg{ 374c9e2be55Smrg int nread; 375c9e2be55Smrg/* DEBUG2( " CheckReadFromPipe #%d,len=%d,", fd, *lenP ) */ 376c9e2be55Smrg#ifdef FIONREAD 377c9e2be55Smrg if (!ioctl( fd, FIONREAD, &nread )) { 378c9e2be55Smrg/* DEBUG1( "nread=%d ...", nread ) */ 379c9e2be55Smrg if (nread) { 380c9e2be55Smrg int old_end = *lenP; 381c9e2be55Smrg *bufP = XtRealloc( *bufP, (Cardinal) ((*lenP += nread) + 1) ); 382c9e2be55Smrg read( fd, *bufP+old_end, nread ); 383c9e2be55Smrg (*bufP)[old_end+nread] = '\0'; 384c9e2be55Smrg } 385c9e2be55Smrg return; 386c9e2be55Smrg } 387c9e2be55Smrg#endif 388c9e2be55Smrg do { 389c9e2be55Smrg char buf[512]; 390c9e2be55Smrg int old_end = *lenP; 391c9e2be55Smrg nread = read( fd, buf, 512 ); 392c9e2be55Smrg if (nread <= 0) 393c9e2be55Smrg break; 394c9e2be55Smrg *bufP = XtRealloc( *bufP, (Cardinal) ((*lenP += nread) + 1) ); 395c9e2be55Smrg memmove( *bufP+old_end, buf, (int) nread ); 396c9e2be55Smrg (*bufP)[old_end+nread] = '\0'; 397c9e2be55Smrg } while (waitEOF); 398c9e2be55Smrg} 399c9e2be55Smrg 400c9e2be55Smrg 401c9e2be55Smrg/* ARGSUSED */ 402c9e2be55Smrgstatic void FreeStatus( 403c9e2be55Smrg Widget w, /* unused */ 404c9e2be55Smrg XtPointer closure, 405c9e2be55Smrg XtPointer call_data) /* unused */ 406c9e2be55Smrg{ 407c9e2be55Smrg CommandStatus status = (CommandStatus)closure; 408c9e2be55Smrg if (status->popup != (Widget)NULL) { 409c9e2be55Smrg XtPopdown( status->popup ); 410c9e2be55Smrg XtDestroyWidget( status->popup ); 411c9e2be55Smrg } 412c9e2be55Smrg if (status->error_buffer != NULL) XtFree(status->error_buffer); 413c9e2be55Smrg XtFree( closure ); 414c9e2be55Smrg} 415c9e2be55Smrg 416c9e2be55Smrg/* Execute the given command, waiting until it's finished. Put the output 417c9e2be55Smrg in the specified file path. Returns 0 if stderr empty, -1 otherwise */ 418c9e2be55Smrg 419c9e2be55Smrgint DoCommand( 420c9e2be55Smrg char **argv, /* The command to execute, and its args. */ 421c9e2be55Smrg char *inputfile, /* Input file for command. */ 422c9e2be55Smrg char *outputfile) /* Output file for command. */ 423c9e2be55Smrg{ 424c9e2be55Smrg int fd_in, fd_out; 425c9e2be55Smrg int status; 426c9e2be55Smrg 427c9e2be55Smrg if (inputfile != NULL) { 428c9e2be55Smrg FILEPTR file = FOpenAndCheck(inputfile, "r"); 429c9e2be55Smrg fd_in = dup(fileno(file)); 430c9e2be55Smrg myfclose(file); 431c9e2be55Smrg } 432c9e2be55Smrg else 433c9e2be55Smrg fd_in = -1; 434c9e2be55Smrg 435c9e2be55Smrg if (outputfile) { 436c9e2be55Smrg FILEPTR file = FOpenAndCheck(outputfile, "w"); 437c9e2be55Smrg fd_out = dup(fileno(file)); 438c9e2be55Smrg myfclose(file); 439c9e2be55Smrg } 440c9e2be55Smrg else 441c9e2be55Smrg fd_out = -1; 442c9e2be55Smrg 443c9e2be55Smrg status = _DoCommandToFileOrPipe( argv, fd_in, fd_out, (char **) NULL, 444c9e2be55Smrg (int *) NULL ); 445c9e2be55Smrg return status; 446c9e2be55Smrg} 447c9e2be55Smrg 448c9e2be55Smrg/* Execute the given command, waiting until it's finished. Put the output 449c9e2be55Smrg in a newly mallocced string, and return a pointer to that string. */ 450c9e2be55Smrg 451c9e2be55Smrgchar *DoCommandToString(char ** argv) 452c9e2be55Smrg{ 453c9e2be55Smrg char *result = NULL; 454c9e2be55Smrg int len = 0; 455c9e2be55Smrg _DoCommandToFileOrPipe( argv, -1, -2, &result, &len ); 456c9e2be55Smrg if (result == NULL) result = XtMalloc((Cardinal) 1); 457c9e2be55Smrg result[len] = '\0'; 458c9e2be55Smrg DEBUG1("('%s')\n", result) 459c9e2be55Smrg return result; 460c9e2be55Smrg} 461d859ff80Smrg 462c9e2be55Smrg 463c9e2be55Smrg/* Execute the command to a temporary file, and return the name of the file. */ 464c9e2be55Smrg 465c9e2be55Smrgchar *DoCommandToFile(char **argv) 466c9e2be55Smrg{ 467c9e2be55Smrg char *name; 468c9e2be55Smrg FILEPTR file; 469c9e2be55Smrg int fd; 470c9e2be55Smrg name = MakeNewTempFileName(); 471c9e2be55Smrg file = FOpenAndCheck(name, "w"); 472c9e2be55Smrg fd = dup(fileno(file)); 473c9e2be55Smrg myfclose(file); 474c9e2be55Smrg _DoCommandToFileOrPipe(argv, -1, fd, (char **) NULL, (int *) NULL); 475c9e2be55Smrg return name; 476c9e2be55Smrg} 477