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