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