xc/programs/Xserver/Xprint/attributes.c

xc/programs/glxgears/glxgears.c
xc/programs/xdbedizzy/xdbedizzy.c
xc/programs/xedit/Imakefile
xc/programs/xedit/Xedit-xprint.ad
xc/programs/xedit/util.c
xc/programs/xedit/xedit.h
xc/programs/xlogo/print.c
xc/programs/xlogo/xlogo.c
xc/programs/xlogo/xlogo.h
xc/programs/xman/Imakefile
xc/programs/xman/print.h
xc/programs/xmore/Imakefile
xc/programs/xmore/print.c
xc/programs/xmore/print.h
xc/programs/xmore/printdialog.c
xc/programs/xphelloworld/xpawhelloworld/xpawhelloworld.c
xc/programs/xphelloworld/xphelloworld/xphelloworld.c
xc/programs/xphelloworld/xpsimplehelloworld/xpsimplehelloworld.c
xc/programs/xphelloworld/xpxmhelloworld/xpxmhelloworld.c
//bugs.freedesktop.org/show_bug.cgi?id=790) attachment #2379
    (https://bugs.freedesktop.org/attachment.cgi?id=2379) Implement support
    client+Xserver support for passing output (stdout+stderr) of the
    spooler command started by the Xprint server back to the application
    using the "xp-spooler-command-results" XPJobAttr attribute
    (applications can fetch the attribute value after the XPEndJobNotify
    event was received; more details can be found in
    http://xprint.mozdev.org/docs/dtprint_fspec.ps).
This commit is contained in:
Roland Mainz 2005-04-11 01:06:15 +00:00
parent 9af443f597
commit 5e2080ef93

View File

@ -65,6 +65,14 @@ copyright holders.
#include "spooler.h"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
static XrmDatabase CopyDb(XrmDatabase inDb);
extern XrmDatabase XpSpoolerGetServerAttributes(void);
@ -1083,6 +1091,50 @@ XpSpoolerGetServerAttributes(void)
return db;
}
/*
* Tailf() works similar to "/bin/tail -f fd_in >fd_out" until
* the process |child| terminates (the child status is
* returned in |child_status|).
* This function is used to copy the stdout/stderr output of a
* child to fd_out until the child terminates.
*/
static
void Tailf(int fd_in, int fd_out, pid_t child, int *child_status)
{
char b[256];
ssize_t sz;
Bool childDone = FALSE;
struct timeval timeout;
long fpos = 0; /* XXX: this is not correct for largefile support */
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
for(;;)
{
/* Check whether the child is still alive or not */
if (waitpid(child, child_status, WNOHANG) == child)
childDone = TRUE;
/* Copy traffic from |fd_in| to |fd_out|
* (Note we have to use |pread()| here to avoid race conditions
* between a child process writing to the same file using the
* same file pointer (|dup(2)| and |fork(2)| just duplicate the
* file handle but not the pointer)).
*/
while ((sz = pread(fd_in, b, sizeof(b), fpos)) > 0)
{
fpos += sz;
write(fd_out, b, sz);
}
if (childDone)
break;
(void)select(0, NULL, NULL, NULL, &timeout);
}
}
/*
* SendFileToCommand takes three character pointers - the file name,
* the command to execute,
@ -1095,6 +1147,7 @@ XpSpoolerGetServerAttributes(void)
*/
static void
SendFileToCommand(
XpContextPtr pContext,
char *fileName,
char *pCommand,
char **argVector,
@ -1105,22 +1158,39 @@ SendFileToCommand(
int status;
struct stat statBuf;
FILE *fp, *outPipe;
FILE *resFp; /* output from launched command */
int resfd;
resFp = tmpfile();
if (resFp == NULL)
{
ErrorF("SendFileToCommand: Cannot open temporary file for command output\n");
return;
}
resfd = fileno(resFp);
if(pipe(pipefd))
return;
{
ErrorF("SendFileToCommand: Cannot open pipe\n");
fclose(resFp);
return;
}
if(stat(fileName, &statBuf) < 0 || (int)statBuf.st_size == 0)
{
close(pipefd[0]);
close(pipefd[1]);
return;
close(pipefd[0]);
close(pipefd[1]);
fclose(resFp);
return;
}
fp = fopen(fileName, "r");
if(fp == (FILE *)NULL)
{
ErrorF("SendFileToCommand: Cannot open scratch spool file '%s'\n", fileName);
close(pipefd[0]);
close(pipefd[1]);
fclose(resFp);
return;
}
@ -1129,13 +1199,22 @@ SendFileToCommand(
close(pipefd[1]);
/* Replace current stdin with input from the pipe */
close(0);
close(STDIN_FILENO);
dup(pipefd[0]);
close(pipefd[0]);
/* Close current stdout and redirect it to stderr */
close(1);
dup(2);
/* Close current stdout and redirect it to resfd */
close(STDOUT_FILENO);
dup(resfd);
/* Close current stderr and redirect it to resfd
* (valgrind may not like that, in this case simply start it using
* % valgrind 50>/dev/tty --logfile-fd=50 <more-options> ./Xprt ... #)
*/
close(STDERR_FILENO);
dup(resfd);
fclose(resFp);
/*
* If a user name is specified, try to set our uid to match that
@ -1171,8 +1250,6 @@ SendFileToCommand(
}
else
{
int res;
(void) close(pipefd[0]);
outPipe = fdopen(pipefd[1], "w");
@ -1181,7 +1258,47 @@ SendFileToCommand(
(void) fclose(outPipe);
(void) fclose(fp);
(void) waitpid(childPid, &status, 0);
/* Wait for spooler child (and send all it's output to stderr) */
Tailf(resfd, STDERR_FILENO, childPid, &status);
if (status != EXIT_SUCCESS)
{
ErrorF("SendFileToCommand: spooler command returned non-zero status %d.\n", status);
}
/* Store "xp-spooler-command-results" XPJobAttr that the
* client can fetch it on demand */
if ((fstat(resfd, &statBuf) >= 0) && (statBuf.st_size >= 0))
{
long bufSize;
char *buf;
bufSize = statBuf.st_size;
/* Clamp buffer size to 4MB to prevent that we allocate giant
* buffers if the spooler goes mad and spams it's stdout/stderr
* channel. */
bufSize = MIN(bufSize, 4*1024*1024);
buf = xalloc(bufSize+1);
if (buf != NULL)
{
bufSize = pread(resfd, buf, bufSize, 0);
buf[bufSize]='\0';
/* XXX: This should be converted from local multibyte encoding to
* Compound Text encoding first */
XpPutOneAttribute(pContext, XPJobAttr, "xp-spooler-command-results", buf);
xfree(buf);
}
}
else
{
ErrorF("SendFileToCommand: fstat() failed.\n");
}
fclose(resFp);
}
return;
}
@ -1483,7 +1600,7 @@ XpSubmitJob(fileName, pContext)
if(userName != (char *)NULL && strlen(userName) == 0)
userName = (char *)NULL;
SendFileToCommand(fileName, cmdNam, vector, userName);
SendFileToCommand(pContext, fileName, cmdNam, vector, userName);
FreeVector(vector);
xfree(cmdNam);