summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorgad <gad@FreeBSD.org>2009-06-24 16:57:33 +0000
committergad <gad@FreeBSD.org>2009-06-24 16:57:33 +0000
commit9a6a7d8ce26144dca1e9a288a4457749f465514a (patch)
tree901f0b263379b969c0acde87a5cb307136d31351 /usr.sbin
parent8680a0da13e7d0054f547e794e0db7ea71121a01 (diff)
downloadFreeBSD-src-9a6a7d8ce26144dca1e9a288a4457749f465514a.zip
FreeBSD-src-9a6a7d8ce26144dca1e9a288a4457749f465514a.tar.gz
Fix end-of-line issues that can come up when `lpq' reads information
about a queue from a remote host. That remote host may use \r, \r\n, or \n\r as the line-ending character. In some cases the remote host will write a single line of information without *any* EOL sequence. Translate all the non-unix EOL's to the standard newline, and make sure the final line includes a terminating newline. Logic is also added to translate all unprintable characters to '?', but that is #if-ed out for now. PR: bin/104731 MFC after: 3 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/lpr/common_source/displayq.c103
1 files changed, 102 insertions, 1 deletions
diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c
index 6c03621..62df9d3 100644
--- a/usr.sbin/lpr/common_source/displayq.c
+++ b/usr.sbin/lpr/common_source/displayq.c
@@ -69,6 +69,13 @@ __FBSDID("$FreeBSD$");
#define SIZCOL 62 /* start of Size column in normal */
/*
+ * isprint() takes a parameter of 'int', but expect values in the range
+ * of unsigned char. Define a wrapper which takes a value of type 'char',
+ * whether signed or unsigned, and ensure it ends up in the right range.
+ */
+#define isprintch(Anychar) isprint((u_char)(Anychar))
+
+/*
* Stuff for handling job specifications
*/
extern uid_t uid, euid;
@@ -86,6 +93,7 @@ static const char *head0 = "Rank Owner Job Files";
static const char *head1 = "Total Size\n";
static void alarmhandler(int _signo);
+static void filtered_write(char *_obuffer, int _wlen, FILE *_wstream);
static void warn(const struct printer *_pp);
/*
@@ -254,12 +262,105 @@ displayq(struct printer *pp, int format)
if (write(fd, line, i) != i)
fatal(pp, "Lost connection");
while ((i = read(fd, line, sizeof(line))) > 0)
- (void) fwrite(line, 1, i, stdout);
+ filtered_write(line, i, stdout);
+ filtered_write(NULL, -1, stdout);
(void) close(fd);
}
}
/*
+ * The lpq-info read from remote hosts may contain unprintable characters,
+ * or carriage-returns instead of line-feeds. Clean those up before echoing
+ * the lpq-info line(s) to stdout. The info may also be missing any kind of
+ * end-of-line character. This also turns CRLF and LFCR into a plain LF.
+ *
+ * This routine may be called multiple times to process a single set of
+ * information, and after a set is finished this routine must be called
+ * one extra time with NULL specified as the buffer address.
+ */
+static void
+filtered_write(char *wbuffer, int wlen, FILE *wstream)
+{
+ static char lastchar, savedchar;
+ char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end;
+ int destlen;
+ char destbuf[BUFSIZ];
+
+ if (wbuffer == NULL) {
+ if (savedchar != '\0') {
+ if (savedchar == '\r')
+ savedchar = '\n';
+ fputc(savedchar, wstream);
+ lastchar = savedchar;
+ savedchar = '\0';
+ }
+ if (lastchar != '\0' && lastchar != '\n')
+ fputc('\n', wstream);
+ lastchar = '\0';
+ return;
+ }
+
+ dest_ch = &destbuf[0];
+ dest_end = dest_ch + sizeof(destbuf);
+ chkptr = wbuffer;
+ w_end = wbuffer + wlen;
+ lastchar = '\0';
+ if (savedchar != '\0') {
+ chkptr = &savedchar;
+ nxtptr = wbuffer;
+ } else
+ nxtptr = chkptr + 1;
+
+ while (chkptr < w_end) {
+ if (nxtptr < w_end) {
+ if ((*chkptr == '\r' && *nxtptr == '\n') ||
+ (*chkptr == '\n' && *nxtptr == '\r')) {
+ *dest_ch++ = '\n';
+ /* want to skip past that second character */
+ nxtptr++;
+ goto check_next;
+ }
+ } else {
+ /* This is the last byte in the buffer given on this
+ * call, so check if it could be the first-byte of a
+ * significant two-byte sequence. If it is, then
+ * don't write it out now, but save for checking in
+ * the next call.
+ */
+ savedchar = '\0';
+ if (*chkptr == '\r' || *chkptr == '\n') {
+ savedchar = *chkptr;
+ break;
+ }
+ }
+ if (*chkptr == '\r')
+ *dest_ch++ = '\n';
+#if 0 /* XXX - don't translate unprintable characters (yet) */
+ else if (*chkptr != '\t' && *chkptr != '\n' &&
+ !isprintch(*chkptr))
+ *dest_ch++ = '?';
+#endif
+ else
+ *dest_ch++ = *chkptr;
+
+check_next:
+ chkptr = nxtptr;
+ nxtptr = chkptr + 1;
+ if (dest_ch >= dest_end) {
+ destlen = dest_ch - &destbuf[0];
+ fwrite(destbuf, 1, destlen, wstream);
+ lastchar = destbuf[destlen - 1];
+ dest_ch = &destbuf[0];
+ }
+ }
+ destlen = dest_ch - &destbuf[0];
+ if (destlen > 0) {
+ fwrite(destbuf, 1, destlen, wstream);
+ lastchar = destbuf[destlen - 1];
+ }
+}
+
+/*
* Print a warning message if there is no daemon present.
*/
static void
OpenPOWER on IntegriCloud