Libinfo-129.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_printer.c
1 /*
2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Printer lookup
26 * Copyright (C) 1989 by NeXT, Inc.
27 */
28 #include <stdlib.h>
29 #include <mach/mach.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <rpc/types.h>
33 #include <rpc/xdr.h>
34 #include <pthread.h>
35
36 #include "_lu_types.h"
37 #include "lookup.h"
38 #include "printerdb.h"
39 #include "lu_utils.h"
40
41 static pthread_mutex_t _printer_lock = PTHREAD_MUTEX_INITIALIZER;
42
43 #define P_GET_NAME 1
44 #define P_GET_ENT 2
45
46 extern prdb_ent *_old_prdb_get();
47 extern prdb_ent *_old_prdb_getbyname();
48 extern void _old_prdb_set();
49 extern void _old_prdb_end();
50
51 static void
52 free_printer_data(prdb_ent *p)
53 {
54 char **names;
55 int i;
56
57 if (p == NULL) return;
58
59 names = p->pe_name;
60 if (names != NULL)
61 {
62 while (*names) free(*names++);
63 free(p->pe_name);
64 }
65
66 for (i = 0; i < p->pe_nprops; i++)
67 {
68 free(p->pe_prop[i].pp_key);
69 free(p->pe_prop[i].pp_value);
70 }
71
72 free(p->pe_prop);
73 }
74
75 static void
76 free_printer(prdb_ent *p)
77 {
78 if (p == NULL) return;
79 free_printer_data(p);
80 free(p);
81 }
82
83 static void
84 free_lu_thread_info_printer(void *x)
85 {
86 struct lu_thread_info *tdata;
87
88 if (x == NULL) return;
89
90 tdata = (struct lu_thread_info *)x;
91
92 if (tdata->lu_entry != NULL)
93 {
94 free_printer((prdb_ent *)tdata->lu_entry);
95 tdata->lu_entry = NULL;
96 }
97
98 _lu_data_free_vm_xdr(tdata);
99
100 free(tdata);
101 }
102
103 static prdb_ent *
104 extract_printer(XDR *xdr)
105 {
106 prdb_ent *p;
107 int i, j, nvals, nkeys, status;
108 char *key, **vals;
109
110 if (xdr == NULL) return NULL;
111
112 if (!xdr_int(xdr, &nkeys)) return NULL;
113
114 p = (prdb_ent *)calloc(1, sizeof(prdb_ent));
115
116 for (i = 0; i < nkeys; i++)
117 {
118 key = NULL;
119 vals = NULL;
120 nvals = 0;
121
122 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
123 if (status < 0)
124 {
125 free_printer(p);
126 return NULL;
127 }
128
129 j = 0;
130
131 if ((p->pe_name == NULL) && (!strcmp("name", key)))
132 {
133 free(key);
134 p->pe_name = vals;
135 j = nvals;
136 vals = NULL;
137 }
138 else
139 {
140 if (p->pe_nprops == 0)
141 {
142 p->pe_prop = (prdb_property *)calloc(1, sizeof(prdb_property));
143 }
144 else
145 {
146 p->pe_prop = (prdb_property *)realloc(p->pe_prop, (p->pe_nprops + 1) * sizeof(prdb_property));
147 }
148 p->pe_prop[p->pe_nprops].pp_key = key;
149 p->pe_prop[p->pe_nprops].pp_value = NULL;
150 if (nvals > 0)
151 {
152 p->pe_prop[p->pe_nprops].pp_value = vals[0];
153 j = 1;
154 }
155 else
156 {
157 p->pe_prop[p->pe_nprops].pp_value = strdup("");
158 }
159 p->pe_nprops++;
160 }
161
162 if (vals != NULL)
163 {
164 for (; j < nvals; j++) free(vals[j]);
165 free(vals);
166 }
167 }
168
169 if (p->pe_name == NULL) p->pe_name = (char **)calloc(1, sizeof(char *));
170 if (p->pe_prop == NULL) p->pe_prop = (prdb_property *)calloc(1, sizeof(prdb_property));
171
172 return p;
173 }
174
175 static prdb_ent *
176 copy_printer(prdb_ent *in)
177 {
178 int i;
179 prdb_ent *p;
180
181 if (in == NULL) return NULL;
182
183 p = (prdb_ent *)calloc(1, sizeof(prdb_ent));
184
185 if (in->pe_name != NULL)
186 {
187 for (i = 0; in->pe_name[i] != NULL; i++);
188 p->pe_name = (char **)calloc(i, sizeof(char *));
189 for (i = 0; p->pe_name[i] != NULL; i++) p->pe_name[i] = strdup(in->pe_name[i]);
190 }
191 else
192 {
193 p->pe_name = (char **)calloc(1, sizeof(char *));
194 }
195
196 if (in->pe_nprops > 0)
197 {
198 p->pe_prop = (struct prdb_property *)calloc(in->pe_nprops, sizeof(struct prdb_property));
199
200 for (i = 0; in->pe_nprops; i++)
201 {
202 p->pe_prop[i].pp_key = strdup(in->pe_prop[i].pp_key);
203 p->pe_prop[i].pp_value = NULL;
204 if (in->pe_prop[i].pp_value != NULL) p->pe_prop[i].pp_value = strdup(in->pe_prop[i].pp_value);
205 }
206 }
207 else
208 {
209 p->pe_prop = (prdb_property *)calloc(1, sizeof(prdb_property));
210 }
211
212 return p;
213 }
214
215 static void
216 recycle_printer(struct lu_thread_info *tdata, struct prdb_ent *in)
217 {
218 struct prdb_ent *p;
219
220 if (tdata == NULL) return;
221 p = (struct prdb_ent *)tdata->lu_entry;
222
223 if (in == NULL)
224 {
225 free_printer(p);
226 tdata->lu_entry = NULL;
227 }
228
229 if (tdata->lu_entry == NULL)
230 {
231 tdata->lu_entry = in;
232 return;
233 }
234
235 free_printer_data(p);
236
237 p->pe_name = in->pe_name;
238 p->pe_nprops = in->pe_nprops;
239 p->pe_prop = in->pe_prop;
240
241 free(in);
242 }
243
244 static prdb_ent *
245 lu_prdb_getbyname(const char *name)
246 {
247 prdb_ent *p;
248 unsigned datalen;
249 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
250 XDR outxdr;
251 XDR inxdr;
252 static int proc = -1;
253 char *lookup_buf;
254 int count;
255
256 if (proc < 0)
257 {
258 if (_lookup_link(_lu_port, "prdb_getbyname", &proc) != KERN_SUCCESS)
259 {
260 return NULL;
261 }
262 }
263
264 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
265 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
266 {
267 xdr_destroy(&outxdr);
268 return NULL;
269 }
270
271 datalen = 0;
272 lookup_buf = NULL;
273
274 if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
275 {
276 xdr_destroy(&outxdr);
277 return NULL;
278 }
279
280 xdr_destroy(&outxdr);
281
282 datalen *= BYTES_PER_XDR_UNIT;
283 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
284
285 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
286
287 count = 0;
288 if (!xdr_int(&inxdr, &count))
289 {
290 xdr_destroy(&inxdr);
291 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
292 return NULL;
293 }
294
295 if (count == 0)
296 {
297 xdr_destroy(&inxdr);
298 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
299 return NULL;
300 }
301
302 p = extract_printer(&inxdr);
303 xdr_destroy(&inxdr);
304 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
305
306 return p;
307 }
308
309 static void
310 lu_prdb_end()
311 {
312 struct lu_thread_info *tdata;
313
314 tdata = _lu_data_create_key(_lu_data_key_printer, free_lu_thread_info_printer);
315 _lu_data_free_vm_xdr(tdata);
316 }
317
318 static void
319 lu_prdb_set()
320 {
321 lu_prdb_end();
322 }
323
324 static prdb_ent *
325 lu_prdb_get()
326 {
327 prdb_ent *p;
328 static int proc = -1;
329 struct lu_thread_info *tdata;
330
331 tdata = _lu_data_create_key(_lu_data_key_printer, free_lu_thread_info_printer);
332 if (tdata == NULL)
333 {
334 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
335 _lu_data_set_key(_lu_data_key_printer, tdata);
336 }
337
338 if (tdata->lu_vm == NULL)
339 {
340 if (proc < 0)
341 {
342 if (_lookup_link(_lu_port, "prdb_get", &proc) != KERN_SUCCESS)
343 {
344 lu_prdb_end();
345 return NULL;
346 }
347 }
348
349 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
350 {
351 lu_prdb_end();
352 return NULL;
353 }
354
355 /* mig stubs measure size in words (4 bytes) */
356 tdata->lu_vm_length *= 4;
357
358 if (tdata->lu_xdr != NULL)
359 {
360 xdr_destroy(tdata->lu_xdr);
361 free(tdata->lu_xdr);
362 }
363 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
364
365 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
366 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
367 {
368 lu_prdb_end();
369 return NULL;
370 }
371 }
372
373 if (tdata->lu_vm_cursor == 0)
374 {
375 lu_prdb_end();
376 return NULL;
377 }
378
379 p = extract_printer(tdata->lu_xdr);
380 if (p == NULL)
381 {
382 lu_prdb_end();
383 return NULL;
384 }
385
386 tdata->lu_vm_cursor--;
387
388 return p;
389 }
390
391 static prdb_ent *
392 getprinter(const char *name, int source)
393 {
394 prdb_ent *res = NULL;
395 struct lu_thread_info *tdata;
396
397 tdata = _lu_data_create_key(_lu_data_key_printer, free_lu_thread_info_printer);
398 if (tdata == NULL)
399 {
400 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
401 _lu_data_set_key(_lu_data_key_printer, tdata);
402 }
403
404 if (_lu_running())
405 {
406 switch (source)
407 {
408 case P_GET_NAME:
409 res = lu_prdb_getbyname(name);
410 break;
411 case P_GET_ENT:
412 res = lu_prdb_get();
413 break;
414 default: res = NULL;
415 }
416 }
417 else
418 {
419 pthread_mutex_lock(&_printer_lock);
420 switch (source)
421 {
422 case P_GET_NAME:
423 res = copy_printer(_old_prdb_getbyname(name));
424 break;
425 case P_GET_ENT:
426 res = copy_printer(_old_prdb_get());
427 break;
428 default: res = NULL;
429 }
430 pthread_mutex_unlock(&_printer_lock);
431 }
432
433 recycle_printer(tdata, res);
434 return (prdb_ent *)tdata->lu_entry;
435 }
436
437 const prdb_ent *
438 prdb_getbyname(const char *name)
439 {
440 return (const prdb_ent *)getprinter(name, P_GET_NAME);
441 }
442
443 const prdb_ent *
444 prdb_get(void)
445 {
446 return (const prdb_ent *)getprinter(NULL, P_GET_ENT);
447 }
448
449 void
450 prdb_set(const char *name)
451 {
452 if (_lu_running()) lu_prdb_set();
453 else _old_prdb_set();
454 }
455
456 void
457 prdb_end(void)
458 {
459 if (_lu_running()) lu_prdb_end();
460 else _old_prdb_end();
461 }