1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: lpd-query.c 155 2006-04-26 02:34:54Z ktou $ */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #define	__EXTENSIONS__	/* for strtok_r() */
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/fcntl.h>
39 #include <time.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <stdarg.h>
43 
44 #include <papi_impl.h>
45 
46 static void
47 parse_lpd_job_entry(service_t *svc, int fd, job_t **job)
48 {
49 	char *iter = NULL;
50 	char line[128];
51 	papi_attribute_t **attributes = NULL;
52 	char *p;
53 	int octets = 0;
54 
55 	*job = NULL;
56 
57 	if (fdgets(line, sizeof (line), fd) == NULL)
58 		return;
59 	/*
60 	 * 1st line...
61 	 *	 user: rank			[job (ID)(host)]\n
62 	 */
63 	if ((p = strtok_r(line, ": ", &iter)) == NULL)	 /* user: ... */
64 		return; /* invalid format */
65 	papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
66 				"job-originating-user-name", p);
67 
68 	p = strtok_r(NULL, "\t ", &iter);	/* ...rank... */
69 	papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
70 				"number-of-intervening-jobs", atoi(p) - 1);
71 	p = strtok_r(NULL, " ", &iter);		/* ...[job ... */
72 	if ((p = strtok_r(NULL, "]\n", &iter)) == NULL)	/* ...(id)(hostname)] */
73 		return;
74 	while (isspace(*p)) p++;
75 	papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
76 				"job-id", atoi(p));
77 	while (isdigit(*(++p)));
78 	while (isspace(*p)) p++;
79 	papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
80 				"job-originating-host-name", p);
81 
82 	/*
83 	 * rest-o-lines
84 	 *	[(num) copies of ]file			size bytes\n
85 	 */
86 	while ((fdgets(line, sizeof (line), fd) != NULL) && (line[0] != '\n')) {
87 		int copies, size;
88 		char *q;
89 
90 		/* find the number of copies */
91 		if ((p = strstr(line, "copies of")) != NULL) {
92 			copies = atoi(line);
93 			p += 9;
94 		} else {
95 			copies = 1;
96 			p = line;
97 		}
98 		papiAttributeListAddInteger(&attributes, PAPI_ATTR_EXCL,
99 				"copies", copies);
100 
101 		/* eat the leading whitespace */
102 		while (isspace(*p) != 0)
103 			p++;
104 		if ((q = strstr(p, " bytes\n")) != NULL) {
105 			/* back up to the beginning of the size */
106 			do { q--; } while (isdigit(*q) != 0);
107 
108 			/* seperate the name and size */
109 			*q = '\0';
110 			q++;
111 
112 			size = atoi(q);
113 
114 			papiAttributeListAddString(&attributes,
115 				PAPI_ATTR_APPEND, "job-name", p);
116 			papiAttributeListAddString(&attributes,
117 				PAPI_ATTR_APPEND, "job-file-names", p);
118 			papiAttributeListAddInteger(&attributes,
119 				PAPI_ATTR_APPEND, "job-file-sizes", size);
120 
121 			octets += (size * copies);
122 		}
123 	}
124 
125 	papiAttributeListAddInteger(&attributes, PAPI_ATTR_APPEND,
126 			"job-k-octets", octets/1024);
127 	papiAttributeListAddInteger(&attributes, PAPI_ATTR_APPEND,
128 			"job-octets", octets);
129 	papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
130 			"printer-name", queue_name_from_uri(svc->uri));
131 
132 	if ((*job = (job_t *)calloc(1, sizeof (**job))) != NULL)
133 		(*job)->attributes = attributes;
134 }
135 
136 static void
137 parse_lpd_job_entries(service_t *svc, int fd)
138 {
139 	job_t *job = NULL;
140 
141 	do {
142 		parse_lpd_job_entry(svc, fd, &job);
143 		list_append(&svc->cache->jobs, job);
144 	} while (job != NULL);
145 
146 }
147 
148 
149 void
150 parse_lpd_query(service_t *svc, int fd)
151 {
152 	papi_attribute_t **attributes = NULL;
153 	cache_t *cache = NULL;
154 	int state = 0x03; /* idle */
155 	char line[128];
156 	char buf[1024];
157 
158 	/* get the status line */
159 	if (fdgets(line, sizeof (line), fd) == NULL)
160 		return;	/* this should not happen. */
161 
162 	papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
163 			"printer-name", queue_name_from_uri(svc->uri));
164 
165 	if (uri_to_string(svc->uri, buf, sizeof (buf)) == 0)
166 		papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
167 				"printer-uri-supported", buf);
168 
169 	papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
170 			"printer-state-reasons", line);
171 
172 	if (strstr(line, "ready and printing") != NULL)
173 		state = 0x04; /* processing */
174 	else if ((strstr(line, "no entries") != NULL) ||
175 		 (strstr(line, "is ready") != NULL))
176 		state = 0x03; /* idle */
177 	else
178 		state = 0x05; /* stopped */
179 
180 	papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
181 			"printer-state", state);
182 
183 	if ((cache = (cache_t *)calloc(1, sizeof (*cache))) == NULL)
184 		return;
185 
186 	if ((cache->printer = (printer_t *)calloc(1, sizeof (*cache->printer)))
187 				== NULL)
188 		return;
189 
190 	cache->printer->attributes = attributes;
191 	svc->cache = cache;
192 
193 	if (fdgets(line, sizeof (line), fd) != NULL) {
194 		/* get the jobs */
195 		parse_lpd_job_entries(svc, fd);
196 	}
197 
198 	time(&cache->timestamp);
199 }
200 
201 void
202 cache_update(service_t *svc)
203 {
204 	int fd;
205 
206 	if (svc->cache != NULL)	/* this should be time based */
207 		return;
208 
209 	if (svc == NULL)
210 		return;
211 
212 	if ((fd = lpd_open(svc, 'q', NULL, 3)) < 0)
213 		return;
214 
215 	parse_lpd_query(svc, fd);
216 
217 	close(fd);
218 }
219 
220 papi_status_t
221 lpd_find_printer_info(service_t *svc, printer_t **printer)
222 {
223 	papi_status_t result = PAPI_BAD_ARGUMENT;
224 
225 	if ((svc == NULL) || (printer == NULL))
226 		return (PAPI_BAD_ARGUMENT);
227 
228 	cache_update(svc);
229 
230 	if (svc->cache != NULL) {
231 		*printer = svc->cache->printer;
232 		result = PAPI_OK;
233 	} else
234 		result = PAPI_NOT_FOUND;
235 
236 	return (result);
237 }
238 
239 papi_status_t
240 lpd_find_jobs_info(service_t *svc, job_t ***jobs)
241 {
242 	papi_status_t result = PAPI_BAD_ARGUMENT;
243 
244 	if (svc != NULL) {
245 		cache_update(svc);
246 
247 		if (svc->cache != NULL) {
248 			*jobs = svc->cache->jobs;
249 			result = PAPI_OK;
250 		}
251 	}
252 
253 	return (result);
254 }
255 
256 papi_status_t
257 lpd_find_job_info(service_t *svc, int job_id, job_t **job)
258 {
259 	papi_status_t result = PAPI_BAD_ARGUMENT;
260 	job_t **jobs;
261 
262 	if (lpd_find_jobs_info(svc, &jobs) != PAPI_OK) {
263 		int i;
264 
265 		*job = NULL;
266 		for (i = 0; ((*job == NULL) && (jobs[i] != NULL)); i++) {
267 			int id = -1;
268 
269 			papiAttributeListGetInteger(jobs[i]->attributes, NULL,
270 					"job-id", &id);
271 			if (id == job_id)
272 				*job = jobs[i];
273 		}
274 
275 		if (*job != NULL)
276 			result = PAPI_OK;
277 	}
278 
279 	return (result);
280 }
281 
282 void
283 cache_free(cache_t *item)
284 {
285 	if (item != NULL) {
286 		if (item->printer != NULL)
287 			papiPrinterFree((papi_printer_t *)item->printer);
288 		if (item->jobs != NULL)
289 			papiJobListFree((papi_job_t *)item->jobs);
290 		free(item);
291 	}
292 }
293