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