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