1 /*
2  * Status buffer routines for the CUPS scheduler.
3  *
4  * Copyright 2007-2014 by Apple Inc.
5  * Copyright 1997-2006 by Easy Software Products, all rights reserved.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8  */
9 
10 /*
11  * Include necessary headers...
12  */
13 
14 #include "cupsd.h"
15 #include <stdarg.h>
16 
17 
18 /*
19  * 'cupsdStatBufDelete()' - Destroy a status buffer.
20  */
21 
22 void
cupsdStatBufDelete(cupsd_statbuf_t * sb)23 cupsdStatBufDelete(cupsd_statbuf_t *sb)	/* I - Status buffer */
24 {
25  /*
26   * Range check input...
27   */
28 
29   if (!sb)
30     return;
31 
32  /*
33   * Close the status pipe and free memory used...
34   */
35 
36   close(sb->fd);
37 
38   free(sb);
39 }
40 
41 
42 /*
43  * 'cupsdStatBufNew()' - Create a new status buffer.
44  */
45 
46 cupsd_statbuf_t	*			/* O - New status buffer */
cupsdStatBufNew(int fd,const char * prefix,...)47 cupsdStatBufNew(int        fd,		/* I - File descriptor of pipe */
48                 const char *prefix,	/* I - Printf-style prefix string */
49 		...)			/* I - Additional args as needed */
50 {
51   cupsd_statbuf_t	*sb;		/* New status buffer */
52   va_list		ap;		/* Argument list */
53 
54 
55  /*
56   * Range check input...
57   */
58 
59   if (fd < 0)
60     return (NULL);
61 
62  /*
63   * Allocate the status buffer...
64   */
65 
66   if ((sb = calloc(1, sizeof(cupsd_statbuf_t))) != NULL)
67   {
68    /*
69     * Assign the file descriptor...
70     */
71 
72     sb->fd = fd;
73 
74    /*
75     * Format the prefix string, if any.  This is usually "[Job 123]"
76     * or "[Sub 123]", and so forth.
77     */
78 
79     if (prefix)
80     {
81      /*
82       * Printf-style prefix string...
83       */
84 
85       va_start(ap, prefix);
86       vsnprintf(sb->prefix, sizeof(sb->prefix), prefix, ap);
87       va_end(ap);
88     }
89     else
90     {
91      /*
92       * No prefix string...
93       */
94 
95       sb->prefix[0] = '\0';
96     }
97   }
98 
99   return (sb);
100 }
101 
102 
103 /*
104  * 'cupsdStatBufUpdate()' - Update the status buffer.
105  */
106 
107 char *					/* O - Line from buffer, "", or NULL */
cupsdStatBufUpdate(cupsd_statbuf_t * sb,int * loglevel,char * line,int linelen)108 cupsdStatBufUpdate(
109     cupsd_statbuf_t *sb,		/* I - Status buffer */
110     int             *loglevel,		/* O - Log level */
111     char            *line,		/* I - Line buffer */
112     int             linelen)		/* I - Size of line buffer */
113 {
114   int		bytes;			/* Number of bytes read */
115   char		*lineptr,		/* Pointer to end of line in buffer */
116 		*message;		/* Pointer to message text */
117 
118 
119  /*
120   * Check if the buffer already contains a full line...
121   */
122 
123   if ((lineptr = strchr(sb->buffer, '\n')) == NULL)
124   {
125    /*
126     * No, read more data...
127     */
128 
129     if ((bytes = read(sb->fd, sb->buffer + sb->bufused, (size_t)(CUPSD_SB_BUFFER_SIZE - sb->bufused - 1))) > 0)
130     {
131       sb->bufused += bytes;
132       sb->buffer[sb->bufused] = '\0';
133 
134      /*
135       * Guard against a line longer than the max buffer size...
136       */
137 
138       if ((lineptr = strchr(sb->buffer, '\n')) == NULL &&
139           sb->bufused == (CUPSD_SB_BUFFER_SIZE - 1))
140 	lineptr = sb->buffer + sb->bufused;
141     }
142     else if (bytes < 0 && errno == EINTR)
143     {
144      /*
145       * Return an empty line if we are interrupted...
146       */
147 
148       *loglevel = CUPSD_LOG_NONE;
149       line[0]   = '\0';
150 
151       return (line);
152     }
153     else
154     {
155      /*
156       * End-of-file, so use the whole buffer...
157       */
158 
159       lineptr  = sb->buffer + sb->bufused;
160       *lineptr = '\0';
161     }
162 
163    /*
164     * Final check for end-of-file...
165     */
166 
167     if (sb->bufused == 0 && bytes == 0)
168       lineptr = NULL;
169   }
170 
171   if (!lineptr)
172   {
173    /*
174     * End of file...
175     */
176 
177     *loglevel = CUPSD_LOG_NONE;
178     line[0]   = '\0';
179 
180     return (NULL);
181   }
182 
183  /*
184   * Terminate the line and process it...
185   */
186 
187   *lineptr++ = '\0';
188 
189  /*
190   * Figure out the logging level...
191   */
192 
193   if (!strncmp(sb->buffer, "EMERG:", 6))
194   {
195     *loglevel = CUPSD_LOG_EMERG;
196     message   = sb->buffer + 6;
197   }
198   else if (!strncmp(sb->buffer, "ALERT:", 6))
199   {
200     *loglevel = CUPSD_LOG_ALERT;
201     message   = sb->buffer + 6;
202   }
203   else if (!strncmp(sb->buffer, "CRIT:", 5))
204   {
205     *loglevel = CUPSD_LOG_CRIT;
206     message   = sb->buffer + 5;
207   }
208   else if (!strncmp(sb->buffer, "ERROR:", 6))
209   {
210     *loglevel = CUPSD_LOG_ERROR;
211     message   = sb->buffer + 6;
212   }
213   else if (!strncmp(sb->buffer, "WARNING:", 8))
214   {
215     *loglevel = CUPSD_LOG_WARN;
216     message   = sb->buffer + 8;
217   }
218   else if (!strncmp(sb->buffer, "NOTICE:", 7))
219   {
220     *loglevel = CUPSD_LOG_NOTICE;
221     message   = sb->buffer + 7;
222   }
223   else if (!strncmp(sb->buffer, "INFO:", 5))
224   {
225     *loglevel = CUPSD_LOG_INFO;
226     message   = sb->buffer + 5;
227   }
228   else if (!strncmp(sb->buffer, "DEBUG:", 6))
229   {
230     *loglevel = CUPSD_LOG_DEBUG;
231     message   = sb->buffer + 6;
232   }
233   else if (!strncmp(sb->buffer, "DEBUG2:", 7))
234   {
235     *loglevel = CUPSD_LOG_DEBUG2;
236     message   = sb->buffer + 7;
237   }
238   else if (!strncmp(sb->buffer, "PAGE:", 5))
239   {
240     *loglevel = CUPSD_LOG_PAGE;
241     message   = sb->buffer + 5;
242   }
243   else if (!strncmp(sb->buffer, "STATE:", 6))
244   {
245     *loglevel = CUPSD_LOG_STATE;
246     message   = sb->buffer + 6;
247   }
248   else if (!strncmp(sb->buffer, "JOBSTATE:", 9))
249   {
250     *loglevel = CUPSD_LOG_JOBSTATE;
251     message   = sb->buffer + 9;
252   }
253   else if (!strncmp(sb->buffer, "ATTR:", 5))
254   {
255     *loglevel = CUPSD_LOG_ATTR;
256     message   = sb->buffer + 5;
257   }
258   else if (!strncmp(sb->buffer, "PPD:", 4))
259   {
260     *loglevel = CUPSD_LOG_PPD;
261     message   = sb->buffer + 4;
262   }
263   else
264   {
265     *loglevel = CUPSD_LOG_DEBUG;
266     message   = sb->buffer;
267   }
268 
269  /*
270   * Skip leading whitespace in the message...
271   */
272 
273   while (isspace(*message & 255))
274     message ++;
275 
276  /*
277   * Send it to the log file as needed...
278   */
279 
280   if (sb->prefix[0])
281   {
282     if (*loglevel > CUPSD_LOG_NONE &&
283 	(*loglevel != CUPSD_LOG_INFO || LogLevel >= CUPSD_LOG_DEBUG))
284     {
285      /*
286       * General status message; send it to the error_log file...
287       */
288 
289       if (message[0] == '[')
290 	cupsdLogMessage(*loglevel, "%s", message);
291       else
292 	cupsdLogMessage(*loglevel, "%s %s", sb->prefix, message);
293     }
294     else if (*loglevel < CUPSD_LOG_NONE && LogLevel >= CUPSD_LOG_DEBUG)
295       cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s %s", sb->prefix, sb->buffer);
296   }
297 
298  /*
299   * Copy the message to the line buffer...
300   */
301 
302   strlcpy(line, message, (size_t)linelen);
303 
304  /*
305   * Copy over the buffer data we've used up...
306   */
307 
308   if (lineptr < sb->buffer + sb->bufused)
309     _cups_strcpy(sb->buffer, lineptr);
310 
311   sb->bufused -= lineptr - sb->buffer;
312 
313   if (sb->bufused < 0)
314     sb->bufused = 0;
315 
316   return (line);
317 }
318