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:
parent
9af443f597
commit
5e2080ef93
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user