2 * grace_np - a library for interfacing with Grace using pipes
4 * Copyright (c) 1997-1998 Henrik Seidel
5 * Copyright (c) 1999-2003 Grace Development Team
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #ifdef HAVE_SYS_PARAM_H
35 # include <sys/param.h>
37 #include <sys/types.h>
42 #ifdef HAVE_SYS_WAIT_H
43 # include <sys/wait.h>
52 /* static global variables */
53 static char* buf
= NULL
; /* global write buffer */
54 static int bufsize
; /* size of the global write buffer */
55 static int bufsizeforce
; /* threshold for forcing a flush */
56 static int fd_pipe
= -1; /* file descriptor of the pipe */
57 static pid_t pid
= (pid_t
) -1; /* pid of grace */
60 * notify grace when finished
64 notify_grace_on_exit(int status
, void* arg
)
66 notify_grace_on_exit(void)
75 * default function for reporting errors
78 GraceDefaultError(const char *msg
)
80 fprintf(stderr
, "%s\n", msg
);
84 * variable holding user function for reporting errors
86 static GraceErrorFunctionType error_function
= GraceDefaultError
;
89 * function for reporting system errors
92 GracePerror(const char *prefix
)
97 sprintf(msg
, "%s: %s", prefix
, strerror(errno
));
99 # ifdef HAVE_SYS_ERRLIST_IN_STDIO_H
100 sprintf(msg
, "%s: %s", prefix
, sys_errlist
[errno
]);
102 if (errno
== EPIPE
) {
103 /* this one deserve special attention here */
104 sprintf(msg
, "%s: Broken pipe", prefix
);
106 sprintf(msg
, "%s: System error (errno = %d)", prefix
, errno
);
114 /* Close the pipe and free the buffer */
119 if (close(fd_pipe
) != 0) {
120 GracePerror("GraceCleanup");
130 * try to send data to grace (one pass only)
133 GraceOneWrite(int left
)
137 written
= write(fd_pipe
, buf
, left
);
144 /* move the remaining characters (and the final '\0') */
146 memmove(buf
, buf
+ written
, left
+ 1);
148 bcopy(buf
+ written
, buf
, left
+ 1);
151 /* clear the buffer */
155 } else if (written
< 0) {
156 if (errno
== EPIPE
) {
157 /* Grace has closed the pipe : we cannot write anymore */
160 GracePerror("GraceOneWrite");
170 * register an user function to report errors
172 GraceErrorFunctionType
173 GraceRegisterErrorFunction(GraceErrorFunctionType f
)
175 GraceErrorFunctionType old
= error_function
;
176 if (f
!= (GraceErrorFunctionType
) NULL
) {
183 handle_sigchld(int signum
)
189 retval
= waitpid(pid
, &status
, WNOHANG
);
191 /* Grace just died */
198 GraceOpenVA(char* exe
, int bs
, ...)
208 error_function("Grace subprocess already running");
212 /* Set the buffer sizes according to arg */
214 error_function("The buffer size in GraceOpenVA should be >= 64");
218 bufsizeforce
= bs
/ 2;
220 /* make sure the grace subprocess is notified at the end */
222 on_exit(notify_grace_on_exit
, NULL
);
224 atexit(notify_grace_on_exit
);
227 /* Don't exit on SIGPIPE */
228 signal(SIGPIPE
, SIG_IGN
);
230 /* Don't exit when our child "grace" exits */
231 signal(SIGCHLD
, handle_sigchld
);
235 GracePerror("GraceOpenVA");
239 /* Fork a subprocess for starting grace */
241 if (pid
== (pid_t
) (-1)) {
242 GracePerror("GraceOpenVA");
248 /* If we are the child, replace ourselves with grace */
249 if (pid
== (pid_t
) 0) {
250 for (i
= 0; i
< OPEN_MAX
; i
++) {
251 /* we close everything except stdin, stdout, stderr
252 and the read part of the pipe */
255 i
!= STDOUT_FILENO
&&
256 i
!= STDERR_FILENO
) {
261 /* build the argument list */
264 arglist
= malloc((numarg
+ 1)*SIZEOF_VOID_P
);
266 arglist
[1] = "-dpipe";
267 sprintf(fd_number
, "%d", fd
[0]);
268 arglist
[2] = fd_number
;
269 while ((s
= va_arg(ap
, char *)) != NULL
) {
271 arglist
= realloc(arglist
, (numarg
+ 1)*SIZEOF_VOID_P
);
272 arglist
[numarg
- 1] = s
;
274 arglist
[numarg
] = NULL
;
277 execvp(exe
, arglist
);
279 /* if we get here execvp failed */
280 fprintf(stderr
, "GraceOpenVA: Could not start %s\n", exe
);
285 /* We are the parent -> keep the write part of the pipe
286 and allocate the write buffer */
287 buf
= malloc(bufsize
);
289 error_function("GraceOpenVA: Not enough memory");
305 return GraceOpenVA("xmgrace", bs
, "-nosafe", "-noask", NULL
);
311 return (fd_pipe
>= 0) ? 1 : 0;
318 error_function("No grace subprocess");
322 /* Tell grace to close the pipe */
323 if (GraceCommand ("exit") == -1 || GraceFlush() != 0){
336 error_function("No grace subprocess");
340 /* Tell grace to close the pipe */
341 if (GraceCommand ("close") == -1)
343 if (GraceFlush() != 0)
357 error_function("No grace subprocess");
363 for (loop
= 0; loop
< 30; loop
++) {
364 left
= GraceOneWrite(left
);
367 } else if (left
== 0) {
372 error_function("GraceFlush: ran into eternal loop");
378 GracePrintf(const char* fmt
, ...)
385 error_function("No grace subprocess");
389 /* Allocate a new string buffer for the function arguments */
390 str
= (char *) malloc ((size_t) bufsize
);
391 if (str
== (char *) NULL
) {
392 error_function("GracePrintf: Not enough memory");
395 /* Print to the string buffer according to the function arguments */
397 #if defined(HAVE_VSNPRINTF)
398 nchar
= vsnprintf (str
, bufsize
- 2, fmt
, ap
);
400 nchar
= vsprintf (str
, fmt
, ap
);
403 nchar
++; /* This is for the appended "\n" */
404 if (GraceCommand (str
) == -1) {
412 GraceCommand(const char* cmd
)
417 error_function("No grace subprocess");
421 /* Append the new string to the global write buffer */
422 if (strlen(buf
) + strlen(cmd
) + 2 > bufsize
) {
423 error_function("GraceCommand: Buffer full");
430 /* Try to send the global write buffer to grace */
431 left
= GraceOneWrite(left
);
432 if (left
>= bufsizeforce
) {
433 if (GraceFlush() != 0) {
436 } else if (left
< 0) {