1 /***************************************************************************
2 * LPRng - An Extended Print Spooler System
3 *
4 * Copyright 1988-2003, Patrick Powell, San Diego, CA
5 * papowell@lprng.com
6 * See LICENSE for conditions of use.
7 *
8 ***************************************************************************/
9
10 #include "lp.h"
11 #include "errorcodes.h"
12 #include "globmatch.h"
13 #include "gethostinfo.h"
14 #include "child.h"
15 #include "fileopen.h"
16 #include "getqueue.h"
17 #include "getprinter.h"
18 #include "linelist.h"
19
20 /* Forward declartions: */
21 static int Find_last_key( struct line_list *l, const char *key, const char *sep, int *m );
22 static int Find_last_casekey( struct line_list *l, const char *key, const char *sep, int *m );
23 static int Find_first_casekey( struct line_list *l, const char *key, const char *sep, int *m );
24 static const char *Fix_val( const char *s );
25 static void Read_file_and_split( struct line_list *list, char *file,
26 const char *linesep, int sort, const char *keysep, int uniq,
27 int trim, int nocomment );
28 static void Find_pc_info( char *name, struct line_list *info,
29 struct line_list *aliases, struct line_list *names,
30 struct line_list *order, struct line_list *input,
31 int depth, int wildcard );
32 static void Config_value_conversion( struct keywords *key, const char *s );
33
34 /* lowercase and uppercase (destructive) a string */
lowercase(char * s)35 void lowercase( char *s )
36 {
37 int c;
38 if( s ){
39 for( ; (c = cval(s)); ++s ){
40 if( isupper(c) ) *s = tolower(c);
41 }
42 }
43 }
uppercase(char * s)44 void uppercase( char *s )
45 {
46 int c;
47 if( s ){
48 for( ; (c = cval(s)); ++s ){
49 if( islower(c) ) *s = toupper(c);
50 }
51 }
52 }
53
54 /*
55 * Trunc str - remove trailing white space (destructive)
56 */
57
trunc_str(char * s)58 char *trunc_str( char *s)
59 {
60 char *t;
61 if(s && *s){
62 for( t=s+safestrlen(s); t > s && isspace(cval(t-1)); --t );
63 *t = 0;
64 }
65 return( s );
66 }
67
Lastchar(char * s)68 static int Lastchar( char *s )
69 {
70 int c = 0;
71 if( s && *s ){
72 s += safestrlen(s)-1;
73 c = cval(s);
74 }
75 return(c);
76 }
77
78 /*
79 * Memory Allocation Routines
80 * - same as malloc, realloc, but with error messages
81 */
malloc_or_die(size_t size,const char * file,int line)82 void *malloc_or_die( size_t size, const char *file, int line )
83 {
84 void *p;
85 #if defined(DMALLOC)
86 p = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC,0,0);
87 #else
88 p = malloc(size);
89 #endif
90 if( p == 0 ){
91 logerr_die(LOG_INFO, "malloc of %d failed, file '%s', line %d",
92 (int)size, file, line );
93 }
94 DEBUG6("malloc_or_die: size %d, addr 0x%lx, file '%s', line %d",
95 (int)size, Cast_ptr_to_long(p), file, line );
96 return( p );
97 }
98
realloc_or_die(void * p,size_t size,const char * file,int line)99 void *realloc_or_die( void *p, size_t size, const char *file, int line )
100 {
101 void *orig = p;
102 if( p == 0 ){
103 p = malloc_or_die(size, file, line);
104 } else {
105 #if defined(DMALLOC)
106 p = dmalloc_realloc(file, line, p, size, DMALLOC_FUNC_REALLOC,0);
107 #else
108 p = realloc(p, size);
109 #endif
110 }
111 if( p == 0 ){
112 logerr(LOG_INFO, "realloc of 0x%lx, new size %d failed, file '%s', line %d",
113 Cast_ptr_to_long(orig), (int)size, file, line );
114 abort();
115 }
116 DEBUG6("realloc_or_die: size %d, orig 0x%lx, addr 0x%lx, file '%s', line %d",
117 (int)size, Cast_ptr_to_long(orig), Cast_ptr_to_long(p), file, line );
118 return( p );
119 }
120
121 /*
122 * duplicate a string safely, generate an error message
123 */
124
safestrdup(const char * p,const char * file,int line)125 char *safestrdup (const char *p, const char *file, int line)
126 {
127 char *new = 0;
128
129 if( p == 0) p = "";
130 new = malloc_or_die( safestrlen (p) + 1, file, line );
131 strcpy( new, p );
132 return( new );
133 }
134
135 /*
136 * char *safestrdup2( char *s1, char *s2, char *file, int line )
137 * duplicate two concatenated strings
138 * returns: malloced string area
139 */
140
safestrdup2(const char * s1,const char * s2,const char * file,int line)141 char *safestrdup2( const char *s1, const char *s2, const char *file, int line )
142 {
143 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0);
144 char *s = malloc_or_die( n, file, line );
145 s[0] = 0;
146 if( s1 ) strcat(s,s1);
147 if( s2 ) strcat(s,s2);
148 return( s );
149 }
150
151 /*
152 * char *safeextend2( char *s1, char *s2, char *file, int line )
153 * extends a malloc'd string
154 * returns: malloced string area
155 */
156
safeextend2(char * s1,const char * s2,const char * file,int line)157 char *safeextend2( char *s1, const char *s2, const char *file, int line )
158 {
159 char *s;
160 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0);
161 s = realloc_or_die( s1, n, file, line );
162 if( s1 == 0 ) *s = 0;
163 if( s2 ) strcat(s,s2);
164 return(s);
165 }
166
167 /*
168 * char *safestrdup3( char *s1, char *s2, char *s3, char *file, int line )
169 * duplicate three concatenated strings
170 * returns: malloced string area
171 */
172
safestrdup3(const char * s1,const char * s2,const char * s3,const char * file,int line)173 char *safestrdup3( const char *s1, const char *s2, const char *s3,
174 const char *file, int line )
175 {
176 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0) + (s3?safestrlen(s3):0);
177 char *s = malloc_or_die( n, file, line );
178 s[0] = 0;
179 if( s1 ) strcat(s,s1);
180 if( s2 ) strcat(s,s2);
181 if( s3 ) strcat(s,s3);
182 return( s );
183 }
184
185
186 /*
187 * char *safeextend3( char *s1, char *s2, char *s3 char *file, int line )
188 * extends a malloc'd string
189 * returns: malloced string area
190 */
191
safeextend3(char * s1,const char * s2,const char * s3,const char * file,int line)192 char *safeextend3( char *s1, const char *s2, const char *s3,
193 const char *file, int line )
194 {
195 char *s;
196 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0) + (s3?safestrlen(s3):0);
197 s = realloc_or_die( s1, n, file, line );
198 if( s1 == 0 ) *s = 0;
199 if( s2 ) strcat(s,s2);
200 if( s3 ) strcat(s,s3);
201 return(s);
202 }
203
204
205
206 /*
207 * char *safeextend4( char *s1, char *s2, char *s3, char *s4,
208 * char *file, int line )
209 * extends a malloc'd string
210 * returns: malloced string area
211 */
212
safeextend4(char * s1,const char * s2,const char * s3,const char * s4,const char * file,int line)213 char *safeextend4( char *s1, const char *s2, const char *s3, const char *s4,
214 const char *file, int line )
215 {
216 char *s;
217 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0)
218 + (s3?safestrlen(s3):0) + (s4?safestrlen(s4):0);
219 s = realloc_or_die( s1, n, file, line );
220 if( s1 == 0 ) *s = 0;
221 if( s2 ) strcat(s,s2);
222 if( s3 ) strcat(s,s3);
223 if( s4 ) strcat(s,s4);
224 return(s);
225 }
226
227 /*
228 * char *safestrdup4
229 * duplicate four concatenated strings
230 * returns: malloced string area
231 */
232
safestrdup4(const char * s1,const char * s2,const char * s3,const char * s4,const char * file,int line)233 char *safestrdup4( const char *s1, const char *s2,
234 const char *s3, const char *s4,
235 const char *file, int line )
236 {
237 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0)
238 + (s3?safestrlen(s3):0) + (s4?safestrlen(s4):0);
239 char *s = malloc_or_die( n, file, line );
240 s[0] = 0;
241 if( s1 ) strcat(s,s1);
242 if( s2 ) strcat(s,s2);
243 if( s3 ) strcat(s,s3);
244 if( s4 ) strcat(s,s4);
245 return( s );
246 }
247
248
249
250 /*
251 * char *safeextend5( char *s1, char *s2, char *s3, char *s4, char *s5
252 * char *file, int line )
253 * extends a malloc'd string
254 * returns: malloced string area
255 */
256
safeextend5(char * s1,const char * s2,const char * s3,const char * s4,const char * s5,const char * file,int line)257 char *safeextend5( char *s1, const char *s2, const char *s3, const char *s4, const char *s5,
258 const char *file, int line )
259 {
260 char *s;
261 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0)
262 + (s3?safestrlen(s3):0) + (s4?safestrlen(s4):0) + (s5?safestrlen(s5):0);
263 s = realloc_or_die( s1, n, file, line );
264 if( s1 == 0 ) *s = 0;
265 if( s2 ) strcat(s,s2);
266 if( s3 ) strcat(s,s3);
267 if( s4 ) strcat(s,s4);
268 if( s5 ) strcat(s,s5);
269 return(s);
270 }
271
272
273 /*
274 * char *safestrdup5
275 * duplicate five concatenated strings
276 * returns: malloced string area
277 */
278
safestrdup5(const char * s1,const char * s2,const char * s3,const char * s4,const char * s5,const char * file,int line)279 char *safestrdup5( const char *s1, const char *s2,
280 const char *s3, const char *s4, const char *s5,
281 const char *file, int line )
282 {
283 int n = 1 + (s1?safestrlen(s1):0) + (s2?safestrlen(s2):0)
284 + (s3?safestrlen(s3):0) + (s4?safestrlen(s4):0) + (s5?safestrlen(s5):0);
285 char *s = malloc_or_die( n, file, line );
286 s[0] = 0;
287 if( s1 ) strcat(s,s1);
288 if( s2 ) strcat(s,s2);
289 if( s3 ) strcat(s,s3);
290 if( s4 ) strcat(s,s4);
291 if( s5 ) strcat(s,s5);
292 return( s );
293 }
294
295 /*
296 Line Splitting and List Management
297
298 Model: we have a list of malloced and duplicated lines
299 we never remove the lines unless we free them.
300 we never put them in unless we malloc them
301 */
302
303 /*
304 * void Init_line_list( struct line_list *l )
305 * - inititialize a list by zeroing it
306 */
307
Init_line_list(struct line_list * l)308 void Init_line_list( struct line_list *l )
309 {
310 memset(l, 0, sizeof(l[0]));
311 }
312
313 /*
314 * void Free_line_list( struct line_list *l )
315 * - clear a list by freeing the allocated array
316 */
317
Free_line_list(struct line_list * l)318 void Free_line_list( struct line_list *l )
319 {
320 int i;
321 if( l == 0 ) return;
322 if( l->list ){
323 for( i = 0; i < l->count; ++i ){
324 if( l->list[i] ) free( l->list[i]); l->list[i] = 0;
325 }
326 free(l->list);
327 }
328 memset(l,0,sizeof(l[0]));
329 }
330
Free_listof_line_list(struct line_list * l)331 void Free_listof_line_list( struct line_list *l )
332 {
333 int i;
334 struct line_list *lp;
335 if( l == 0 ) return;
336 for( i = 0; i < l->count; ++i ){
337 lp = (void *)l->list[i];
338 Free_line_list(lp);
339 memset( lp, 0, sizeof(lp[0]) );
340 }
341 Free_line_list(l);
342 }
343
344 /*
345 * void Check_max( struct line_list *l, int incr )
346 *
347 */
348
Check_max(struct line_list * l,int incr)349 void Check_max( struct line_list *l, int incr )
350 {
351 if( l->count+incr >= l->max ){
352 l->max += 100+incr;
353 if( !(l->list = realloc_or_die( l->list, l->max*sizeof(char *),
354 __FILE__,__LINE__)) ){
355 Errorcode = JFAIL;
356 logerr(LOG_INFO, "Check_max: realloc %d failed",
357 (int)(l->max*sizeof(char*)) );
358 }
359 }
360 }
361
362 /*
363 *char *Add_line_list( struct line_list *l, char *str,
364 * char *sep, int sort, int uniq )
365 * - add a copy of str to the line list
366 * sep - key separator, used for sorting
367 * sort = 1 - sort the values
368 * uniq = 1 - only one value
369 * returns: added string
370 */
371
Add_line_list(struct line_list * l,const char * instr,const char * sep,int sort,int uniq)372 char *Add_line_list( struct line_list *l, const char *instr,
373 const char *sep, int sort, int uniq )
374 {
375 char *s = 0;
376 char *str;
377 int c = 0, cmp, mid;
378 if(DEBUGL5){
379 char b[48];
380 int n;
381 plp_snprintf( b,sizeof(b)-8, "%s",instr );
382 if( (n = safestrlen(b)) > (int)sizeof(b)-10 ) strcpy( b+n,"..." );
383 LOGDEBUG("Add_line_list: '%s', sep '%s', sort %d, uniq %d",
384 b, sep, sort, uniq );
385 }
386
387 Check_max(l, 2);
388 str = safestrdup( instr,__FILE__,__LINE__);
389 if( sort == 0 ){
390 l->list[l->count++] = str;
391 } else {
392 s = 0;
393 if( sep && (s = safestrpbrk( str, sep )) ){ c = *s; *s = 0; }
394 /* find everything <= the mid point */
395 /* cmp = key <> list[mid] */
396 cmp = Find_last_key( l, str, sep, &mid );
397 if( s ) *s = c;
398 /* str < list[mid+1] */
399 if( cmp == 0 && uniq ){
400 /* we replace */
401 free( l->list[mid] );
402 l->list[mid] = str;
403 } else if( cmp >= 0 ){
404 /* we need to insert after mid */
405 ++l->count;
406 memmove( l->list+mid+2, l->list+mid+1,
407 sizeof( char * ) * (l->count - mid - 1));
408 l->list[mid+1] = str;
409 } else if( cmp < 0 ) {
410 /* we need to insert before mid */
411 ++l->count;
412 memmove( l->list+mid+1, l->list+mid,
413 sizeof( char * ) * (l->count - mid));
414 l->list[mid] = str;
415 }
416 }
417 if(DEBUGL5)Dump_line_list("Add_line_list: result", l);
418 return( str );
419 }
420
421 /*
422 *void Add_casekey_line_list( struct line_list *l, char *str,
423 * char *sep )
424 * - add a copy of str to the line list, using case sensitive keys
425 * sep - key separator, used for sorting
426 * sort = 1 - sort the values
427 * uniq = 1 - only one value
428 */
429
Add_casekey_line_list(struct line_list * l,char * str,const char * sep)430 static void Add_casekey_line_list( struct line_list *l, char *str,
431 const char *sep)
432 {
433 char *s = 0;
434 int c = 0, cmp, mid;
435 if(DEBUGL5){
436 char b[40];
437 int n;
438 plp_snprintf( b,sizeof(b)-8, "%s",str );
439 if( (n = safestrlen(b)) > (int)sizeof(b)-10 ) strcpy( b+n,"..." );
440 LOGDEBUG("Add_casekey_line_list: '%s', sep '%s', sort 1, uniq 1",
441 b, sep );
442 }
443
444 Check_max(l, 2);
445 str = safestrdup( str,__FILE__,__LINE__);
446 s = 0;
447 if( sep && (s = safestrpbrk( str, sep )) ){ c = *s; *s = 0; }
448 /* find everything <= the mid point */
449 /* cmp = key <> list[mid] */
450 cmp = Find_last_casekey( l, str, sep, &mid );
451 if( s ) *s = c;
452 /* str < list[mid+1] */
453 if( cmp == 0 ){
454 /* we replace */
455 free( l->list[mid] );
456 l->list[mid] = str;
457 } else if( cmp >= 0 ){
458 /* we need to insert after mid */
459 ++l->count;
460 memmove( l->list+mid+2, l->list+mid+1,
461 sizeof( char * ) * (l->count - mid - 1));
462 l->list[mid+1] = str;
463 } else if( cmp < 0 ) {
464 /* we need to insert before mid */
465 ++l->count;
466 memmove( l->list+mid+1, l->list+mid,
467 sizeof( char * ) * (l->count - mid));
468 l->list[mid] = str;
469 }
470 /* if(DEBUGL4)Dump_line_list("Add_casekey_line_list: result", l); */
471 }
472
Merge_line_list(struct line_list * dest,struct line_list * src,const char * sep,int sort,int uniq)473 void Merge_line_list( struct line_list *dest, struct line_list *src,
474 const char *sep, int sort, int uniq )
475 {
476 int i;
477 for( i = 0; i < src->count; ++i ){
478 Add_line_list( dest, src->list[i], sep, sort, uniq );
479 }
480 }
481
Merge_listof_line_list(struct line_list * dest,struct line_list * src)482 void Merge_listof_line_list( struct line_list *dest, struct line_list *src)
483 {
484 struct line_list *sp, *dp;
485 int i;
486 for( i = 0; i < src->count; ++i ){
487 if( (sp = (void *)src->list[i]) ){
488 Check_max( dest, 1 );
489 dp = malloc_or_die(sizeof(dp[0]),__FILE__,__LINE__);
490 memset(dp,0,sizeof(dp[0]));
491 Merge_line_list( dp, sp, 0, 0, 0);
492 dest->list[dest->count++] = (void *)dp;
493 }
494 }
495 }
496
497 /*
498 * Split( struct line_list *l, char *str, int sort, char *keysep,
499 * int uniq, int trim, int nocomments, char *escape )
500 * Split the str up into strings, as delimted by sep.
501 * put duplicates of the original into the line_list l.
502 * If sort != 0, then sort them using keysep to separate sort key from value
503 * if uniq != then replace rather than add entries
504 * if trim != 0 then remove leading and trailing whitespace and
505 * if trim is a printable character any characters at start == trim
506 * if nocomments != 0, then remove comments as well
507 * if escape != 0, then allow the characters in the string to be escaped
508 * i.e. - escape = ":" then \: would be replace by :
509 *
510 */
Split(struct line_list * l,const char * str,const char * sep,int sort,const char * keysep,int uniq,int trim,int nocomments,const char * escape)511 void Split( struct line_list *l, const char *str, const char *sep,
512 int sort, const char *keysep, int uniq, int trim, int nocomments, const char *escape )
513 {
514 const char *end = 0, *t;
515 char *buffer = 0;
516 int len, blen = 0;
517 if(DEBUGL5){
518 char b[40];
519 int n;
520 plp_snprintf( b,sizeof(b)-8, "%s",str );
521 if( (n = safestrlen(b)) > (int)sizeof(b)-10 ) strcpy( b+n,"..." );
522 LOGDEBUG("Split: str 0x%lx '%s', sep '%s', escape '%s', sort %d, keysep '%s', uniq %d, trim %d",
523 Cast_ptr_to_long(str), b, sep, escape, sort, keysep, uniq, trim );
524 }
525 for( ; str && *str; str = end ){
526 end = 0;
527 t = str;
528 if( !ISNULL(sep) ) while( (t = safestrpbrk( t, sep )) ){
529 if( escape && t != str && cval(t-1) == '\\'
530 && strchr( escape, cval(t) ) ){
531 ++t;
532 DEBUG5("Split: escape '%s'", t );
533 continue;
534 }
535 end = t+1;
536 break;
537 }
538 if( !end ){
539 t = str + safestrlen(str);
540 }
541 DEBUG5("Split: str 0x%lx, ('%c%c...') end 0x%lx, t 0x%lx",
542 Cast_ptr_to_long(str), str[0], str[1],
543 Cast_ptr_to_long(end), Cast_ptr_to_long(t));
544 if( trim ){
545 while( isspace(cval(str)) ) ++str;
546 /* you can also remove leading characters */
547 if( cval(str) == trim && isprint(trim) ) ++str;
548 for( ; t > str && isspace(cval(t-1)); --t );
549 }
550 len = t - str;
551 DEBUG5("Split: after trim len %d, str 0x%lx, end 0x%lx, t 0x%lx",
552 len, Cast_ptr_to_long(str),
553 Cast_ptr_to_long(end), Cast_ptr_to_long(t));
554 if( len < 0 ) continue;
555 if( trim && len == 0 ) continue;
556 if( nocomments && (cval(str) == '#') ) continue;
557 if( blen <= len ){
558 blen = 2*len;
559 buffer = realloc_or_die(buffer,blen+1,__FILE__,__LINE__);
560 }
561 memmove(buffer,str,len);
562 buffer[len] = 0;
563 Add_line_list( l, buffer, keysep, sort, uniq );
564 }
565 if( buffer ) free(buffer);
566 }
567
Join_line_list(struct line_list * l,const char * sep)568 char *Join_line_list( struct line_list *l, const char *sep )
569 {
570 char *s, *t, *str = 0;
571 int len = 0, i, n = 0;
572
573 if( sep ) n = safestrlen(sep);
574 for( i = 0; i < l->count; ++i ){
575 s = l->list[i];
576 if( s && *s ) len += safestrlen(s) + n;
577 }
578 if( len ){
579 str = malloc_or_die(len+1,__FILE__,__LINE__);
580 t = str;
581 for( i = 0; i < l->count; ++i ){
582 s = l->list[i];
583 if( s && *s ){
584 strcpy( t, s );
585 t += safestrlen(t);
586 if( n ){
587 strcpy(t,sep);
588 t += n;
589 }
590 }
591 }
592 *t = 0;
593 }
594 return( str );
595 }
596
Join_line_list_with_sep(struct line_list * l,const char * sep)597 char *Join_line_list_with_sep( struct line_list *l, const char *sep )
598 {
599 char *s = Join_line_list( l, sep );
600 int len = 0;
601
602 if( sep ) len = safestrlen(sep);
603 if( s ){
604 *(s+safestrlen(s)-len) = 0;;
605 }
606 return( s );
607 }
608
Dump_line_list(const char * title,struct line_list * l)609 void Dump_line_list( const char *title, struct line_list *l )
610 {
611 int i;
612 LOGDEBUG("Dump_line_list: %s - 0x%lx, count %d, max %d, list 0x%lx",
613 title, Cast_ptr_to_long(l), l?l->count:0, l?l->max:0, l?Cast_ptr_to_long(l->list):(long)0 );
614 if(l)for( i = 0; i < l->count; ++i ){
615 LOGDEBUG( " [%2d] 0x%lx ='%s'", i, Cast_ptr_to_long(l->list[i]), l->list[i] );
616 }
617 }
618
Dump_line_list_sub(const char * title,struct line_list * l)619 void Dump_line_list_sub( const char *title, struct line_list *l )
620 {
621 int i;
622 LOGDEBUG(" %s - 0x%lx, count %d, max %d, list 0x%lx",
623 title, Cast_ptr_to_long(l), l?l->count:0, l?l->max:0, l?Cast_ptr_to_long(l->list):(long)0 );
624 if(l)for( i = 0; i < l->count; ++i ){
625 LOGDEBUG( " [%2d] 0x%lx ='%s'", i, Cast_ptr_to_long(l->list[i]), l->list[i] );
626 }
627 }
628
629
630 /*
631 * int Find_first_key( struct line_list *l, char *key, char *sep, int *mid )
632 * int Find_last_key( struct line_list *l, char *key, char *sep, int *mid )
633 * Search the list for the last corresponding key value
634 * The list has lines of the form:
635 * key [separator] value
636 * returns:
637 * *at = index of last tested value
638 * return value: 0 if found;
639 * <0 if list[*at] < key
640 * >0 if list[*at] > key
641 */
642
Find_last_key(struct line_list * l,const char * key,const char * sep,int * m)643 static int Find_last_key( struct line_list *l, const char *key, const char *sep, int *m )
644 {
645 int c=0, cmp=-1, cmpl = 0, bot, top, mid;
646 char *s, *t;
647 mid = bot = 0; top = l->count-1;
648 DEBUG5("Find_last_key: count %d, key '%s'", l->count, key );
649 while( cmp && bot <= top ){
650 mid = (top+bot)/2;
651 s = l->list[mid];
652 t = 0;
653 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
654 cmp = safestrcasecmp(key,s);
655 if( t ) *t = c;
656 if( cmp > 0 ){
657 bot = mid+1;
658 } else if( cmp < 0 ){
659 top = mid -1;
660 } else while( mid+1 < l->count ){
661 s = l->list[mid+1];
662 DEBUG5("Find_last_key: existing entry, mid %d, '%s'",
663 mid, l->list[mid] );
664 t = 0;
665 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
666 cmpl = safestrcasecmp(s,key);
667 if( t ) *t = c;
668 if( cmpl ) break;
669 ++mid;
670 }
671 DEBUG5("Find_last_key: cmp %d, top %d, mid %d, bot %d",
672 cmp, top, mid, bot);
673 }
674 if( m ) *m = mid;
675 DEBUG5("Find_last_key: key '%s', cmp %d, mid %d", key, cmp, mid );
676 return( cmp );
677 }
678
679
680 /*
681 * int Find_first_casekey( struct line_list *l, char *key, char *sep, int *mid )
682 * int Find_last_casekey( struct line_list *l, char *key, char *sep, int *mid )
683 * Search the list for the last corresponding key value using case sensitive keys
684 * The list has lines of the form:
685 * key [separator] value
686 * returns:
687 * *at = index of last tested value
688 * return value: 0 if found;
689 * <0 if list[*at] < key
690 * >0 if list[*at] > key
691 */
692
Find_last_casekey(struct line_list * l,const char * key,const char * sep,int * m)693 static int Find_last_casekey( struct line_list *l, const char *key, const char *sep, int *m )
694 {
695 int c=0, cmp=-1, cmpl = 0, bot, top, mid;
696 char *s, *t;
697 mid = bot = 0; top = l->count-1;
698 DEBUG5("Find_last_casekey: count %d, key '%s'", l->count, key );
699 while( cmp && bot <= top ){
700 mid = (top+bot)/2;
701 s = l->list[mid];
702 t = 0;
703 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
704 cmp = safestrcmp(key,s);
705 if( t ) *t = c;
706 if( cmp > 0 ){
707 bot = mid+1;
708 } else if( cmp < 0 ){
709 top = mid -1;
710 } else while( mid+1 < l->count ){
711 s = l->list[mid+1];
712 DEBUG5("Find_last_key: existing entry, mid %d, '%s'",
713 mid, l->list[mid] );
714 t = 0;
715 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
716 cmpl = safestrcmp(s,key);
717 if( t ) *t = c;
718 if( cmpl ) break;
719 ++mid;
720 }
721 DEBUG5("Find_last_casekey: cmp %d, top %d, mid %d, bot %d",
722 cmp, top, mid, bot);
723 }
724 if( m ) *m = mid;
725 DEBUG5("Find_last_casekey: key '%s', cmp %d, mid %d", key, cmp, mid );
726 return( cmp );
727 }
728
Find_first_key(struct line_list * l,const char * key,const char * sep,int * m)729 int Find_first_key( struct line_list *l, const char *key, const char *sep, int *m )
730 {
731 int c=0, cmp=-1, cmpl = 0, bot, top, mid;
732 char *s, *t;
733 mid = bot = 0; top = l->count-1;
734 DEBUG5("Find_first_key: count %d, key '%s', sep '%s'",
735 l->count, key, sep );
736 while( cmp && bot <= top ){
737 mid = (top+bot)/2;
738 s = l->list[mid];
739 t = 0;
740 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
741 cmp = safestrcasecmp(key,s);
742 if( t ) *t = c;
743 if( cmp > 0 ){
744 bot = mid+1;
745 } else if( cmp < 0 ){
746 top = mid -1;
747 } else while( mid > 0 ){
748 s = l->list[mid-1];
749 t = 0;
750 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
751 cmpl = safestrcasecmp(s,key);
752 if( t ) *t = c;
753 if( cmpl ) break;
754 --mid;
755 }
756 DEBUG5("Find_first_key: cmp %d, top %d, mid %d, bot %d",
757 cmp, top, mid, bot);
758 }
759 if( m ) *m = mid;
760 DEBUG5("Find_first_key: cmp %d, mid %d, key '%s', count %d",
761 cmp, mid, key, l->count );
762 return( cmp );
763 }
764
Find_first_casekey(struct line_list * l,const char * key,const char * sep,int * m)765 static int Find_first_casekey( struct line_list *l, const char *key, const char *sep, int *m )
766 {
767 int c=0, cmp=-1, cmpl = 0, bot, top, mid;
768 char *s, *t;
769 mid = bot = 0; top = l->count-1;
770 DEBUG5("Find_first_casekey: count %d, key '%s', sep '%s'",
771 l->count, key, sep );
772 while( cmp && bot <= top ){
773 mid = (top+bot)/2;
774 s = l->list[mid];
775 t = 0;
776 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
777 cmp = safestrcmp(key,s);
778 if( t ) *t = c;
779 if( cmp > 0 ){
780 bot = mid+1;
781 } else if( cmp < 0 ){
782 top = mid -1;
783 } else while( mid > 0 ){
784 s = l->list[mid-1];
785 t = 0;
786 if( sep && (t = safestrpbrk(s, sep )) ) { c = *t; *t = 0; }
787 cmpl = safestrcmp(s,key);
788 if( t ) *t = c;
789 if( cmpl ) break;
790 --mid;
791 }
792 DEBUG5("Find_first_casekey: cmp %d, top %d, mid %d, bot %d",
793 cmp, top, mid, bot);
794 }
795 if( m ) *m = mid;
796 DEBUG5("Find_first_casekey: cmp %d, mid %d, key '%s', count %d",
797 cmp, mid, key, l->count );
798 return( cmp );
799 }
800
801 /*
802 * char *Find_value( struct line_list *l, char *key )
803 * Search the list for a corresponding key value
804 * value
805 * key "1"
806 * key@ "0"
807 * key#v v
808 * key=v v
809 * key v v
810 * If key does not exist, we return "0"
811 */
812
Find_value(struct line_list * l,const char * key)813 static const char *Find_value( struct line_list *l, const char *key )
814 {
815 const char *s = "0";
816 int mid, cmp = -1;
817 const char *sep = Option_value_sep;
818
819 DEBUG5("Find_value: key '%s', sep '%s'", key, sep );
820 if( l ) cmp = Find_first_key( l, key, sep, &mid );
821 DEBUG5("Find_value: key '%s', cmp %d, mid %d", key, cmp, mid );
822 if( cmp==0 ){
823 s = Fix_val( safestrpbrk(l->list[mid], sep ) );
824 }
825 DEBUG4( "Find_value: key '%s', value '%s'", key, s );
826 return(s);
827 }
828
829 /*
830 * char *Find_exists_value( struct line_list *l, char *key, char *sep )
831 * Search the list for a corresponding key value
832 * value
833 * key "1"
834 * key@ "0"
835 * key#v v
836 * key=v v
837 * If key does not exist we return 0 (null)
838 */
839
Find_exists_value(struct line_list * l,const char * key,const char * sep)840 const char *Find_exists_value( struct line_list *l, const char *key, const char *sep )
841 {
842 const char *s = 0;
843 int mid, cmp = -1;
844
845 if( l ) cmp = Find_first_key( l, key, sep, &mid );
846 if( cmp==0 ){
847 if( sep ){
848 s = Fix_val( safestrpbrk(l->list[mid], sep ) );
849 } else {
850 s = l->list[mid];
851 }
852 }
853 DEBUG4( "Find_exists_value: key '%s', cmp %d, value '%s'", key, cmp, s );
854 return(s);
855 }
856
857
858 /*
859 * char *Find_str_value( struct line_list *l, char *key )
860 * Search the list for a corresponding key value
861 * value
862 * key 0
863 * key@ 0
864 * key#v 0
865 * key=v v
866 */
867
Find_str_value(struct line_list * l,const char * key)868 char *Find_str_value( struct line_list *l, const char *key )
869 {
870 char *s = 0;
871 int mid, cmp = -1;
872 const char *sep = Option_value_sep;
873
874 if( l ) cmp = Find_first_key( l, key, sep, &mid );
875 if( cmp==0 ){
876 /*
877 * value: NULL, "", "@", "=xx", "#xx".
878 * returns: "0", "1","0", "xx", "xx"
879 */
880 s = safestrpbrk(l->list[mid], sep );
881 if( s && *s == '=' ){
882 ++s;
883 } else {
884 s = 0;
885 }
886 }
887 DEBUG4( "Find_str_value: key '%s', value '%s'", key, s );
888 return(s);
889 }
890
891
892 /*
893 * char *Find_casekey_str_value( struct line_list *l, char *key, char *sep )
894 * Search the list for a corresponding key value using case sensitive keys
895 * value
896 * key 0
897 * key@ 0
898 * key#v 0
899 * key=v v
900 */
901
Find_casekey_str_value(struct line_list * l,const char * key,const char * sep)902 char *Find_casekey_str_value( struct line_list *l, const char *key, const char *sep )
903 {
904 char *s = 0;
905 int mid, cmp = -1;
906
907 if( l ) cmp = Find_first_casekey( l, key, sep, &mid );
908 if( cmp==0 ){
909 /*
910 * value: NULL, "", "@", "=xx", "#xx".
911 * returns: "0", "1","0", "xx", "xx"
912 */
913 if( sep ){
914 s = safestrpbrk(l->list[mid], sep );
915 if( s && *s == '=' ){
916 ++s;
917 } else {
918 s = 0;
919 }
920 } else {
921 s = l->list[mid];
922 }
923 }
924 DEBUG4( "Find_casekey_str_value: key '%s', value '%s'", key, s );
925 return(s);
926 }
927
928
929 /*
930 * Set_str_value( struct line_list *l, char *key, char *value )
931 * set a string value in an ordered, sorted list
932 */
Set_str_value(struct line_list * l,const char * key,const char * value)933 void Set_str_value( struct line_list *l, const char *key, const char *value )
934 {
935 char *s = 0;
936 int mid;
937 if( key == 0 ) return;
938 if(DEBUGL6){
939 char buffer[16];
940 plp_snprintf(buffer,sizeof(buffer)-5, "%s",value);
941 buffer[12] = 0;
942 if( value && safestrlen(value) > 12 ) strcat(buffer,"...");
943 LOGDEBUG("Set_str_value: '%s'= 0x%lx '%s'", key,
944 Cast_ptr_to_long(value), buffer);
945 }
946 if( value && *value ){
947 s = safestrdup3(key,"=",value,__FILE__,__LINE__);
948 Add_line_list(l,s,Hash_value_sep,1,1);
949 if(s) free(s); s = 0;
950 } else if( !Find_first_key(l, key, Hash_value_sep, &mid ) ){
951 Remove_line_list(l,mid);
952 }
953 }
954
955 /*
956 * Set_casekey_str_value( struct line_list *l, char *key, char *value )
957 * set an string value in an ordered, sorted list, with case sensitive keys
958 */
Set_casekey_str_value(struct line_list * l,const char * key,const char * value)959 void Set_casekey_str_value( struct line_list *l, const char *key, const char *value )
960 {
961 char *s = 0;
962 int mid;
963 if( key == 0 ) return;
964 if(DEBUGL6){
965 char buffer[16];
966 plp_snprintf(buffer,sizeof(buffer)-5, "%s",value);
967 buffer[12] = 0;
968 if( value && safestrlen(value) > 12 ) strcat(buffer,"...");
969 LOGDEBUG("Set_str_value: '%s'= 0x%lx '%s'", key,
970 Cast_ptr_to_long(value), buffer);
971 }
972 if( value && *value ){
973 s = safestrdup3(key,"=",value,__FILE__,__LINE__);
974 Add_casekey_line_list(l,s,Hash_value_sep);
975 if(s) free(s); s = 0;
976 } else if( !Find_first_casekey(l, key, Hash_value_sep, &mid ) ){
977 Remove_line_list(l,mid);
978 }
979 }
980
981
982 /*
983 * Set_flag_value( struct line_list *l, char *key, int value )
984 * set a flag value in an ordered, sorted list
985 */
Set_flag_value(struct line_list * l,const char * key,long value)986 void Set_flag_value( struct line_list *l, const char *key, long value )
987 {
988 char buffer[SMALLBUFFER];
989 if( key == 0 ) return;
990 plp_snprintf(buffer,sizeof(buffer), "%s=0x%lx",key,value);
991 Add_line_list(l,buffer,Hash_value_sep,1,1);
992 }
993
994
995 /*
996 * Set_nz_flag_value( struct line_list *l, char *key, int value )
997 * set a nonzero flag value in an ordered, sorted list
998 */
Set_nz_flag_value(struct line_list * l,const char * key,long value)999 void Set_nz_flag_value( struct line_list *l, const char *key, long value )
1000 {
1001 if( !Find_flag_value( l, key ) ){
1002 Set_flag_value( l, key, value );
1003 }
1004 }
1005
1006
1007 /*
1008 * Set_double_value( struct line_list *l, char *key, int value )
1009 * set a double value in an ordered, sorted list
1010 */
Set_double_value(struct line_list * l,const char * key,double value)1011 void Set_double_value( struct line_list *l, const char *key, double value )
1012 {
1013 char buffer[SMALLBUFFER];
1014 if( key == 0 ) return;
1015 plp_snprintf(buffer,sizeof(buffer), "%s=%0.0f",key,value);
1016 Add_line_list(l,buffer,Hash_value_sep,1,1);
1017 }
1018
1019
1020 /*
1021 * Set_decimal_value( struct line_list *l, char *key, int value )
1022 * set a decimal value in an ordered, sorted list
1023 */
Set_decimal_value(struct line_list * l,const char * key,long value)1024 void Set_decimal_value( struct line_list *l, const char *key, long value )
1025 {
1026 char buffer[SMALLBUFFER];
1027 if( key == 0 ) return;
1028 plp_snprintf(buffer,sizeof(buffer), "%s=%ld",key,value);
1029 Add_line_list(l,buffer,Hash_value_sep,1,1);
1030 }
1031 /*
1032 * Remove_line_list( struct line_list *l, int mid )
1033 * Remove the indicated entry and move the other
1034 * entries up.
1035 */
Remove_line_list(struct line_list * l,int mid)1036 void Remove_line_list( struct line_list *l, int mid )
1037 {
1038 char *s;
1039 if( mid >= 0 && mid < l->count ){
1040 if( (s = l->list[mid]) ){
1041 free(s);
1042 l->list[mid] = 0;
1043 }
1044 memmove(&l->list[mid],&l->list[mid+1],(l->count-mid-1)*sizeof(char *));
1045 --l->count;
1046 }
1047 }
1048
1049
1050 /*
1051 * Remove_duplicates_line_list( struct line_list *l )
1052 * Remove duplicate entries in the list
1053 */
Remove_duplicates_line_list(struct line_list * l)1054 static void Remove_duplicates_line_list( struct line_list *l )
1055 {
1056 char *s, *t;
1057 int i, j;
1058 for( i = 0; i < l->count; ){
1059 if( (s = l->list[i]) ){
1060 for( j = i+1; j < l->count; ){
1061 if( !(t = l->list[j]) || !safestrcmp(s,t) ){
1062 Remove_line_list( l, j );
1063 } else {
1064 ++j;
1065 }
1066 }
1067 ++i;
1068 } else {
1069 Remove_line_list( l, i );
1070 }
1071 }
1072 }
1073
1074
1075 /*
1076 * char *Find_flag_value( struct line_list *l, char *key )
1077 * Search the list for a corresponding key value
1078 * value
1079 * key 1
1080 * key@ 0
1081 * key#v v if v is integer, 0 otherwise
1082 * key=v v if v is integer, 0 otherwise
1083 */
1084
Find_flag_value(struct line_list * l,const char * key)1085 int Find_flag_value( struct line_list *l, const char *key )
1086 {
1087 const char *s;
1088 char *e;
1089 int n = 0;
1090
1091 if( l && (s = Find_value( l, key )) ){
1092 e = 0;
1093 n = strtol(s,&e,0);
1094 if( !e || *e ) n = 0;
1095 }
1096 DEBUG4( "Find_flag_value: key '%s', value '%d'", key, n );
1097 return(n);
1098 }
1099
1100
1101 /*
1102 * char *Find_decimal_value( struct line_list *l, char *key )
1103 * Search the list for a corresponding key value
1104 * value
1105 * key 1
1106 * key@ 0
1107 * key#v v if v is decimal, 0 otherwise
1108 * key=v v if v is decimal, 0 otherwise
1109 */
1110
Find_decimal_value(struct line_list * l,const char * key)1111 int Find_decimal_value( struct line_list *l, const char *key )
1112 {
1113 const char *s = 0;
1114 char *e;
1115 int n = 0;
1116
1117 if( l && (s = Find_value( l, key )) ){
1118 e = 0;
1119 n = strtol(s,&e,10);
1120 if( !e || *e ){
1121 e = 0;
1122 n = strtol(s,&e,0);
1123 if( !e || *e ) n = 0;
1124 }
1125 }
1126 DEBUG4( "Find_decimal_value: key '%s', value '%d'", key, n );
1127 return(n);
1128 }
1129
1130
1131 /*
1132 * double Find_double_value( struct line_list *l, char *key )
1133 * Search the list for a corresponding key value
1134 * value
1135 * key 1
1136 * key@ 0
1137 * key#v v if v is decimal, 0 otherwise
1138 * key=v v if v is decimal, 0 otherwise
1139 */
1140
Find_double_value(struct line_list * l,const char * key)1141 double Find_double_value( struct line_list *l, const char *key )
1142 {
1143 const char *s = 0;
1144 char *e;
1145 double n = 0;
1146
1147 if( l && (s = Find_value( l, key )) ){
1148 e = 0;
1149 n = strtod(s,&e);
1150 }
1151 DEBUG4( "Find_double_value: key '%s', value '%0.0f'", key, n );
1152 return(n);
1153 }
1154
1155 /*
1156 * char *Fix_val( char *s )
1157 * passed: NULL, "", "@", "=xx", "#xx".
1158 * returns: "0", "1","0", "xx", "xx"
1159 */
1160
Fix_val(const char * s)1161 static const char *Fix_val( const char *s )
1162 {
1163 int c = 0;
1164 if( s ){
1165 c = cval(s);
1166 ++s;
1167 while( isspace(cval(s)) ) ++s;
1168 }
1169 if( c == 0 ){
1170 s = "1";
1171 } else if( c == '@' ){
1172 s = "0";
1173 }
1174 return( s );
1175 }
1176
1177 /*
1178 * Find_tags( struct line_list dest,
1179 * struct line_list *list, char *tag )
1180 *
1181 * Scan the list (ordered, of course) for the
1182 * set of entries starting with 'tag' and extract them
1183 * to list
1184 */
1185
Find_tags(struct line_list * dest,struct line_list * l,const char * key)1186 void Find_tags( struct line_list *dest, struct line_list *l, const char *key )
1187 {
1188 int cmp=-1, cmpl = 0, bot, top, mid, len;
1189 char *s;
1190
1191 if( key == 0 || *key == 0 ) return;
1192 mid = bot = 0; top = l->count-1;
1193 len = safestrlen(key);
1194 DEBUG5("Find_tags: count %d, key '%s'", l->count, key );
1195 while( cmp && bot <= top ){
1196 mid = (top+bot)/2;
1197 s = l->list[mid];
1198 cmp = safestrncasecmp(key,s,len);
1199 if( cmp > 0 ){
1200 bot = mid+1;
1201 } else if( cmp < 0 ){
1202 top = mid -1;
1203 } else while( mid > 0 ){
1204 DEBUG5("Find_tags: existing entry, mid %d, '%s'", mid, l->list[mid] );
1205 s = l->list[mid-1];
1206 cmpl = safestrncasecmp(s,key,len);
1207 if( cmpl ) break;
1208 --mid;
1209 }
1210 DEBUG5("Find_tags: cmp %d, top %d, mid %d, bot %d",
1211 cmp, top, mid, bot);
1212 }
1213 if( cmp == 0 ){
1214 s = l->list[mid];
1215 do{
1216 DEBUG5("Find_tags: adding '%s'", s+len );
1217 Add_line_list(dest,s+len,Hash_value_sep,1,1);
1218 ++mid;
1219 } while( mid < l->count
1220 && (s = l->list[mid])
1221 && !(cmp = safestrncasecmp(key,s,len)));
1222 }
1223 }
1224
1225 /*
1226 * Find_defaulttags( struct line_list dest,
1227 * struct keywords *var_list, char *tag )
1228 *
1229 * Scan the variable list for default values
1230 * starting with 'tag' and extract them
1231 * to list
1232 */
1233
Find_default_tags(struct line_list * dest,struct keywords * var_list,const char * tag)1234 void Find_default_tags( struct line_list *dest,
1235 struct keywords *var_list, const char *tag )
1236 {
1237 int len = safestrlen(tag);
1238 const char *key, *value;
1239
1240 if( var_list ) while( var_list->keyword ){
1241 if( !strncmp((key = var_list->keyword), tag, len)
1242 && (value = var_list->default_value) ){
1243 if( *value == '=' ) ++value;
1244 DEBUG5("Find_default_tags: adding '%s'='%s'", key, value);
1245 Set_str_value(dest, key+len, value );
1246 }
1247 ++var_list;
1248 }
1249 }
1250
1251
1252
1253 /*
1254 * Read_file_list( struct line_list *model, char *str
1255 * char *sep, int sort, char *keysep, int uniq, int trim, int marker,
1256 * int doinclude, int nocomment, int depth, int maxdepth )
1257 * read the model information from these files
1258 * if marker != then add a NULL line after each file
1259 */
1260
Read_file_list(int required,struct line_list * model,char * str,const char * linesep,int sort,const char * keysep,int uniq,int trim,int marker,int doinclude,int nocomment,int depth,int maxdepth)1261 void Read_file_list( int required, struct line_list *model, char *str,
1262 const char *linesep, int sort, const char *keysep, int uniq, int trim,
1263 int marker, int doinclude, int nocomment, int depth, int maxdepth )
1264 {
1265 struct line_list l;
1266 int i, start, end, c=0, n, found;
1267 char *s, *t;
1268 struct stat statb;
1269
1270 Init_line_list(&l);
1271 DEBUG3("Read_file_list: '%s', doinclude %d, depth %d, maxdepth %d, keysep '%s'",
1272 str, doinclude, depth, maxdepth, keysep );
1273 if( depth > maxdepth ){
1274 Errorcode = JABORT;
1275 logerr_die(LOG_ERR,
1276 "Read_file_list: recursion depth %d exceeds maxdepth %d for file '%s'",
1277 depth, maxdepth, str );
1278 }
1279 Split( &l, str, File_sep, 0, 0, 0, 1, 0 ,0);
1280 start = model->count;
1281 for( i = 0; i < l.count; ++i ){
1282 if( stat( l.list[i], &statb ) == -1 ){
1283 if( required || depth ){
1284 Errorcode = JABORT;
1285 logerr_die(LOG_ERR,
1286 "Read_file_list: cannot stat required or included file '%s'",
1287 l.list[i] );
1288 }
1289 continue;
1290 }
1291 Read_file_and_split( model, l.list[i], linesep, sort, keysep,
1292 uniq, trim, nocomment );
1293 if( doinclude ){
1294 /* scan through the list, looking for include lines */
1295 for( end = model->count; start < end; ){
1296 t = 0;
1297 s = model->list[start];
1298 found = 0;
1299 t = 0;
1300 if( s && (t = safestrpbrk( s, Whitespace )) ){
1301 c = *t; *t = 0;
1302 found = !safestrcasecmp( s, "include" );
1303 *t = c;
1304 }
1305 if( found ){
1306 DEBUG4("Read_file_list: include '%s'", t+1 );
1307 Read_file_list( 1, model, t+1, linesep, sort, keysep, uniq, trim,
1308 marker, doinclude, nocomment, depth+1, maxdepth );
1309 /* at this point the include lines are at
1310 * end to model->count-1
1311 * we need to move the lines from start to end-1
1312 * to model->count, and then move end to start
1313 */
1314 n = end - start;
1315 Check_max( model, n );
1316 /* copy to end */
1317 if(DEBUGL5)Dump_line_list("Read_file_list: include before",
1318 model );
1319 memmove( &model->list[model->count],
1320 &model->list[start], n*sizeof(char *) );
1321 memmove( &model->list[start],
1322 &model->list[end],(model->count-start)*sizeof(char *));
1323 if(DEBUGL4)Dump_line_list("Read_file_list: include after",
1324 model );
1325 end = model->count;
1326 start = end - n;
1327 DEBUG4("Read_file_list: start now '%s'",model->list[start]);
1328 /* we get rid of include line */
1329 s = model->list[start];
1330 free(s);
1331 model->list[start] = 0;
1332 memmove( &model->list[start], &model->list[start+1],
1333 n*sizeof(char *) );
1334 --model->count;
1335 end = model->count;
1336 } else {
1337 ++start;
1338 }
1339 }
1340 }
1341 if( marker ){
1342 /* put null at end of list */
1343 Check_max( model, 1 );
1344 model->list[model->count++] = 0;
1345 }
1346 }
1347 Free_line_list(&l);
1348 if(DEBUGL5)Dump_line_list("Read_file_list: result", model);
1349 }
1350
Read_fd_and_split(struct line_list * list,int fd,const char * linesep,int sort,const char * keysep,int uniq,int trim,int nocomment)1351 void Read_fd_and_split( struct line_list *list, int fd,
1352 const char *linesep, int sort, const char *keysep, int uniq,
1353 int trim, int nocomment )
1354 {
1355 int size = 0, count, len;
1356 char *sv;
1357 char buffer[LARGEBUFFER];
1358
1359 sv = 0;
1360 while( (count = ok_read(fd, buffer, sizeof(buffer)-1)) > 0 ){
1361 buffer[count] = 0;
1362 len = size+count+1;
1363 sv = realloc_or_die( sv, len,__FILE__,__LINE__);
1364 memmove( sv+size, buffer, count );
1365 size += count;
1366 sv[size] = 0;
1367 }
1368 close( fd );
1369 DEBUG4("Read_fd_and_split: size %d", size );
1370 Split( list, sv, linesep, sort, keysep, uniq, trim, nocomment ,0);
1371 if( sv ) free( sv );
1372 }
1373
Read_file_and_split(struct line_list * list,char * file,const char * linesep,int sort,const char * keysep,int uniq,int trim,int nocomment)1374 static void Read_file_and_split( struct line_list *list, char *file,
1375 const char *linesep, int sort, const char *keysep, int uniq,
1376 int trim, int nocomment )
1377 {
1378 int fd;
1379 struct stat statb;
1380
1381 DEBUG3("Read_file_and_split: '%s', trim %d, nocomment %d",
1382 file, trim, nocomment );
1383 if( (fd = Checkread( file, &statb )) < 0 ){
1384 logerr_die(LOG_INFO,
1385 "Read_file_and_split: cannot open '%s' - '%s'",
1386 file, Errormsg(errno) );
1387 }
1388 Read_fd_and_split( list, fd, linesep, sort, keysep, uniq,
1389 trim, nocomment );
1390 }
1391
1392
1393 /*
1394 * Printcap information
1395 */
1396
1397
1398 /*
1399 * Build_pc_names( struct line_list *names, struct line_list *order, char *s )
1400 * names = list of aliases and names
1401 * order = order that names were found
1402 *
1403 * get the primary name
1404 * if it is not in the names lists, add to order list
1405 * put the names and aliases in the names list
1406 */
Build_pc_names(struct line_list * names,struct line_list * order,char * str,struct host_information * hostname)1407 static int Build_pc_names( struct line_list *names, struct line_list *order,
1408 char *str, struct host_information *hostname )
1409 {
1410 char *s, *t;
1411 int c = 0, i, ok = 0, len, start_oh, end_oh;
1412 struct line_list l, opts, oh;
1413
1414 Init_line_list(&l);
1415 Init_line_list(&opts);
1416 Init_line_list(&oh);
1417
1418 DEBUG4("Build_pc_names: start '%s'", str);
1419 if( (s = safestrpbrk(str, ":")) ){
1420 c = *s; *s = 0;
1421 Split(&opts,s+1,":",1,Option_value_sep,0,1,0,":");
1422 }
1423 Split(&l,str,"|",0,0,0,1,0,0);
1424 if( s ) *s = c;
1425 if(DEBUGL4)Dump_line_list("Build_pc_names- names", &l);
1426 if(DEBUGL4)Dump_line_list("Build_pc_names- options", &opts);
1427 if( l.count == 0 ){
1428 if(Warnings){
1429 WARNMSG(
1430 "no name for printcap entry '%s'", str );
1431 } else {
1432 logmsg(LOG_INFO,
1433 "no name for printcap entry '%s'", str );
1434 }
1435 } else {
1436 ok = 1;
1437 if( Find_flag_value( &opts,SERVER ) && !Is_server ){
1438 DEBUG4("Build_pc_names: not server" );
1439 ok = 0;
1440 } else if( Find_flag_value( &opts,CLIENT ) && Is_server ){
1441 DEBUG4("Build_pc_names: not client" );
1442 ok = 0;
1443 } else if( !Find_first_key(&opts,"oh",Hash_value_sep,&start_oh)
1444 && !Find_last_key(&opts,"oh",Hash_value_sep,&end_oh) ){
1445 ok = 0;
1446 DEBUG4("Build_pc_names: start_oh %d, end_oh %d",
1447 start_oh, end_oh );
1448 for( i = start_oh; !ok && i <= end_oh; ++i ){
1449 DEBUG4("Build_pc_names: [%d] '%s'", i, opts.list[i] );
1450 if( (t = safestrchr( opts.list[i], '=' )) ){
1451 Split(&oh,t+1,File_sep,0,0,0,1,0,0);
1452 ok = !Match_ipaddr_value(&oh, hostname);
1453 DEBUG4("Build_pc_names: check host '%s', ok %d",
1454 t+1, ok );
1455 Free_line_list(&oh);
1456 }
1457 }
1458 }
1459 if( ok && (s = safestrpbrk( l.list[0], Option_value_sep)) ){
1460 ok = 0;
1461 if(Warnings){
1462 WARNMSG(
1463 "bad printcap name '%s', has '%c' character",
1464 l.list[0], *s );
1465 } else {
1466 logmsg(LOG_INFO,
1467 "bad printcap name '%s', has '%c' character",
1468 l.list[0], *s );
1469 }
1470 }
1471 if( ok ){
1472 if(DEBUGL4)Dump_line_list("Build_pc_names: adding ", &l);
1473 if(DEBUGL4)Dump_line_list("Build_pc_names- before names", names );
1474 if(DEBUGL4)Dump_line_list("Build_pc_names- before order", order );
1475 if( !Find_exists_value( names, l.list[0], Hash_value_sep ) ){
1476 Add_line_list(order,l.list[0],0,0,0);
1477 }
1478 for( i = 0; i < l.count; ++i ){
1479 if( safestrpbrk( l.list[i], Option_value_sep ) ){
1480 continue;
1481 }
1482 Set_str_value(names,l.list[i],l.list[0]);
1483 }
1484 len = safestrlen(str);
1485 s = str;
1486 DEBUG4("Build_pc_names: before '%s'", str );
1487 *s = 0;
1488 for( i = 0; i < l.count; ++i ){
1489 if( *str ) *s++ = '|';
1490 strcpy(s,l.list[i]);
1491 s += safestrlen(s);
1492 }
1493 for( i = 0; i < opts.count; ++i ){
1494 *s++ = ':';
1495 strcpy(s,opts.list[i]);
1496 s += safestrlen(s);
1497 }
1498 if( safestrlen(str) > len ){
1499 Errorcode = JABORT;
1500 fatal(LOG_ERR, "Build_pc_names: LINE GREW! fatal error");
1501 }
1502 DEBUG4("Build_pc_names: end '%s'", str );
1503 }
1504 }
1505
1506 Free_line_list(&l);
1507 Free_line_list(&opts);
1508 DEBUG4("Build_pc_names: returning ok '%d'", ok );
1509 return ok;
1510 }
1511
1512 /*
1513 * Build_printcap_info
1514 * OUTPUT
1515 * names = list of names in the form
1516 * alias=primary
1517 * order = list of names in order
1518 * list = list of all of the printcap entries
1519 * INPUT
1520 * input = orginal list information in split line format
1521 *
1522 * run through the raw information, extrating primary name and aliases
1523 * create entries in the names and order lists
1524 */
Build_printcap_info(struct line_list * names,struct line_list * order,struct line_list * list,struct line_list * raw,struct host_information * hostname)1525 void Build_printcap_info(
1526 struct line_list *names, struct line_list *order,
1527 struct line_list *list, struct line_list *raw,
1528 struct host_information *hostname )
1529 {
1530 int i, c;
1531 char *t, *keyid = 0;
1532 int appendline = 0;
1533
1534 DEBUG1("Build_printcap_info: list->count %d, raw->count %d",
1535 list->count, raw->count );
1536 for( i = 0; i < raw->count; ++i ){
1537 t = raw->list[i];
1538 DEBUG4("Build_printcap_info: doing '%s'", t );
1539 if( t ) while( isspace( cval(t) ) ) ++t;
1540 /* ignore blank lines and comments */
1541 if( t == 0 || (c = *t) == 0 || c == '#') continue;
1542 /* append lines starting with :, | */
1543 if( keyid
1544 && (safestrchr(Printcap_sep,c) || appendline) ){
1545 DEBUG4("Build_printcap_info: old keyid '%s', adding '%s'",
1546 keyid, t );
1547 keyid = safeextend3(keyid, " ", t,__FILE__,__LINE__ );
1548 if( (appendline = (Lastchar(keyid) == '\\')) ){
1549 keyid[safestrlen(keyid)-1] = 0;
1550 }
1551 } else {
1552 DEBUG4("Build_printcap_info: old keyid '%s', new '%s'",
1553 keyid, t );
1554 if( keyid ){
1555 if( Build_pc_names( names, order, keyid, hostname ) ){
1556 Add_line_list( list, keyid, Printcap_sep, 1, 0 );
1557 }
1558 free(keyid); keyid = 0;
1559 }
1560 keyid = safestrdup(t,__FILE__,__LINE__);
1561 if( (appendline = (Lastchar(keyid) == '\\')) ){
1562 keyid[safestrlen(keyid)-1] = 0;
1563 }
1564 }
1565 }
1566 if( keyid ){
1567 if( Build_pc_names( names, order, keyid, hostname ) ){
1568 Add_line_list( list, keyid, Printcap_sep, 1, 0 );
1569 }
1570 free(keyid); keyid = 0;
1571 }
1572 if(DEBUGL4) Dump_line_list( "Build_printcap_info- end", list );
1573 return;
1574 }
1575
1576 /*
1577 * char *Select_pc_info(
1578 * - returns the main name of the print queue
1579 * struct line_list *aliases = list of names and aliases
1580 * struct line_list *info = printcap infor
1581 * struct line_list *names = entry names in the input list
1582 * alias=mainname
1583 * struct line_list *input = printcap entries, starting with mainname
1584 *
1585 * Select the printcap information and put it in the info list.
1586 * Return the main name;
1587 */
1588
Select_pc_info(const char * id,struct line_list * info,struct line_list * aliases,struct line_list * names,struct line_list * order,struct line_list * input,int depth,int wildcard)1589 char *Select_pc_info( const char *id,
1590 struct line_list *info,
1591 struct line_list *aliases,
1592 struct line_list *names,
1593 struct line_list *order,
1594 struct line_list *input,
1595 int depth, int wildcard )
1596 {
1597 int start, end, i, c;
1598 char *s, *t, *found = 0, *allglob = 0;
1599 struct line_list l;
1600
1601 Init_line_list(&l);
1602 DEBUG1("Select_pc_info: looking for '%s', depth %d", id, depth );
1603 if( depth > 5 ){
1604 Errorcode = JABORT;
1605 fatal(LOG_ERR, "Select_pc_info: printcap tc recursion depth %d", depth );
1606 }
1607 if(DEBUGL4)Dump_line_list("Select_pc_info- names", names );
1608 if(DEBUGL4)Dump_line_list("Select_pc_info- order", order );
1609 if(DEBUGL4)Dump_line_list("Select_pc_info- input", input );
1610 start = 0; end = 0;
1611 found = Find_str_value( names, id );
1612 if( !found && PC_filters_line_list.count ){
1613 Filterprintcap( &l, &PC_filters_line_list, id);
1614 Build_printcap_info( names, order, input, &l, &Host_IP );
1615 Free_line_list( &l );
1616 if(DEBUGL4)Dump_line_list("Select_pc_info- after filter aliases", aliases );
1617 if(DEBUGL4)Dump_line_list("Select_pc_info- after filter info", info );
1618 if(DEBUGL4)Dump_line_list("Select_pc_info- after filter names", names );
1619 if(DEBUGL4)Dump_line_list("Select_pc_info- after filter input", input );
1620 found = Find_str_value( names, id );
1621 }
1622 /* do partial glob match */
1623 c = 0;
1624 for( i = 0; !found && i < names->count; ++i ){
1625 s = names->list[i];
1626 if( (t = safestrpbrk(s, Hash_value_sep)) ){
1627 c = *t; *t = 0;
1628 DEBUG1("Select_pc_info: wildcard trying '%s'", s );
1629 if( !safestrcmp(s, id ) ){
1630 found = t+1;
1631 }
1632 *t = c;
1633 }
1634 }
1635 if( !found && wildcard ){
1636 c = 0;
1637 for( i = 0; !found && i < names->count; ++i ){
1638 s = names->list[i];
1639 if( (t = safestrpbrk(s, Hash_value_sep)) ){
1640 c = *t; *t = 0;
1641 DEBUG1("Select_pc_info: wildcard trying '%s'", s );
1642 if( !strcmp(s,"*") ){
1643 if( ISNULL(allglob) ){
1644 allglob = t+1;
1645 }
1646 } else if( !Globmatch( s, id ) ){
1647 found = t+1;
1648 }
1649 *t = c;
1650 }
1651 }
1652 }
1653 if( !found ){
1654 found = allglob;
1655 }
1656 if( found ){
1657 Find_pc_info( found, info, aliases, names, order, input, depth, 0 );
1658 }
1659 DEBUG1("Select_pc_info: returning '%s'", found );
1660 if(DEBUGL4)Dump_line_list("Select_pc_info- returning aliases", aliases );
1661 if(DEBUGL4)Dump_line_list("Select_pc_info- returning info", info );
1662 return( found );
1663 }
1664
Find_pc_info(char * name,struct line_list * info,struct line_list * aliases,struct line_list * names,struct line_list * order,struct line_list * input,int depth,int wildcard)1665 static void Find_pc_info( char *name,
1666 struct line_list *info,
1667 struct line_list *aliases,
1668 struct line_list *names,
1669 struct line_list *order,
1670 struct line_list *input,
1671 int depth, int wildcard )
1672 {
1673 int start, end, i, j, c, start_tc, end_tc;
1674 char *s, *t, *u;
1675 struct line_list l, pc, tc;
1676
1677 Init_line_list(&l); Init_line_list(&pc); Init_line_list(&tc);
1678
1679 DEBUG1("Find_pc_info: found name '%s'", name );
1680 if( Find_first_key(input,name,Printcap_sep,&start)
1681 || Find_last_key(input,name,Printcap_sep,&end) ){
1682 Errorcode = JABORT;
1683 fatal(LOG_ERR,
1684 "Find_pc_info: name '%s' in names and not in input list",
1685 name );
1686 }
1687 DEBUG4("Find_pc_info: name '%s', start %d, end %d",
1688 name, start, end );
1689 for(; start <= end; ++start ){
1690 u = input->list[start];
1691 DEBUG4("Find_pc_info: line [%d]='%s'", start, u );
1692 if( u && *u ){
1693 Add_line_list( &pc, u, 0, 0, 0 );
1694 }
1695 }
1696 if(DEBUGL4)Dump_line_list("Find_pc_info- entry lines", &l );
1697 for( start = 0; start < pc.count; ++ start ){
1698 u = pc.list[start];
1699 c = 0;
1700 if( (t = safestrpbrk(u,":")) ){
1701 Split(&l, t+1, ":", 1, Option_value_sep, 0, 1, 0,":");
1702 }
1703 if( aliases ){
1704 if( t ){
1705 c = *t; *t = 0;
1706 Split(aliases, u, Printcap_sep, 0, 0, 0, 0, 0,0);
1707 Remove_duplicates_line_list(aliases);
1708 *t = c;
1709 } else {
1710 Split(aliases, u, Printcap_sep, 0, 0, 0, 0, 0,0);
1711 Remove_duplicates_line_list(aliases);
1712 }
1713 }
1714 /* get the tc entries */
1715 if(DEBUGL4)Dump_line_list("Find_pc_info- pc entry", &l );
1716 if( !Find_first_key(&l,"tc",Hash_value_sep,&start_tc)
1717 && !Find_last_key(&l,"tc",Hash_value_sep,&end_tc) ){
1718 for( ; start_tc <= end_tc; ++start_tc ){
1719 if( (s = l.list[start_tc]) ){
1720 lowercase(s);
1721 DEBUG4("Find_pc_info: tc '%s'", s );
1722 if( (t = safestrchr( s, '=' )) ){
1723 Split(&tc,t+1,File_sep,0,0,0,1,0,0);
1724 }
1725 free( l.list[start_tc] );
1726 l.list[start_tc] = 0;
1727 }
1728 }
1729 }
1730 if(DEBUGL4)Dump_line_list("Find_pc_info- tc", &tc );
1731 for( j = 0; j < tc.count; ++j ){
1732 s = tc.list[j];
1733 DEBUG4("Find_pc_info: tc entry '%s'", s );
1734 if( !Select_pc_info( s, info, 0, names, order, input, depth+1, wildcard ) ){
1735 fatal(LOG_ERR,
1736 "Find_pc_info: tc entry '%s' not found", s);
1737 }
1738 }
1739 Free_line_list(&tc);
1740 if(DEBUGL4)Dump_line_list("Find_pc_info - adding", &l );
1741 for( i = 0; i < l.count; ++i ){
1742 if( (t = l.list[i]) ){
1743 Add_line_list( info, t, Option_value_sep, 1, 1 );
1744 }
1745 }
1746 Free_line_list(&l);
1747 }
1748 Free_line_list(&pc);
1749 }
1750
1751 /*
1752 * variable lists and initialization
1753 */
1754 /***************************************************************************
1755 * Clear_var_list( struct pc_var_list *vars );
1756 * Set the printcap variable value to 0 or null;
1757 ***************************************************************************/
1758
Clear_var_list(struct keywords * v,int setv)1759 void Clear_var_list( struct keywords *v, int setv )
1760 {
1761 char *s;
1762 void *p;
1763 struct keywords *vars;
1764 for( vars = v; vars->keyword; ++vars ){
1765 if( !(p = vars->variable) ) continue;
1766 switch( vars->type ){
1767 case STRING_K:
1768 s = ((char **)p)[0];
1769 if(s)free(s);
1770 ((char **)p)[0] = 0;
1771 break;
1772 case INTEGER_K:
1773 case FLAG_K: ((int *)p)[0] = 0; break;
1774 default: break;
1775 }
1776 if( setv && vars->default_value ){
1777 Config_value_conversion( vars, vars->default_value );
1778 }
1779 }
1780 if(DEBUGL5)Dump_parms("Clear_var_list: after",v );
1781 }
1782
1783 /***************************************************************************
1784 * Set_var_list( struct keywords *vars, struct line_list *values );
1785 * for each name in keywords
1786 * find entry in values
1787 ***************************************************************************/
1788
Set_var_list(struct keywords * keys,struct line_list * values)1789 void Set_var_list( struct keywords *keys, struct line_list *values )
1790 {
1791 struct keywords *vars;
1792 const char *s;
1793
1794 for( vars = keys; vars->keyword; ++vars ){
1795 if( (s = Find_exists_value( values, vars->keyword, Option_value_sep )) ){
1796 Config_value_conversion( vars, s );
1797 }
1798 }
1799 }
1800
1801
1802 /***************************************************************************
1803 * int Check_str_keyword( char *name, int *value )
1804 * - check a string for a simple keyword name
1805 ***************************************************************************/
1806
1807 #define FIXV(S,V) { S, N_(S), INTEGER_K, (void *)0, V, 0,0 }
1808 static struct keywords simple_words[] = {
1809 FIXV( "all", 1 ), FIXV( "yes", 1 ), FIXV( "allow", 1 ), FIXV( "true", 1 ),
1810 FIXV( "no", 0 ), FIXV( "deny", 0 ), FIXV( "false", 0 ),
1811 FIXV( "none", 0 ),
1812 {0,0,0,0,0,0,0}
1813 };
1814
Check_str_keyword(const char * name,int * value)1815 static int Check_str_keyword( const char *name, int *value )
1816 {
1817 struct keywords *keys;
1818 for( keys = simple_words; keys->keyword; ++keys ){
1819 if( !safestrcasecmp( name, keys->keyword ) ){
1820 *value = keys->maxval;
1821 return( 1 );
1822 }
1823 }
1824 return( 0 );
1825 }
1826
1827 /***************************************************************************
1828 * void Config_value_conversion( struct keyword *key, char *value )
1829 * set the value of the variable as required
1830 ***************************************************************************/
Config_value_conversion(struct keywords * key,const char * s)1831 static void Config_value_conversion( struct keywords *key, const char *s )
1832 {
1833 int i = 0, c = 0, value = 0;
1834 char *end; /* end of conversion */
1835 void *p;
1836
1837 DEBUG5("Config_value_conversion: '%s'='%s'", key->keyword, s );
1838 if( !(p = key->variable) ) return;
1839 while(s && isspace(cval(s)) ) ++s;
1840 /*
1841 * we have null str "", "@", "#val", or "=val"
1842 * FLAG 1 0 val!=0 val!=0
1843 * INT 1 0 val val
1844 */
1845 switch( key->type ){
1846 case FLAG_K:
1847 case INTEGER_K:
1848 DEBUG5("Config_value_conversion: int '%s'", s );
1849 i = 1;
1850 if( s && (c=cval(s)) ){
1851 if( c == '@' ){
1852 i = 0;
1853 } else {
1854 /* get rid of leading junk */
1855 while( safestrchr(Option_value_sep,c) ){
1856 ++s;
1857 c = cval(s);
1858 }
1859 if( Check_str_keyword( s, &value ) ){
1860 i = value;
1861 } else {
1862 end = 0;
1863 i = strtol( s, &end, 0 );
1864 if( end == 0 ){
1865 i = 1;
1866 }
1867 }
1868 }
1869 }
1870 ((int *)p)[0] = i;
1871 DEBUG5("Config_value_conversion: setting '%d'", i );
1872 break;
1873 case STRING_K:
1874 end = ((char **)p)[0];
1875 DEBUG5("Config_value_conversion: current value '%s'", end );
1876 if( end ) free( end );
1877 ((char **)p)[0] = 0;
1878 while(s && (c=cval(s)) && safestrchr(Option_value_sep,c) ) ++s;
1879 end = 0;
1880 if( s && *s ){
1881 end = safestrdup(s,__FILE__,__LINE__);
1882 trunc_str(end);
1883 }
1884 ((char **)p)[0] = end;
1885 DEBUG5("Config_value_conversion: setting '%s'", end );
1886 break;
1887 default:
1888 break;
1889 }
1890 }
1891
1892
1893 static struct keywords Keyletter[] = {
1894 { "P", 0, STRING_K, &Printer_DYN, 0,0,0 },
1895 { "Q", 0, STRING_K, &Queue_name_DYN, 0,0,0 },
1896 { "h", 0, STRING_K, &ShortHost_FQDN, 0,0,0 },
1897 { "H", 0, STRING_K, &FQDNHost_FQDN, 0,0,0 },
1898 { "a", 0, STRING_K, &Architecture_DYN, 0,0,0 },
1899 { "R", 0, STRING_K, &RemotePrinter_DYN, 0,0,0 },
1900 { "M", 0, STRING_K, &RemoteHost_DYN, 0,0,0 },
1901 { "D", 0, STRING_K, &Current_date_DYN, 0,0,0 },
1902 { 0,0,0,0,0,0,0 }
1903 };
1904
Expand_percent(char ** var)1905 void Expand_percent( char **var )
1906 {
1907 struct keywords *key;
1908 char *str, *s, *t, *u, **v = var;
1909 int c, len;
1910
1911 if( v == 0 || (str = *v) == 0 || !safestrpbrk(str,"%") ){
1912 return;
1913 }
1914 DEBUG4("Expand_percent: starting '%s'", str );
1915 if( Current_date_DYN == 0 ){
1916 Set_DYN(&Current_date_DYN, Time_str(0,0) );
1917 if( (s = safestrrchr(Current_date_DYN,'-')) ){
1918 *s = 0;
1919 }
1920 }
1921 s = str;
1922 while( (s = safestrpbrk(s,"%")) ){
1923 t = 0;
1924 if( (c = cval(s+1)) && isalpha( c ) ){
1925 for( key = Keyletter; t == 0 && key->keyword; ++key ){
1926 if( (c == key->keyword[0]) ){
1927 t = *(char **)key->variable;
1928 break;
1929 }
1930 }
1931 }
1932 if( t ){
1933 *s = 0;
1934 s += 2;
1935 len = safestrlen(str) + safestrlen(t);
1936 u = str;
1937 str = safestrdup3(str,t,s,__FILE__,__LINE__);
1938 if(u) free(u); u = 0;
1939 s = str+len;
1940 } else {
1941 ++s;
1942 }
1943 }
1944 *v = str;
1945 DEBUG4("Expand_percent: ending '%s'", str );
1946 }
1947
1948 /***************************************************************************
1949 * Expand_vars:
1950 * expand the values of a selected list of strings
1951 * These should be from _DYN
1952 ***************************************************************************/
Expand_vars(void)1953 void Expand_vars( void )
1954 {
1955 void *p;
1956 struct keywords *var;
1957
1958 /* check to see if you need to expand */
1959 for( var = Pc_var_list; var->keyword; ++var ){
1960 if( var->type == STRING_K && (p = var->variable) ){
1961 Expand_percent(p);
1962 }
1963 }
1964 }
1965
1966
1967 /***************************************************************************
1968 * Expand_hash_values:
1969 * expand the values of a hash
1970 ***************************************************************************/
Expand_hash_values(struct line_list * hash)1971 void Expand_hash_values( struct line_list *hash )
1972 {
1973 char *u, *s;
1974 int i;
1975
1976 /* check to see if you need to expand */
1977 for( i = 0; i < hash->count; ++i ){
1978 s = hash->list[i];
1979 if( safestrchr( s, '%' ) ){
1980 u = safestrdup(s,__FILE__,__LINE__);
1981 Expand_percent( &u );
1982 if( s ) free(s); s = 0;
1983 hash->list[i] = u;
1984 }
1985 }
1986 }
1987
1988 /*
1989 * Set a _DYN variable
1990 */
1991
Set_DYN(char ** v,const char * s)1992 char *Set_DYN( char **v, const char *s )
1993 {
1994 char *t = *v;
1995 *v = 0;
1996 if( s && *s ) *v = safestrdup(s,__FILE__,__LINE__);
1997 if( t ) free(t);
1998 return( *v );
1999 }
2000
2001 /*
2002 * Clear the total configuration information
2003 * - we simply remove all dynmically allocated values
2004 */
Clear_config(void)2005 void Clear_config( void )
2006 {
2007 struct line_list **l;
2008
2009 DEBUGF(DDB1)("Clear_config: freeing everything");
2010 Remove_tempfiles();
2011 Clear_tempfile_list();
2012 Clear_var_list( Pc_var_list, 1 );
2013 Clear_var_list( DYN_var_list, 1 );
2014 for( l = Allocs; *l; ++l ) Free_line_list(*l);
2015 }
2016
2017 /***************************************************************************
2018 * void Get_config( char *names )
2019 * gets the configuration information from a list of files
2020 ***************************************************************************/
2021
Get_config(int required,char * path)2022 void Get_config( int required, char *path )
2023 {
2024 int i;
2025 DEBUG1("Get_config: required '%d', '%s'", required, path );
2026 /* void Read_file_list( int required, struct line_list *model, char *str,
2027 * const char *linesep, int sort, const char *keysep, int uniq, int trim,
2028 * int marker, int doinclude, int nocomment, int depth, int maxdepth )
2029 */
2030 Read_file_list( /*required*/required,
2031 /*model*/ &Config_line_list,/*str*/ path,
2032 /*linesep*/Line_ends, /*sort*/1, /*keysep*/Option_value_sep,/*uniq*/1,
2033 /*trim*/':',/*marker*/0,/*doinclude*/1,/*nocomment*/1,
2034 /*depth*/0,/*maxdepth*/4 );
2035 if(DEBUGL4)Dump_line_list("Get_config - before", &Config_line_list );
2036 /*
2037 * fix up the information by removing blanks between the key and values
2038 */
2039 for( i = 0; i < Config_line_list.count; ++i ){
2040 char *s = Config_line_list.list[i];
2041 char *t = safestrpbrk( s, Option_value_sep );
2042 int c;
2043 if( t && (c = cval(t)) && isspace(c) ){
2044 char *e = t+1;
2045 while( isspace(cval(e)) ) ++e;
2046 if( e != t+1 ){
2047 memmove(t+1,e,strlen(e)+1);
2048 }
2049 if( isspace(c) ) *t = '=';
2050 }
2051 }
2052 if(DEBUGL3)Dump_line_list("Get_config - after", &Config_line_list );
2053
2054 Set_var_list( Pc_var_list, &Config_line_list);
2055 Get_local_host();
2056 Expand_vars();
2057 }
2058
2059 /***************************************************************************
2060 * void Reset_config( char *names )
2061 * Resets the configuration and printcap information
2062 ***************************************************************************/
2063
Reset_config(void)2064 void Reset_config( void )
2065 {
2066 DEBUG1("Reset_config: starting");
2067 Clear_var_list( Pc_var_list, 1 );
2068 Free_line_list( &PC_entry_line_list );
2069 Free_line_list( &PC_alias_line_list );
2070 Set_var_list( Pc_var_list, &Config_line_list);
2071 Expand_vars();
2072 }
2073
close_on_exec(int fd)2074 void close_on_exec( int fd )
2075 {
2076 for( ;fd <= Max_fd+10; fd++ ){
2077 (void) close( fd);
2078 }
2079 }
2080
Setup_env_for_process(struct line_list * env,struct job * job)2081 static void Setup_env_for_process( struct line_list *env, struct job *job )
2082 {
2083 struct line_list env_names;
2084 struct passwd *pw;
2085 char *s, *t, *u, *name;
2086 int i;
2087
2088 Init_line_list(&env_names);
2089 if( (pw = getpwuid( getuid())) == 0 ){
2090 logerr_die(LOG_INFO, "setup_envp: getpwuid(%ld) failed", (long)getuid());
2091 }
2092 Set_str_value(env,"PRINTER",Printer_DYN);
2093 Set_str_value(env,"USER",pw->pw_name);
2094 Set_str_value(env,"LOGNAME",pw->pw_name);
2095 Set_str_value(env,"HOME",pw->pw_dir);
2096 Set_str_value(env,"LOGDIR",pw->pw_dir);
2097 Set_str_value(env,"PATH",Filter_path_DYN);
2098 Set_str_value(env,"LD_LIBRARY_PATH",Filter_ld_path_DYN);
2099 Set_str_value(env,"SHELL",Shell_DYN);
2100 Set_str_value(env,"IFS"," \t");
2101
2102 s = getenv( "TZ" ); Set_str_value(env,"TZ",s);
2103 Set_str_value(env,"SPOOL_DIR", Spool_dir_DYN );
2104 if( PC_entry_line_list.count ){
2105 t = Join_line_list_with_sep(&PC_alias_line_list,"|");
2106 s = Join_line_list_with_sep(&PC_entry_line_list,"\n :");
2107 u = safestrdup4(t,(s?"\n :":0),s,"\n",__FILE__,__LINE__);
2108 Expand_percent( &u );
2109 Set_str_value(env, "PRINTCAP_ENTRY",u);
2110 if(s) free(s); s = 0;
2111 if(t) free(t); t = 0;
2112 if(u) free(u); u = 0;
2113 }
2114 if( Ppd_file_DYN ){
2115 Set_str_value(env, "PPD", Ppd_file_DYN);
2116 }
2117 if( job ){
2118 if( (s = Make_job_ticket_image( job )) ){
2119 Set_str_value(env, "HF", s );
2120 free(s); s = 0;
2121 }
2122 if( (s = Find_str_value(&job->info,CF_OUT_IMAGE)) ){
2123 Set_str_value(env, "CONTROL", s );
2124 }
2125 if( (s = Find_str_value(&job->info,DATAFILES)) ){
2126 Set_str_value(env, "DATAFILES", s );
2127 }
2128 }
2129
2130 if( Pass_env_DYN ){
2131 Free_line_list(&env_names);
2132 Split(&env_names,Pass_env_DYN,File_sep,1,Hash_value_sep,1,1,0,0);
2133 for( i = 0; i < env_names.count; ++i ){
2134 name = env_names.list[i];
2135 if( (s = getenv( name )) ){
2136 Set_str_value( env, name, s);
2137 }
2138 }
2139 }
2140 Free_line_list(&env_names);
2141 Check_max(env,1);
2142 env->list[env->count] = 0;
2143 if(DEBUGL1)Dump_line_list("Setup_env_for_process", env );
2144 }
2145
2146 /***************************************************************************
2147 * void Getprintcap_pathlist( char *path )
2148 * Read printcap information from a (semi)colon or comma separated set of files
2149 * or filter specifications
2150 * 1. break path up into set of path names
2151 * 2. read the printcap information into memory
2152 * 3. parse the printcap informormation
2153 ***************************************************************************/
2154
Getprintcap_pathlist(int required,struct line_list * raw,struct line_list * filters,char * path)2155 void Getprintcap_pathlist( int required,
2156 struct line_list *raw, struct line_list *filters,
2157 char *path )
2158 {
2159 struct line_list l;
2160 int i, c;
2161
2162 Init_line_list(&l);
2163 DEBUG2("Getprintcap_pathlist: processing '%s'", path );
2164 Split(&l,path,Strict_file_sep,0,0,0,1,0,0);
2165 for( i = 0; i < l.count; ++i ){
2166 path = l.list[i];
2167 c = path[0];
2168 switch( c ){
2169 case '|':
2170 DEBUG2("Getprintcap_pathlist: filter '%s'", path );
2171 if( filters ) Add_line_list( filters, path, 0, 0, 0 );
2172 break;
2173 case '/':
2174 DEBUG2("Getprintcap_pathlist: file '%s'", path );
2175 /*
2176 void Read_file_list( int required, struct line_list *model, char *str,
2177 const char *linesep, int sort, const char *keysep, int uniq, int trim,
2178 int marker, int doinclude, int nocomment, int depth, int maxdepth )
2179 */
2180 Read_file_list(/*required*/required,/*model*/raw,/*str*/path,
2181 /*linesep*/Line_ends,/*sort*/0,/*keysep*/0,/*uniq*/0,/*trim*/1,
2182 /*marker*/0,/*doinclude*/1,/*nocomment*/1,/*depth*/0,/*maxdepth*/4);
2183 break;
2184 default:
2185 fatal(LOG_ERR,
2186 "Getprintcap_pathlist: entry not filter or absolute pathname '%s'",
2187 path );
2188 }
2189 }
2190 Free_line_list(&l);
2191
2192 if(DEBUGL4){
2193 Dump_line_list( "Getprintcap_pathlist - filters", filters );
2194 Dump_line_list( "Getprintcap_pathlist - info", raw );
2195 }
2196 }
2197
2198 /***************************************************************************
2199 * int Filterprintcap( struct line_list *raw, *filters, char *str )
2200 * - for each entry in the filters list do the following:
2201 * - make the filter, sending it the 'name' for access
2202 * - read from the filter until EOF, adding it to the raw list
2203 * - kill off the filter process
2204 ***************************************************************************/
2205
Filterprintcap(struct line_list * raw,struct line_list * filters,const char * str)2206 void Filterprintcap( struct line_list *raw, struct line_list *filters,
2207 const char *str )
2208 {
2209 int count, n, intempfd, outtempfd;
2210 char *filter;
2211
2212 if( filters->count > 0 ){
2213 intempfd = Make_temp_fd( 0 );
2214 outtempfd = Make_temp_fd( 0 );
2215 if( Write_fd_str( intempfd, str) < 0
2216 || Write_fd_str( intempfd,"\n") < 0 ){
2217 Errorcode = JABORT;
2218 logerr_die(LOG_ERR, "Filterprintcap: Write_fd_str failed");
2219 }
2220 for( count = 0; count < filters->count; ++count ){
2221 filter = filters->list[count];
2222 DEBUG2("Filterprintcap: filter '%s'", filter );
2223 if( lseek(intempfd,0,SEEK_SET) == -1 ){
2224 Errorcode = JABORT;
2225 logerr_die(LOG_ERR, "Filterprintcap: lseek intempfd failed");
2226 }
2227 n = Filter_file(Send_query_rw_timeout_DYN, intempfd, outtempfd, "PC_FILTER",
2228 filter, Filter_options_DYN, 0,
2229 0, 0 );
2230 if( n ){
2231 Errorcode = JABORT;
2232 logerr_die(LOG_ERR, "Filterprintcap: filter '%s' failed", filter);
2233 }
2234 }
2235 if( lseek(outtempfd,0,SEEK_SET) == -1 ){
2236 Errorcode = JABORT;
2237 logerr_die(LOG_ERR, "Filterprintcap: lseek outtempfd failed");
2238 }
2239 Read_fd_and_split( raw,outtempfd,Line_ends,0,0,0,1,1);
2240 /* do not worry if these fail */
2241 close( intempfd); intempfd = -1;
2242 close( outtempfd); outtempfd = -1;
2243 }
2244 }
2245
2246
2247 /***************************************************************************
2248 * int In_group( char* *group, char *user );
2249 * returns 1 on failure, 0 on success
2250 * scan group for user name
2251 * Note: we first check for the group. If there is none, we check for
2252 * wildcard (*) in group name, and then scan only if we need to
2253 ***************************************************************************/
2254
In_group(char * group,char * user)2255 static int In_group( char *group, char *user )
2256 {
2257 struct group *grent;
2258 struct passwd *pwent;
2259 char **members;
2260 int result = 1;
2261
2262 DEBUGF(DDB3)("In_group: checking '%s' for membership in group '%s'", user, group);
2263 if( group == 0 || user == 0 ){
2264 return( result );
2265 }
2266 /* first try getgrnam, see if it is a group */
2267 pwent = getpwnam(user);
2268 if( (grent = getgrnam( group )) ){
2269 DEBUGF(DDB3)("In_group: group id: %ld\n", (long)grent->gr_gid);
2270 if( pwent && ((long)pwent->pw_gid == (long)grent->gr_gid) ){
2271 DEBUGF(DDB3)("In_group: user default group id: %ld\n", (long)pwent->pw_gid);
2272 result = 0;
2273 } else for( members = grent->gr_mem; result && *members; ++members ){
2274 DEBUGF(DDB3)("In_group: member '%s'", *members);
2275 result = (safestrcmp( user, *members ) != 0);
2276 }
2277 }
2278 if( result && safestrchr( group, '*') ){
2279 /* wildcard in group name, scan through all groups */
2280 setgrent();
2281 while( result && (grent = getgrent()) ){
2282 DEBUGF(DDB3)("In_group: group name '%s'", grent->gr_name);
2283 /* now do match against group */
2284 if( Globmatch( group, grent->gr_name ) == 0 ){
2285 if( pwent && ((long)pwent->pw_gid == (long)grent->gr_gid) ){
2286 DEBUGF(DDB3)("In_group: user default group id: %ld\n",
2287 (long)pwent->pw_gid);
2288 result = 0;
2289 } else {
2290 DEBUGF(DDB3)("In_group: found '%s'", grent->gr_name);
2291 for( members = grent->gr_mem; result && *members; ++members ){
2292 DEBUGF(DDB3)("In_group: member '%s'", *members);
2293 result = (safestrcmp( user, *members ) != 0);
2294 }
2295 }
2296 }
2297 }
2298 endgrent();
2299 }
2300 if( result && group[0] == '@' ) { /* look up user in netgroup */
2301 #ifdef HAVE_INNETGR
2302 if( !innetgr( group+1, NULL, user, NULL ) ) {
2303 DEBUGF(DDB3)( "In_group: user %s NOT in netgroup %s", user, group+1 );
2304 } else {
2305 DEBUGF(DDB3)( "In_group: user %s in netgroup %s", user, group+1 );
2306 result = 0;
2307 }
2308 #else
2309 DEBUGF(DDB3)( "In_group: no innetgr() call, netgroups not permitted" );
2310 #endif
2311 }
2312 DEBUGF(DDB3)("In_group: result: %d", result );
2313 return( result );
2314 }
2315
Check_for_rg_group(char * user)2316 int Check_for_rg_group( char *user )
2317 {
2318 int i, match = 0;
2319 struct line_list l;
2320 char *s;
2321
2322 Init_line_list(&l);
2323
2324 s = RestrictToGroupMembers_DYN;
2325 DEBUG3("Check_for_rg_group: name '%s', restricted_group '%s'",
2326 user, s );
2327 if( s ){
2328 match = 1;
2329 Split(&l,s,List_sep,0,0,0,0,0,0);
2330 for( i = 0; match && i < l.count; ++i ){
2331 s = l.list[i];
2332 match = In_group( s, user );
2333 }
2334 }
2335 Free_line_list(&l);
2336 DEBUG3("Check_for_rg_group: result: %d", match );
2337 return( match );
2338 }
2339
2340
2341 /***************************************************************************
2342 * Make_temp_fd( char *name, int namelen )
2343 * 1. we can call this repeatedly, and it will make
2344 * different temporary files.
2345 * 2. we NEVER modify the temporary file name - up to the first '.'
2346 * is the base - we keep adding suffixes as needed.
2347 * 3. Remove_files uses the tempfile information to find and delete temp
2348 * files so be careful.
2349 ***************************************************************************/
2350
2351
Init_tempfile(void)2352 static char *Init_tempfile( void )
2353 {
2354 char *dir = 0, *s;
2355 struct stat statb;
2356
2357 if( Is_server ){
2358 if( dir == 0 ) dir = Spool_dir_DYN;
2359 if( dir == 0 ) dir = Server_tmp_dir_DYN;
2360 } else {
2361 dir = getenv( "LPR_TMP" );
2362 if( dir == 0 ) dir = Default_tmp_dir_DYN;
2363 }
2364 /* remove trailing / */
2365 if( (s = safestrrchr(dir,'/')) && s[1] == 0 ) *s = 0;
2366 if( dir == 0 || stat( dir, &statb ) != 0
2367 || !S_ISDIR(statb.st_mode) ){
2368 fatal(LOG_ERR, "Init_tempfile: bad tempdir '%s'", dir );
2369 }
2370 DEBUG3("Init_tempfile: temp file '%s'", dir );
2371 return( dir );
2372 }
2373
Make_temp_fd_in_dir(char ** temppath,char * dir)2374 int Make_temp_fd_in_dir( char **temppath, char *dir )
2375 {
2376 int tempfd;
2377 struct stat statb;
2378 int len;
2379 char *pathname;
2380
2381 len = 1 + plp_snprintf(NULL, 0, "%s/temp%02dXXXXXX",dir,Tempfiles.count );
2382 pathname = malloc_or_die(len, __FILE__, __LINE__);
2383 plp_snprintf(pathname, len, "%s/temp%02dXXXXXX",dir,Tempfiles.count );
2384 tempfd = mkstemp( pathname );
2385 if( tempfd == -1 ){
2386 Errorcode = JFAIL;
2387 fatal(LOG_INFO, "Make_temp_fd_in_dir: cannot create tempfile '%s'", pathname );
2388 }
2389 Add_line_list(&Tempfiles,pathname,0,0,0);
2390 if( temppath ){
2391 *temppath = Tempfiles.list[Tempfiles.count-1];
2392 }
2393 if( fchmod(tempfd,(Is_server?Spool_file_perms_DYN:0) | 0600 ) == -1 ){
2394 Errorcode = JFAIL;
2395 logerr_die(LOG_INFO, "Make_temp_fd_in_dir: chmod '%s' to 0%o failed ",
2396 pathname, Spool_file_perms_DYN );
2397 }
2398 if( stat(pathname,&statb) == -1 ){
2399 Errorcode = JFAIL;
2400 logerr_die(LOG_INFO, "Make_temp_fd_in_dir: stat '%s' failed ", pathname );
2401 }
2402 DEBUG1("Make_temp_fd_in_dir: fd %d, name '%s'", tempfd, pathname );
2403 free(pathname);
2404 return( tempfd );
2405 }
2406
Make_temp_fd(char ** temppath)2407 int Make_temp_fd( char **temppath )
2408 {
2409 return( Make_temp_fd_in_dir( temppath, Init_tempfile()) );
2410 }
2411
2412 /***************************************************************************
2413 * Clear_tempfile_list()
2414 * - clear the list of tempfiles created for this job
2415 * - this is done by a child process
2416 ***************************************************************************/
Clear_tempfile_list(void)2417 void Clear_tempfile_list(void)
2418 {
2419 Free_line_list(&Tempfiles);
2420 }
2421
2422 /***************************************************************************
2423 * Unlink_tempfiles()
2424 * - remove the tempfiles created for this job
2425 ***************************************************************************/
2426
Unlink_tempfiles(void)2427 void Unlink_tempfiles(void)
2428 {
2429 int i;
2430 for( i = 0; i < Tempfiles.count; ++i ){
2431 DEBUG4("Unlink_tempfiles: unlinking '%s'", Tempfiles.list[i] );
2432 unlink(Tempfiles.list[i]);
2433 }
2434 Free_line_list(&Tempfiles);
2435 }
2436
2437
2438 /***************************************************************************
2439 * Remove_tempfiles()
2440 * - remove the tempfiles created for this job
2441 ***************************************************************************/
2442
Remove_tempfiles(void)2443 void Remove_tempfiles(void)
2444 {
2445 Unlink_tempfiles();
2446 }
2447
2448 /***************************************************************************
2449 * Split_cmd_line
2450 * if we have xx "yy zz" we split this as
2451 * xx
2452 * yy zz
2453 ***************************************************************************/
2454
Split_cmd_line(struct line_list * l,char * line)2455 void Split_cmd_line( struct line_list *l, char *line )
2456 {
2457 char *s = line, *t;
2458 int c;
2459
2460 DEBUG1("Split_cmd_line: line '%s'", line );
2461 while( s && cval(s) ){
2462 while( strchr(Whitespace,cval(s)) ) ++s;
2463 /* ok, we have skipped the whitespace */
2464 if( (c = cval(s)) ){
2465 if( c == '"' || c == '\'' ){
2466 /* we now have hit a quoted string */
2467 ++s;
2468 t = strchr(s,c);
2469 } else if( !(t = strpbrk(s, Whitespace)) ){
2470 t = s+safestrlen(s);
2471 }
2472 if( t ){
2473 c = cval(t);
2474 *t = 0;
2475 Add_line_list(l, s, 0, 0, 0);
2476 *t = c;
2477 if( c ) ++t;
2478 }
2479 s = t;
2480 }
2481 }
2482 if(DEBUGL1){ Dump_line_list("Split_cmd_line", l ); }
2483 }
2484
2485 /***************************************************************************
2486 * Make_passthrough
2487 *
2488 * int Make_passthrough - returns PID of process
2489 * char *line - command line
2490 * char *flags, - additional flags
2491 * struct line_list *passfd, - file descriptors
2492 * struct job *job - job with for option expansion
2493 * struct line_list *env_init - environment
2494 ***************************************************************************/
2495
Make_passthrough(char * line,const char * flags,struct line_list * passfd,struct job * job,struct line_list * env_init)2496 int Make_passthrough( char *line, const char *flags, struct line_list *passfd,
2497 struct job *job, struct line_list *env_init )
2498 {
2499 int c, i, pid = -1, noopts, root, newfd, fd;
2500 struct line_list cmd;
2501 struct line_list env;
2502 char error[SMALLBUFFER];
2503 char *s;
2504
2505 DEBUG1("Make_passthrough: cmd '%s', flags '%s'", line, flags );
2506 if( job ){
2507 s = Find_str_value( &job->info,QUEUENAME );
2508 if( !ISNULL(s) ){
2509 Set_DYN(&Queue_name_DYN,s );
2510 }
2511 }
2512 Init_line_list(&env);
2513 if( env_init ){
2514 Merge_line_list(&env,env_init,Hash_value_sep,1,1);
2515 }
2516 Init_line_list(&cmd);
2517
2518 while( isspace(cval(line)) ) ++line;
2519 if( cval(line) == '|' ) ++line;
2520 noopts = root = 0;
2521 while( cval(line) ){
2522 while( isspace(cval(line)) ) ++line;
2523 if( !safestrncmp(line,"$-", 2)
2524 || !safestrncmp(line,"-$", 2) ){
2525 noopts = 1;
2526 line += 2;
2527 } else if( !safestrncasecmp(line,"root", 4) ){
2528 /* only set to root if it is the LPD server */
2529 root = Is_server;
2530 line += 4;
2531 } else {
2532 break;
2533 }
2534 }
2535
2536 c = cval(line);
2537 if( strpbrk(line, "<>|;") || c == '(' ){
2538 Add_line_list( &cmd, Shell_DYN, 0, 0, 0 );
2539 Add_line_list( &cmd, "-c", 0, 0, 0 );
2540 Add_line_list( &cmd, line, 0, 0, 0 );
2541 if( c != '(' ){
2542 s = cmd.list[cmd.count-1];
2543 s = safestrdup3("( ",s," )",__FILE__,__LINE__);
2544 if( cmd.list[cmd.count-1] ) free( cmd.list[cmd.count-1] );
2545 cmd.list[cmd.count-1] = s;
2546 }
2547 Fix_dollars(&cmd, job, 1, flags);
2548 } else {
2549 Split_cmd_line(&cmd, line);
2550 if( !noopts ){
2551 Split(&cmd, flags, Whitespace, 0,0, 0, 0, 0,0);
2552 }
2553 Fix_dollars(&cmd, job, 0, flags);
2554 }
2555
2556 Check_max(&cmd,1);
2557 cmd.list[cmd.count] = 0;
2558
2559 Setup_env_for_process(&env, job);
2560 if(DEBUGL1){
2561 Dump_line_list("Make_passthrough - cmd",&cmd );
2562 LOGDEBUG("Make_passthrough: fd count %d, root %d", passfd->count, root );
2563 for( i = 0 ; i < passfd->count; ++i ){
2564 fd = Cast_ptr_to_int(passfd->list[i]);
2565 LOGDEBUG(" [%d]=%d",i,fd);
2566 }
2567 Dump_line_list("Make_passthrough - env",&env );
2568 }
2569
2570 c = cmd.list[0][0];
2571 if( c != '/' ){
2572 fatal(LOG_ERR, "Make_passthrough: bad filter - not absolute path name'%s'",
2573 cmd.list[0] );
2574 }
2575 if( (pid = dofork(0)) == -1 ){
2576 logerr_die(LOG_ERR, "Make_passthrough: fork failed");
2577 } else if( pid == 0 ){
2578 for( i = 0; i < passfd->count; ++i ){
2579 fd = Cast_ptr_to_int(passfd->list[i]);
2580 if( fd < i ){
2581 /* we have fd 3 -> 4, but 3 gets wiped out */
2582 do{
2583 newfd = dup(fd);
2584 Max_open(newfd);
2585 if( newfd < 0 ){
2586 Errorcode = JABORT;
2587 logerr_die(LOG_INFO, "Make_passthrough: dup failed");
2588 }
2589 DEBUG4("Make_passthrough: fd [%d] = %d, dup2 -> %d",
2590 i, fd, newfd );
2591 passfd->list[i] = Cast_int_to_voidstar(newfd);
2592 } while( newfd < i );
2593 }
2594 }
2595 if(DEBUGL4){
2596 LOGDEBUG("Make_passthrough: after fixing fd, count %d", passfd->count );
2597 for( i = 0 ; i < passfd->count; ++i ){
2598 fd = Cast_ptr_to_int(passfd->list[i]);
2599 LOGDEBUG(" [%d]=%d",i,fd);
2600 }
2601 }
2602 /* set up full perms for filter */
2603 if( Is_server ){
2604 if( root ){
2605 if( UID_root ) To_euid_root();
2606 } else {
2607 Full_daemon_perms();
2608 }
2609 } else {
2610 Full_user_perms();
2611 }
2612
2613 for( i = 0; i < passfd->count; ++i ){
2614 fd = Cast_ptr_to_int(passfd->list[i]);
2615 if( dup2(fd,i) == -1 ){
2616 plp_snprintf(error,sizeof(error),
2617 "Make_passthrough: pid %ld, dup2(%d,%d) failed", (long)getpid(), fd, i );
2618 Write_fd_str(2,error);
2619 exit(JFAIL);
2620 }
2621 }
2622 close_on_exec(passfd->count);
2623 execve(cmd.list[0],cmd.list,env.list);
2624 plp_snprintf(error,sizeof(error),
2625 "Make_passthrough: pid %ld, execve '%s' failed - '%s'\n", (long)getpid(),
2626 cmd.list[0], Errormsg(errno) );
2627 Write_fd_str(2,error);
2628 exit(JABORT);
2629 }
2630 passfd->count = 0;
2631 Free_line_list(passfd);
2632 Free_line_list(&env);
2633 Free_line_list(&cmd);
2634 return( pid );
2635 }
2636
2637 /*
2638 * Filter_file: we filter a file through this program
2639 * input_fd = input file descriptor. if -1, then we make it /dev/null
2640 * tempfile = name of tempfile for output
2641 * error_header = header used for error messages from filter
2642 * pgm = program
2643 * filter_options = options for filter
2644 * job = job we are doing the work for
2645 * env = environment options we want to pass
2646 * RETURN:
2647 * exit status of the filter, adjusted to be in the JXXX status
2648 * if it exits with error status, we get JSIGNAL
2649 */
2650
Filter_file(int timeout,int input_fd,int output_fd,const char * error_header,char * pgm,const char * filter_options,struct job * job,struct line_list * env,int verbose)2651 int Filter_file( int timeout, int input_fd, int output_fd, const char *error_header,
2652 char *pgm, const char * filter_options, struct job *job,
2653 struct line_list *env, int verbose )
2654 {
2655 int innull_fd, outnull_fd, pid, len, n;
2656 char *s;
2657 int of_error[2];
2658 plp_status_t status;
2659 struct line_list files;
2660 char buffer[SMALLBUFFER];
2661
2662 Init_line_list( &files );
2663
2664 of_error[0] = of_error[1] = -1;
2665
2666 innull_fd = input_fd;
2667 if( innull_fd < 0 && (innull_fd = open("/dev/null", O_RDWR )) < 0 ){
2668 Errorcode = JFAIL;
2669 logerr_die(LOG_INFO, "Filter_file: open /dev/null failed");
2670 }
2671 Max_open(innull_fd);
2672
2673 outnull_fd = output_fd;
2674 if( outnull_fd < 0 && (outnull_fd = open("/dev/null", O_RDWR )) < 0 ){
2675 Errorcode = JFAIL;
2676 logerr_die(LOG_INFO, "Filter_file: open /dev/null failed");
2677 }
2678 Max_open(outnull_fd);
2679
2680 if( pipe( of_error ) == -1 ){
2681 Errorcode = JFAIL;
2682 logerr_die(LOG_INFO, "Filter_file: pipe() failed");
2683 }
2684 Max_open(of_error[0]); Max_open(of_error[1]);
2685 DEBUG3("Filter_file: fd of_error[%d,%d]", of_error[0], of_error[1] );
2686
2687 Check_max(&files, 10 );
2688 files.list[files.count++] = Cast_int_to_voidstar(innull_fd); /* stdin */
2689 files.list[files.count++] = Cast_int_to_voidstar(outnull_fd); /* stdout */
2690 files.list[files.count++] = Cast_int_to_voidstar(of_error[1]); /* stderr */
2691 if( (pid = Make_passthrough( pgm, filter_options, &files, job, env )) < 0 ){
2692 Errorcode = JFAIL;
2693 logerr_die(LOG_INFO, "Filter_file: could not create process '%s'", pgm);
2694 }
2695 files.count = 0;
2696 Free_line_list(&files);
2697
2698 if( input_fd < 0 ) close(innull_fd); innull_fd = -1;
2699 if( output_fd < 0 ) close(outnull_fd); outnull_fd = -1;
2700 if( (close(of_error[1]) == -1 ) ){
2701 Errorcode = JFAIL;
2702 logerr_die(LOG_INFO, "Filter_file: X8 close(%d) failed",
2703 of_error[1]);
2704 }
2705 of_error[1] = -1;
2706 buffer[0] = 0;
2707 len = 0;
2708 while( len < (int)sizeof(buffer)-1
2709 && (n = Read_fd_len_timeout(timeout, of_error[0],buffer+len,sizeof(buffer)-len-1)) >0 ){
2710 buffer[n+len] = 0;
2711 while( (s = safestrchr(buffer,'\n')) ){
2712 *s++ = 0;
2713 setstatus(job, "%s: %s", error_header, buffer );
2714 memmove(buffer,s,safestrlen(s)+1);
2715 }
2716 len = safestrlen(buffer);
2717 }
2718 if( buffer[0] ){
2719 setstatus(job, "%s: %s", error_header, buffer );
2720 }
2721 if( (close(of_error[0]) == -1 ) ){
2722 Errorcode = JFAIL;
2723 logerr_die(LOG_INFO, "Filter_file: X8 close(%d) failed",
2724 of_error[0]);
2725 }
2726 of_error[0] = -1;
2727 while( (n = plp_waitpid(pid,&status,0)) != pid ){
2728 int err = errno;
2729 DEBUG1("Filter_file: waitpid(%d) returned %d, err '%s'",
2730 pid, n, Errormsg(err) );
2731 if( err == EINTR ) continue;
2732 Errorcode = JABORT;
2733 logerr_die(LOG_ERR, "Filter_file: waitpid(%d) failed", pid);
2734 }
2735 DEBUG1("Filter_file: pid %d, exit status '%s'", pid, Decode_status(&status) );
2736 n = 0;
2737 if( WIFSIGNALED(status) ){
2738 Errorcode = JFAIL;
2739 logerr_die(LOG_INFO, "Filter_file: pgm '%s' died with signal %d, '%s'",
2740 pgm, n, Sigstr(n));
2741 }
2742 n = WEXITSTATUS(status);
2743 if( n > 0 && n < 32 ) n+=(JFAIL-1);
2744 DEBUG1("Filter_file: final status '%s'", Server_status(n) );
2745 if( verbose ){
2746 setstatus(job, "Filter_file: pgm '%s' exited with status '%s'", pgm, Server_status(n));
2747 }
2748 return( n );
2749 }
2750
2751 #define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2752 #define LOWER "abcdefghijklmnopqrstuvwxyz"
2753 #define DIGIT "01234567890"
2754 #define SAFE "-_."
2755 #define LESS_SAFE SAFE "@/:()=,+-%"
2756
Is_clean_name(char * s)2757 char *Is_clean_name( char *s )
2758 {
2759 int c;
2760 if( s ){
2761 for( ; (c = cval(s)); ++s ){
2762 if( !(isalnum(c) || safestrchr( SAFE, c )) ) return( s );
2763 }
2764 }
2765 return( 0 );
2766 }
2767
Clean_name(char * s)2768 void Clean_name( char *s )
2769 {
2770 int c;
2771 if( s ){
2772 for( ; (c = cval(s)); ++s ){
2773 if( !(isalnum(c) || safestrchr( SAFE, c )) ) *s = '_';
2774 }
2775 }
2776 }
2777
2778 /*
2779 * Find a possible bad character in a line
2780 */
2781
Is_meta(int c)2782 static int Is_meta( int c )
2783 {
2784 return( !( isspace(c) || isalnum( c )
2785 || (Safe_chars_DYN && safestrchr(Safe_chars_DYN,c))
2786 || safestrchr( LESS_SAFE, c ) ) );
2787 }
2788
Find_meta(char * s)2789 static char *Find_meta( char *s )
2790 {
2791 int c = 0;
2792 if( s ){
2793 for( ; (c = cval(s)); ++s ){
2794 if( Is_meta( c ) ) return( s );
2795 }
2796 s = 0;
2797 }
2798 return( s );
2799 }
2800
Clean_meta(char * t)2801 void Clean_meta( char *t )
2802 {
2803 char *s = t;
2804 if( t ){
2805 while( (s = safestrchr(s,'\\')) ) *s = '/';
2806 s = t;
2807 for( s = t; (s = Find_meta( s )); ++s ){
2808 *s = '_';
2809 }
2810 }
2811 }
2812
2813 /**********************************************************************
2814 * Dump_parms( char *title, struct keywords *k )
2815 * - dump the list of keywords and variable values given by the
2816 * entries in the array.
2817 **********************************************************************/
2818
Dump_parms(const char * title,struct keywords * k)2819 void Dump_parms( const char *title, struct keywords *k )
2820 {
2821 char *s;
2822 void *p;
2823 int v;
2824
2825 if( title ) LOGDEBUG( "*** Current Values '%s' ***", title );
2826 for( ; k && k->keyword; ++k ){
2827 if( !(p = k->variable) ) continue;
2828 switch(k->type){
2829 case FLAG_K:
2830 v = *(int *)(p);
2831 LOGDEBUG( " %s FLAG %d", k->keyword, v);
2832 break;
2833 case INTEGER_K:
2834 v = *(int *)(p);
2835 LOGDEBUG( " %s# %d (0x%x, 0%o)", k->keyword,v,v,v);
2836 break;
2837 case STRING_K:
2838 s = *(char **)(p);
2839 if( s ){
2840 LOGDEBUG( " %s= '%s'", k->keyword, s );
2841 } else {
2842 LOGDEBUG( " %s= <NULL>", k->keyword );
2843 }
2844 break;
2845 default:
2846 LOGDEBUG( " %s: UNKNOWN TYPE", k->keyword );
2847 }
2848 }
2849 if( title ) LOGDEBUG( "*** <END> ***");
2850 }
2851
2852
2853 /**********************************************************************
2854 * Dump_parms( char *title, struct keywords *k )
2855 * - dump the list of keywords and variable values given by the
2856 * entries in the array.
2857 **********************************************************************/
2858
Dump_default_parms(int fd,const char * title,struct keywords * k)2859 void Dump_default_parms( int fd, const char *title, struct keywords *k )
2860 {
2861 const char *def, *key;
2862 char buffer[2*SMALLBUFFER];
2863 int n;
2864
2865 if( title ){
2866 plp_snprintf(buffer,sizeof(buffer), "%s\n", title );
2867 Write_fd_str(fd, buffer);
2868 }
2869 for( ; k && k->keyword; ++k ){
2870 n = 0;
2871 key = k->keyword;
2872 def = k->default_value;
2873 switch(k->type){
2874 case FLAG_K:
2875 if( def ){
2876 if( cval(def) == '=' ) ++def;
2877 n = strtol(def,0,0);
2878 }
2879 plp_snprintf(buffer,sizeof(buffer), " :%s%s\n", key, n?"":"@");
2880 break;
2881 case INTEGER_K:
2882 if( def ){
2883 if( cval(def) == '=' ) ++def;
2884 n = strtol(def,0,0);
2885 }
2886 plp_snprintf(buffer,sizeof(buffer), " :%s=%d\n", key, n);
2887 break;
2888 case STRING_K:
2889 if( def ){
2890 if( cval(def) == '=' ) ++def;
2891 } else {
2892 def = "";
2893 }
2894 plp_snprintf(buffer,sizeof(buffer), " :%s=%s\n", key, def);
2895 break;
2896 default:
2897 plp_snprintf(buffer,sizeof(buffer), "# %s UNKNOWN\n", key);
2898 }
2899 Write_fd_str(fd, buffer);
2900 }
2901 Write_fd_str(fd, "\n");
2902 }
2903
2904
2905 /***************************************************************************
2906 *char *Fix_Z_opts( struct job *job )
2907 *
2908 * fix the -Z option value
2909 * Remove_Z_DYN - remove these from the Z string
2910 * Prefix_Z_DYN - put these at the start
2911 * Append_Z_DYN - put these at the end
2912 * Prefix_option_to_option - prefix options to start of option
2913 * OS Z -> O and S to Z
2914 * Z S -> Z to S
2915 ***************************************************************************/
2916
Fix_Z_opts(struct job * job)2917 void Fix_Z_opts( struct job *job )
2918 {
2919 char *str, *s, *pattern, *start, *end;
2920 char buffer[16];
2921 struct line_list l;
2922 int i, c, n;
2923
2924 Init_line_list(&l);
2925 str = Find_str_value( &job->info,"Z" );
2926 DEBUG4("Fix_Z_opts: initially '%s', remove '%s', append '%s', prefix '%s'",
2927 str, Remove_Z_DYN, Append_Z_DYN, Prefix_Z_DYN );
2928 DEBUG4("Fix_Z_opts: prefix_options '%s'", Prefix_option_to_option_DYN );
2929 if( Prefix_option_to_option_DYN ){
2930 s = Prefix_option_to_option_DYN;
2931 while( s && *s ){
2932 if( !isalpha(cval(s)) ){
2933 memmove(s,s+1,safestrlen(s+1)+1);
2934 } else {
2935 ++s;
2936 }
2937 }
2938 s = Prefix_option_to_option_DYN;
2939 /* now we have the fixed value */
2940 DEBUG4("Fix_Z_opts: prefix_options fixed '%s'", s);
2941 n = safestrlen(s);
2942 if( n < 2 ){
2943 fatal(LOG_ERR, "Fix_Z_opts: not enough letters '%s'", s );
2944 }
2945 /* find the starting values */
2946 str = 0;
2947 buffer[1] = 0;
2948 for( i = 0; i < n-1; ++i ){
2949 buffer[0] = s[i];
2950 if( (start = Find_str_value(&job->info,buffer)) ){
2951 str= safeextend2(str,start, __FILE__,__LINE__);
2952 Set_str_value(&job->info,buffer,0);
2953 }
2954 }
2955 /* do we need to prefix it? */
2956 if( str ){
2957 buffer[0] = s[i];
2958 start = Find_str_value(&job->info,buffer);
2959 /* put at start */
2960 start= safestrdup3(str,(start?",":""),start,
2961 __FILE__,__LINE__);
2962 Set_str_value(&job->info, buffer, start );
2963 if( start ) free(start); start = 0;
2964 }
2965 if( str ) free(str); str = 0;
2966 }
2967 str = Find_str_value( &job->info,"Z" );
2968 DEBUG4("Fix_Z_opts: after Prefix_option_to_option '%s'", str );
2969 if( Remove_Z_DYN && str ){
2970 /* remove the various options - split on commas */
2971 Split(&l, Remove_Z_DYN, ",", 0, 0, 0, 0, 0,0);
2972 for( i = 0; i < l.count; ++i ){
2973 pattern = l.list[i];
2974 DEBUG4("Fix_Z_opts: REMOVE pattern '%s'", pattern );
2975 for( start = str; start && *start; start = end ){
2976 c = 0;
2977 if( !(end = strpbrk(start,",")) ){
2978 end = start+safestrlen(start);
2979 }
2980 c = *end;
2981 *end = 0;
2982 /* now we have the option */
2983 DEBUG4("Fix_Z_opts: str '%s'", start );
2984 if( !Globmatch( pattern, start) ){
2985 /* move the values up in the string, end -> ',' */
2986 if( c ){
2987 memmove( start,end+1, safestrlen(end+1)+1);
2988 } else {
2989 *start = 0;
2990 }
2991 end = start;
2992 } else {
2993 *end = c;
2994 if( c ) ++end;
2995 }
2996 }
2997 }
2998 Free_line_list(&l);
2999 }
3000 DEBUG4("Fix_Z_opts: after remove '%s'", str );
3001 if( Append_Z_DYN && *Append_Z_DYN ){
3002 s = safestrdup3(str,",",Append_Z_DYN,__FILE__,__LINE__);
3003 Set_str_value(&job->info,"Z",s);
3004 str = Find_str_value(&job->info,"Z");
3005 if(s) free(s); s = 0;
3006 }
3007 DEBUG4("Fix_Z_opts: after append '%s'", str );
3008 if( Prefix_Z_DYN && *Prefix_Z_DYN ){
3009 s = safestrdup3(Prefix_Z_DYN,",",str,__FILE__,__LINE__);
3010 Set_str_value(&job->info,"Z",s);
3011 str = Find_str_value(&job->info,"Z");
3012 if(s) free(s); s = 0;
3013 }
3014 DEBUG4("Fix_Z_opts: after Prefix_Z '%s'", str );
3015 for( s = safestrchr(str,','); s; s = strchr(s,',') ){
3016 if( cval(s+1) == ',' ){
3017 memmove(s,s+1,safestrlen(s+1)+1);
3018 } else {
3019 ++s;
3020 }
3021 }
3022 if( str ){
3023 if( cval(str) == ',' ){
3024 memmove(str,str+1,safestrlen(str+1)+1);
3025 }
3026 if( (n = safestrlen(str)) && cval(str+n-1) == ',' ) str[n-1] = 0;
3027 }
3028 DEBUG4("Fix_Z_opts: final Z '%s'", str );
3029 Free_line_list(&l);
3030 }
3031
3032
3033 /***************************************************************************
3034 * void Fix_dollars( struct line_list *l, struct job *job,
3035 * int nosplit, char *flags )
3036 * Note: see the code for the keys!
3037 * replace
3038 * \x with x except for \r,\n,\t, -> space
3039 * \nnn with nnn
3040 * $* with flag string, and then evaluate options
3041 * $X with -X<value>
3042 * $0X with -X <value>
3043 * $-X with <value>
3044 * $0-X with <value> (same as $-X)
3045 * ${s} with value of control file parameter s (must be upper case)
3046 * ${ss} with value of printcap option ss
3047 * $'{ss} with quoted value of printcap option ss
3048 *
3049 * nosplit - do not split the option value over two entries
3050 * flags - flags to use for $*
3051 ***************************************************************************/
3052
Fix_dollars(struct line_list * l,struct job * job,int nosplit,const char * flags)3053 void Fix_dollars( struct line_list *l, struct job *job, int nosplit, const char *flags )
3054 {
3055 int i, j, count, space, notag, kind, n, c, position, quote;
3056 const char *str;
3057 char *strv, *s, *t, *rest;
3058 char buffer[SMALLBUFFER], tag[32];
3059
3060 if(DEBUGL4)Dump_line_list("Fix_dollars- before", l );
3061 for( count = 0; count < l->count; ++count ){
3062 position = 0;
3063 for( strv = l->list[count]; (s = safestrpbrk(strv+position,"$\\")); ){
3064 DEBUG4("Fix_dollars: expanding [%d]='%s'", count, strv );
3065 position = s - strv;
3066 c = cval(s);
3067 *s++ = 0;
3068 if( c == '\\' ){
3069 c = *s++;
3070 /* check for end of string */
3071 if( c == 0 ) break;
3072 if( c == 'r' || c == 'n' || c == 't' ){
3073 c = ' ';
3074 } else if( isdigit( c ) ){
3075 tag[0] = c;
3076 if( (tag[1] = *s) ) ++s;
3077 if( (tag[2] = *s) ) ++s;
3078 tag[3] = 0;
3079 c = strtol( tag, 0, 8 );
3080 }
3081 if( !isprint(c) || isspace(c) ) c = ' ';
3082 strv[position] = c;
3083 ++position;
3084 memmove(strv+position,s,safestrlen(s)+1);
3085 continue;
3086 }
3087 /* now we handle the $ */
3088 str = 0;
3089 rest = 0;
3090 n = space = notag = quote = 0;
3091 kind = STRING_K;
3092 while( (c = cval(s)) && safestrchr( " 0-'", c) ){
3093 switch( c ){
3094 case '0': case ' ': space = 1; break;
3095 case '-': notag = 1; break;
3096 case '\'': quote = 1; break;
3097 default: break;
3098 }
3099 ++s;
3100 }
3101 rest = s+1;
3102 if( c == '*' ){
3103 if( flags && *flags ){
3104 rest = safestrdup(rest,__FILE__,__LINE__);
3105 position = safestrlen(strv);
3106 l->list[count] = strv
3107 = safeextend3(strv,flags,rest,__FILE__,__LINE__);
3108 if( rest ) free(rest); rest = 0;
3109 }
3110 continue;
3111 } else if( c == '{' ){
3112 ++s;
3113 if( !(rest = safestrchr(rest,'}')) ){
3114 break;
3115 }
3116 *rest++ = 0;
3117 if( !cval(s+1) && isupper(cval(s)) ){
3118 str = job?Find_str_value( &job->info,s):0;
3119 } else {
3120 str = Find_value( &PC_entry_line_list, s );
3121 }
3122 notag = 1;
3123 space = 0;
3124 } else {
3125 quote = 0;
3126 switch( c ){
3127 case 'a':
3128 str = Accounting_file_DYN;
3129 if( str && cval(str) == '|' ) str = 0;
3130 break;
3131 case 'b': str = job?Find_str_value(&job->info,SIZE):0; break;
3132 case 'c':
3133 notag = 1; space=0;
3134 t = job?Find_str_value(&job->info,FORMAT):0;
3135 if( t && *t == 'l'){
3136 str="-c";
3137 }
3138 break;
3139 case 'd': str = Spool_dir_DYN; break;
3140 case 'e':
3141 str = job?Find_str_value(&job->info, DF_NAME):0;
3142 break;
3143 case 'f':
3144 str = job?Find_str_value(&job->info,"N"):0;
3145 break;
3146 case 'h':
3147 str = job?Find_str_value(&job->info,FROMHOST):0;
3148 break;
3149 case 'i':
3150 str = job?Find_str_value(&job->info,"I"):0;
3151 break;
3152 case 'j':
3153 str = job?Find_str_value(&job->info,NUMBER):0;
3154 break;
3155 case 'k':
3156 str = job?Find_str_value(&job->info,XXCFTRANSFERNAME):0;
3157 break;
3158 case 'l':
3159 kind = INTEGER_K; n = Page_length_DYN; break;
3160 case 'n':
3161 str = job?Find_str_value(&job->info,LOGNAME):0;
3162 break;
3163 case 'p': str = RemotePrinter_DYN; break;
3164 case 'r': str = RemoteHost_DYN; break;
3165 case 's': str = Status_file_DYN; break;
3166 case 't':
3167 str = Time_str( 0, time( (void *)0 ) ); break;
3168 case 'w': kind = INTEGER_K; n = Page_width_DYN; break;
3169 case 'x': kind = INTEGER_K; n = Page_x_DYN; break;
3170 case 'y': kind = INTEGER_K; n = Page_y_DYN; break;
3171 case 'F':
3172 str = job?Find_str_value(&job->info,FORMAT):0;
3173 break;
3174 case 'P': str = Printer_DYN; break;
3175 case 'S': str = Comment_tag_DYN; break;
3176 /* case '_': str = esc_Auth_client_id_DYN; break; */
3177 default:
3178 if( isupper(c) ){
3179 buffer[1] = 0; buffer[0] = c;
3180 str = job?Find_str_value( &job->info,buffer):0;
3181 }
3182 break;
3183 }
3184 }
3185 buffer[0] = 0;
3186 tag[0] = 0;
3187 switch( kind ){
3188 case INTEGER_K:
3189 plp_snprintf(buffer,sizeof(buffer), "%d", n );
3190 str = buffer;
3191 break;
3192 }
3193 DEBUG4(
3194 "Fix_dollars: strv '%s', found '%s', rest '%s', notag %d, space %d",
3195 strv, str, rest, notag, space );
3196 tag[0] = 0;
3197 if( str && !cval(str) ) str = 0;
3198 if( quote && !str ) str = "";
3199 if( str ){
3200 rest = safestrdup(rest,__FILE__,__LINE__);
3201 if( notag ){
3202 space = 0;
3203 } else {
3204 i = 0;
3205 if( (quote || nosplit) && !space ) tag[i++] = '\'';
3206 tag[i++] = '-'; tag[i++] = c; tag[i++] = 0;
3207 l->list[count] = strv = safeextend2( strv, tag, __FILE__,__LINE__ );
3208 if( !(quote || nosplit) ) tag[0] = 0;
3209 tag[1] = 0;
3210 }
3211 if( space ){
3212 DEBUG4("Fix_dollars: space [%d]='%s'", count, l->list[count] );
3213 if( quote || nosplit ){
3214 position = safestrlen(strv) + safestrlen(str) + 2;
3215 l->list[count] =
3216 strv = safeextend5( strv," '",str,"'",rest,__FILE__,__LINE__);
3217 } else {
3218 Check_max(l,2);
3219 for( i = l->count; i >= count; --i ){
3220 l->list[i+1] = l->list[i];
3221 }
3222 ++l->count;
3223 ++count;
3224 l->list[count] = strv = safestrdup2(str,rest,__FILE__,__LINE__);
3225 position = safestrlen(str);
3226 }
3227 } else {
3228 position = safestrlen(strv) + safestrlen(str)+safestrlen(tag);
3229 l->list[count] = strv
3230 = safeextend4(strv,str,tag,rest,__FILE__,__LINE__);
3231 }
3232 if( rest ) free(rest); rest = 0;
3233 } else {
3234 memmove(strv+position,rest,safestrlen(rest)+1);
3235 }
3236 DEBUG4("Fix_dollars: [%d]='%s'", count, strv );
3237 }
3238 }
3239 for( i = j = 0; i < l->count; ++i ){
3240 if( (s = l->list[i]) && *s == 0 ){
3241 free(s); s = 0;
3242 }
3243 l->list[j] = s;
3244 if( s ) ++j;
3245 }
3246 l->count = j;
3247 if(DEBUGL4)Dump_line_list("Fix_dollars- after", l );
3248 }
3249
3250 /*
3251 * char *Make_pathname( char *dir, char *file )
3252 * - makes a full pathname from the dir and file part
3253 */
3254
Make_pathname(const char * dir,const char * file)3255 char *Make_pathname( const char *dir, const char *file )
3256 {
3257 char *s, *path;
3258 if( file == 0 ){
3259 path = 0;
3260 } else if( file[0] == '/' ){
3261 path = safestrdup(file,__FILE__,__LINE__);
3262 } else if( dir ){
3263 path = safestrdup3(dir,"/",file,__FILE__,__LINE__);
3264 } else {
3265 path = safestrdup2("./",file,__FILE__,__LINE__);
3266 }
3267 if( (s = path) ) while((s = strstr(s,"//"))) memmove(s,s+1,safestrlen(s)+1 );
3268 return(path);
3269 }
3270
3271 /***************************************************************************
3272 * Get_keywords and keyval
3273 * - decode the control word and return a key
3274 ***************************************************************************/
3275
Get_keyval(char * s,struct keywords * controlwords)3276 int Get_keyval( char *s, struct keywords *controlwords )
3277 {
3278 int i;
3279 const char *t;
3280 for( i = 0; controlwords[i].keyword; ++i ){
3281 if(
3282 safestrcasecmp( s, controlwords[i].keyword ) == 0
3283 || ( (t = controlwords[i].translation) && safestrcasecmp( s, _(t) ) == 0)
3284 ){
3285 return( controlwords[i].type );
3286 }
3287 }
3288 return( 0 );
3289 }
3290
Get_keystr(int c,struct keywords * controlwords)3291 const char *Get_keystr( int c, struct keywords *controlwords )
3292 {
3293 int i;
3294 for( i = 0; controlwords[i].keyword; ++i ){
3295 if( controlwords[i].type == c ){
3296 return( controlwords[i].keyword );
3297 }
3298 }
3299 return( 0 );
3300 }
3301
Escape(const char * str,int level)3302 char *Escape( const char *str, int level )
3303 {
3304 char *s = 0;
3305 int i, c, j, k, incr = 3*level;
3306 int len = 0;
3307
3308 if( str == 0 || *str == 0 ) return(0);
3309 if( level <= 0 ) level = 1;
3310
3311 len = safestrlen(str);
3312 for( j = 0; (c = cval(str+j)); ++j ){
3313 if( c != ' ' && !isalnum( c ) ){
3314 len += incr;
3315 }
3316 }
3317 DEBUG5("Escape: level %d, allocated length %d, length %d, for '%s'",
3318 level, len, safestrlen(str), str );
3319 s = malloc_or_die(len+1,__FILE__,__LINE__);
3320 i = 0;
3321 for( i = j = 0; (c = cval(str+j)); ++j ){
3322 if( c == ' ' ){
3323 s[i++] = '?';
3324 } else if( !isalnum( c ) ){
3325 plp_snprintf(s+i,4, "%%%02x",c);
3326 /* we encode the % as %25 and move the other stuff over */
3327 for( k = 1; k < level; ++k ){
3328 /* we move the stuff after the % two positions */
3329 /* s+i is the %, s+i+1 is the first digit */
3330 memmove(s+i+3, s+i+1, safestrlen(s+i+1)+1);
3331 memmove(s+i+1, "25", 2 );
3332 }
3333 i += safestrlen(s+i);
3334 } else {
3335 s[i++] = c;
3336 }
3337 }
3338 s[i] = 0;
3339 DEBUG5("Escape: final length %d '%s'", i, s );
3340 return(s);
3341 }
3342
3343 /*
3344 * we replace a colon by \072 in a dynmaically allocated string
3345 */
3346
Escape_colons(struct line_list * list)3347 void Escape_colons( struct line_list *list )
3348 {
3349 int linenumber, len, c;
3350 char *str, *s, *t, *newstr;
3351
3352 for( linenumber = 0; list && linenumber < list->count; ++linenumber ){
3353 str = list->list[linenumber];
3354
3355 if( str == 0 || strchr(str,':') == 0 ) continue;
3356
3357 len = safestrlen(str);
3358 for( s = str; (s = strchr(s,':')); ++s ){
3359 len += 4;
3360 }
3361 DEBUG4("Escape_colons: new length %d for '%s'",
3362 len, str );
3363 newstr = t = malloc_or_die(len+1,__FILE__,__LINE__);
3364 for( s = str; (c = cval(s)); ++s ){
3365 if( c != ':' ){
3366 *t++ = c;
3367 } else {
3368 strcpy(t,"\\072");
3369 t += 4;
3370 }
3371 }
3372 *t = 0;
3373 free(str);
3374 list->list[linenumber] = newstr;
3375 DEBUG4("Escape_colons: '%s'", newstr );
3376 }
3377 }
3378
Unescape(char * str)3379 void Unescape( char *str )
3380 {
3381 int i, c;
3382 char *s = str;
3383 char buffer[4];
3384 if( str == 0 ) return;
3385 for( i = 0; (c = cval(str)); ++str ){
3386 if( c == '?' ){
3387 c = ' ';
3388 } else if( c == '%'
3389 && (buffer[0] = cval(str+1))
3390 && (buffer[1] = cval(str+2))
3391 ){
3392 buffer[2] = 0;
3393 c = strtol(buffer,0,16);
3394 str += 2;
3395 }
3396 s[i++] = c;
3397 }
3398 s[i] = 0;
3399 DEBUG5("Unescape '%s'", s );
3400 }
3401
3402 /***************************************************************************
3403 * int Fix_str( char * str )
3404 * - make a copy of the original string
3405 * - substitute all the escape characters
3406 * \f, \n, \r, \t, and \nnn
3407 ***************************************************************************/
3408
Fix_str(char * str)3409 char *Fix_str( char *str )
3410 {
3411 char *s, *end, *dupstr, buffer[4];
3412 int c, len;
3413 DEBUG3("Fix_str: '%s'", str );
3414 if( str == 0 ) return(str);
3415 dupstr = s = safestrdup(str,__FILE__,__LINE__);
3416 DEBUG3("Fix_str: dup '%s', 0x%lx", dupstr, Cast_ptr_to_long(dupstr) );
3417 for( ; (s = safestrchr(s,'\\')); ){
3418 end = s+1;
3419 c = cval(end);
3420 /* check for \nnn */
3421 if( isdigit( c ) ){
3422 for( len = 0; len < 3; ++len ){
3423 if( !isdigit(cval(end)) ){
3424 break;
3425 }
3426 buffer[len] = *end++;
3427 }
3428 c = strtol(buffer,0,8);
3429 } else {
3430 switch( c ){
3431 case 'f': c = '\f'; break;
3432 case 'r': c = '\r'; break;
3433 case 'n': c = '\n'; break;
3434 case 't': c = '\t'; break;
3435 }
3436 ++end;
3437 }
3438 s[0] = c;
3439 if( c == 0 ) break;
3440 memcpy(s+1,end,safestrlen(end)+1);
3441 ++s;
3442 }
3443 if( *dupstr == 0 ){ free(dupstr); dupstr = 0; }
3444 DEBUG3( "Fix_str: final str '%s' -> '%s'", str, dupstr );
3445 return( dupstr );
3446 }
3447
3448 /***************************************************************************
3449 * int Shutdown_or_close( int fd )
3450 * - if the file descriptor is a socket, then do a shutdown (write), return fd;
3451 * or if the
3452 * - otherwise close it and return -1;
3453 ***************************************************************************/
3454
Shutdown_or_close(int fd)3455 int Shutdown_or_close( int fd )
3456 {
3457 struct stat statb;
3458
3459 if( fd < 0 || fstat( fd, &statb ) == -1 ){
3460 fd = -1;
3461 } else if( Backwards_compatible_DYN || !Half_close_DYN
3462 || !(S_ISSOCK(statb.st_mode)) || shutdown( fd, 1 ) == -1 ){
3463 close(fd);
3464 fd = -1;
3465 }
3466 return( fd );
3467 }
3468
3469 /* change the format of the output of a filter
3470 * bq_format=IoIo...D
3471 * I is input type or '*' for all types
3472 * o is output type
3473 * D is default
3474 * If no default, preserve the original type
3475 */
3476
3477 /* moved here from lpd_jobs.c to avoid the whole file sucked into lpr - brl */
Fix_bq_format(int format,struct line_list * datafile)3478 void Fix_bq_format( int format, struct line_list *datafile )
3479 {
3480 char fmt[2], *s;
3481 fmt[0] = format; fmt[1] = 0;
3482 if( (s = Bounce_queue_format_DYN) ){
3483 lowercase( s );
3484 while( s[0] ){
3485 if( s[1] ){
3486 if( format == cval(s) || cval(s) == '*' ){
3487 fmt[0] = s[1];
3488 break;
3489 }
3490 } else {
3491 if( cval(s) != '*' ){
3492 fmt[0] = s[0];
3493 }
3494 break;
3495 }
3496 s += 2;
3497 }
3498 }
3499 Set_str_value(datafile,FORMAT,fmt);
3500 }
3501
3502