1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/*************************************************************************** 18 * LPRng - An Extended Print Spooler System 19 * 20 * Copyright 1988-2003, Patrick Powell, San Diego, CA 21 * papowell@lprng.com 22 * See LICENSE for conditions of use. 23 * 24 ***************************************************************************/ 25 26 static char *const _id = 27"$Id: getqueue.c,v 1.1.1.1 2008/10/15 03:28:26 james26_jang Exp $"; 28 29 30/*************************************************************************** 31 * Commentary 32 * Patrick Powell Thu Apr 27 21:48:38 PDT 1995 33 * 34 * The spool directory holds files and other information associated 35 * with jobs. Job files have names of the form cfXNNNhostname. 36 * 37 * The Scan_queue routine will scan a spool directory, looking for new 38 * or missing control files. If one is found, it will add it to 39 * the control file list. It will then sort the list of file names. 40 * 41 * In order to prevent strange things with pointers, you should not store 42 * pointers to this list, but use indexes instead. 43 ***************************************************************************/ 44 45#include "lp.h" 46#include "child.h" 47#include "errorcodes.h" 48#include "fileopen.h" 49#include "linelist.h" 50#include "getprinter.h" 51#include "gethostinfo.h" 52#include "getqueue.h" 53#include "globmatch.h" 54#include "permission.h" 55#include "lockfile.h" 56#include "merge.h" 57 58#if defined(USER_INCLUDE) 59# include USER_INCLUDE 60#else 61# if defined(ORDER_ROUTINE) 62# error No 'USER_INCLUDE' file with ORDER_ROUTINE function prototypes specified 63 You need an include file with function prototypes 64# endif 65#endif 66 67/**** ENDINCLUDE ****/ 68/* 69 * We make the following assumption: 70 * a hold file is the thing that LPRng will create. A control file without 71 * a hold file is an orphan, and should be disposed of. We will ignore these 72 * and leave it to the checkpc code to clean them up. 73 */ 74 75#if defined(JY20031104Scan_queue) 76int Scan_queue( struct line_list *spool_control, 77 struct line_list *sort_order, int *pprintable, int *pheld, int *pmove, 78 int only_queue_process, int *perr, int *pdone, 79 const char *remove_prefix, const char *remove_suffix ) 80{ 81 DIR *dir; /* directory */ 82 struct dirent *d; /* directory entry */ 83 struct line_list directory_files; 84 char *hf_name; 85 int c, printable, held, move, error, done, p, h, m, e, dn; 86 int remove_prefix_len = safestrlen( remove_prefix ); 87 int remove_suffix_len = safestrlen( remove_suffix ); 88 struct job job; 89 90 c = printable = held = move = error = done = 0; 91 Init_job( &job ); 92 Init_line_list(&directory_files); 93 if( pprintable ) *pprintable = 0; 94 if( pheld ) *pheld = 0; 95 if( pmove ) *pmove = 0; 96 if( perr ) *perr = 0; 97 if( pdone ) *pdone = 0; 98 99 Free_line_list(sort_order); 100 101 if( !(dir = opendir( "." )) ){ 102 return(1); 103 } 104 105 hf_name = 0; 106 while(1){ 107 while( (d = readdir(dir)) ){ 108 hf_name = d->d_name; 109 DEBUG5("Scan_queue: found file '%s'", hf_name ); 110 if( 111 (remove_prefix_len && !strncmp( hf_name, remove_prefix, remove_prefix_len ) ) 112 || (remove_suffix_len 113 && !strcmp( hf_name+strlen(hf_name)-remove_suffix_len, remove_suffix )) 114 ){ 115 DEBUG1("Scan_queue: removing file '%s'", hf_name ); 116 unlink( hf_name ); 117 continue; 118 } else if( (cval(hf_name+0) == 'h') 119 && (cval(hf_name+1) == 'f') 120 && isalpha(cval(hf_name+2)) 121 && isdigit(cval(hf_name+3)) 122 ){ 123 break; 124 } 125 } 126 /* found them all */ 127 if( d == 0 ){ 128 break; 129 } 130 131 Free_job( &job ); 132 133 DEBUG2("Scan_queue: processing file '%s'", hf_name ); 134 135 /* read the hf file and get the information */ 136 Get_file_image_and_split( hf_name, 0, 0, 137 &job.info, Line_ends, 1, Value_sep,1,1,1,0); 138#ifdef ORIGINAL_DEBUG//JY@1020 139 if(DEBUGL5)Dump_line_list("Scan_queue: hf", &job.info ); 140#endif 141 if( job.info.count == 0 ){ 142 continue; 143 } 144 145 /* get the data file from the control file */ 146 Setup_cf_info( &job, 1 ); 147 Job_printable(&job,spool_control, &p,&h,&m,&e,&dn); 148 if( p ) ++printable; 149 if( h ) ++held; 150 if( m ) ++move; 151 if( e ) ++error; 152 if( dn ) ++done; 153 154 /* now generate the sort key */ 155 DEBUG4("Scan_queue: p %d, m %d, e %d, dn %d, only_queue_process %d", 156 p, m, e, dn, only_queue_process ); 157 if( sort_order ){ 158 if( !only_queue_process || (p || m || e || dn) ){ 159#ifdef ORIGINAL_DEBUG//JY@1020 160 if(DEBUGL4)Dump_job("Scan_queue - before Make_sort_key",&job); 161#endif 162 Make_sort_key( &job ); 163 DEBUG5("Scan_queue: sort key '%s'",job.sort_key); 164 Set_str_value(sort_order,job.sort_key,hf_name); 165 } 166 } 167 } 168 closedir(dir); 169 170 Free_job(&job); 171 Free_line_list(&directory_files); 172 173#ifdef ORIGINAL_DEBUG//JY@1020 174 if(DEBUGL5){ 175 LOGDEBUG("Scan_queue: final values" ); 176 Dump_line_list_sub(SORT_KEY,sort_order); 177 } 178#endif 179 if( pprintable ) *pprintable = printable; 180 if( pheld ) *pheld = held; 181 if( pmove ) *pmove = move; 182 if( perr ) *perr = error; 183 if( pdone ) *pdone = done; 184 DEBUG3("Scan_queue: final printable %d, held %d, move %d, error %d, done %d", 185 printable, held, move, error, done ); 186 return(0); 187} 188#endif 189 190/* 191 * char *Get_fd_image( int fd, char *file ) 192 * Get an image of a file from an fd 193 */ 194 195char *Get_fd_image( int fd, off_t maxsize ) 196{ 197 char *s = 0; 198 struct stat statb; 199 char buffer[LARGEBUFFER]; 200 int n; 201 off_t len; 202 203 DEBUG3("Get_fd_image: fd %d", fd ); 204 205 if( lseek(fd, 0, SEEK_SET) == -1 ){ 206 Errorcode = JFAIL; 207 LOGERR_DIE(LOG_INFO)"Get_fd_image: lseek failed" ); 208 } 209 if( maxsize && fstat(fd, &statb) == 0 210 && maxsize< statb.st_size/1024 ){ 211 lseek(fd, -maxsize*1024, SEEK_END); 212 } 213 214 len = 0; 215 while( (n = read(fd,buffer,sizeof(buffer))) > 0 ){ 216 s = realloc_or_die(s,len+n+1,__FILE__,__LINE__); 217 memcpy(s+len,buffer,n); 218 len += n; 219 s[len] = 0; 220 } 221#ifdef ORIGINAL_DEBUG//JY@1020 222 if(DEBUGL3){ 223 SNPRINTF(buffer,32)"%s",s); 224 logDebug("Get_fd_image: len %d '%s'", s?safestrlen(s):0, buffer ); 225 } 226#endif 227 return(s); 228} 229 230/* 231 * char *Get_file_image( char *dir, char *file ) 232 * Get an image of a file 233 */ 234 235char *Get_file_image( const char *file, off_t maxsize ) 236{ 237 char *s = 0; 238 struct stat statb; 239 int fd; 240 241 if( file == 0 ) return(0); 242 DEBUG3("Get_file_image: '%s', maxsize %d", file, maxsize ); 243 if( (fd = Checkread( file, &statb )) >= 0 ){ 244 s = Get_fd_image( fd, maxsize ); 245 close(fd); 246 } 247 return(s); 248} 249 250/* 251 * char *Get_fd_image_and_split 252 * Get an image of a file 253 */ 254 255int Get_fd_image_and_split( int fd, 256 int maxsize, int clean, 257 struct line_list *l, const char *sep, 258 int sort, const char *keysep, int uniq, int trim, int nocomments, 259 char **return_image ) 260{ 261 char *s = 0; 262 if( return_image ) *return_image = 0; 263 s = Get_fd_image( fd, maxsize ); 264 if( s == 0 ) return 1; 265 if( clean ) Clean_meta(s); 266 Split( l, s, sep, sort, keysep, uniq, trim, nocomments ,0); 267 if( return_image ){ 268 *return_image = s; 269 } else { 270 if( s ) free(s); s = 0; 271 } 272 return(0); 273} 274 275 276/* 277 * char *Get_file_image_and_split 278 * Get an image of a file 279 */ 280 281int Get_file_image_and_split( const char *file, 282 int maxsize, int clean, 283 struct line_list *l, const char *sep, 284 int sort, const char *keysep, int uniq, int trim, int nocomments, 285 char **return_image ) 286{ 287 char *s = 0; 288 if( return_image ) *return_image = 0; 289 if( !ISNULL(file) ) s = Get_file_image( file, maxsize ); 290 if( s == 0 ) return 1; 291 if( clean ) Clean_meta(s); 292 Split( l, s, sep, sort, keysep, uniq, trim, nocomments ,0); 293 if( return_image ){ 294 *return_image = s; 295 } else { 296 if( s ) free(s); s = 0; 297 } 298 return(0); 299} 300 301/* 302 * Set up a job data structure with information from the 303 * file images 304 * - Check_for_hold - 305 * checks to see if the job is held by class or by 306 * command 307 * Setup_job - gets the job information and updates it 308 * from the spool queue and control information 309 */ 310 311 312void Check_for_hold( struct job *job, struct line_list *spool_control ) 313{ 314 int held, i; 315 /* get the hold class of the job */ 316 held = Get_hold_class(&job->info,spool_control); 317 Set_flag_value(&job->info,HOLD_CLASS,held); 318 319 /* see if we need to hold this job by time */ 320 if( !Find_exists_value(&job->info,HOLD_TIME,Value_sep) ){ 321 if( Find_flag_value(spool_control,HOLD_TIME,Value_sep) ){ 322 i = time((void *)0); 323 } else { 324 i = 0; 325 } 326 Set_flag_value( &job->info, HOLD_TIME, i ); 327 } 328 held = Find_flag_value(&job->info,HOLD_TIME,Value_sep); 329 Set_flag_value(&job->info,HELD,held); 330} 331 332/* 333 * Setup_job: called only when you REALLY want to 334 * read the control file and hold file. 335 */ 336 337#if defined(JY20031104Setup_job) 338void Setup_job( struct job *job, struct line_list *spool_control, 339 const char *cf_name, const char *hf_name, int check_for_existence ) 340{ 341 struct stat statb; 342 char *path, *s; 343 struct line_list *lp; 344 int i, j, size = 0; 345 346 /* add the hold file information directly */ 347 DEBUG3("Setup_job: hf_name '%s', cf_name (TRANSFERNAME) '%s'", hf_name, cf_name ); 348 if( cf_name ){ 349 Set_str_value(&job->info,TRANSFERNAME, cf_name); 350 } 351 cf_name = Find_str_value(&job->info,TRANSFERNAME,Value_sep); 352 353 if( hf_name ){ 354 Set_str_value(&job->info,HF_NAME,hf_name); 355 } 356 hf_name = Find_str_value(&job->info,HF_NAME,Value_sep); 357 358 if( cf_name && !Find_str_value(&job->info,NUMBER,Value_sep) ){ 359 Check_format( CONTROL_FILE, cf_name, job ); 360 } 361 362 if( !Find_str_value(&job->info,JOB_TIME,Value_sep) 363 && (path = Find_str_value(&job->info,OPENNAME,Value_sep)) ){ 364 j = 0; 365 if( stat(path,&statb) ){ 366 i = time((void *)0); 367 } else { 368 i = statb.st_mtime; 369#ifdef ST_MTIMESPEC_TV_NSEC 370 j = statb.st_mtimespec.tv_nsec/1000; 371#endif 372#ifdef ST_MTIMENSEC 373 j = statb.st_mtimensec/1000; 374#endif 375 } 376 Set_flag_value(&job->info,JOB_TIME,i); 377 Set_flag_value(&job->info,JOB_TIME_USEC,j); 378 } 379 380 /* set up the control file information */ 381 Setup_cf_info( job, check_for_existence ); 382 383 /* set the class of the job */ 384 if( !Find_str_value(&job->info,CLASS,Value_sep) 385 && (s = Find_str_value(&job->info,PRIORITY,Value_sep)) ){ 386 Set_str_value(&job->info,CLASS,s); 387 } 388 /* set the size of the job */ 389 if( !Find_flag_value(&job->info,SIZE,Value_sep) ){ 390 size = 0; 391 for( i = 0; i < job->datafiles.count; ++i ){ 392 lp = (void *)job->datafiles.list[i]; 393 size += Find_flag_value(lp,SIZE,Value_sep); 394 } 395 Set_decimal_value(&job->info,SIZE,size); 396 } 397 398 Make_identifier( job ); 399 Check_for_hold( job, spool_control ); 400 401#ifdef ORIGINAL_DEBUG//JY@1020 402 if(DEBUGL3)Dump_job("Setup_job",job); 403#endif 404} 405#endif 406 407/* Get_hold_class( spool_control, job ) 408 * check to see if the spool class and the job class are compatible 409 * returns: non-zero if held, 0 if not held 410 * i.e.- cmpare(spoolclass,jobclass) 411 */ 412 413int Get_hold_class( struct line_list *info, struct line_list *sq ) 414{ 415 int held, i; 416 char *s, *t; 417 struct line_list l; 418 419 Init_line_list(&l); 420 held = 0; 421 if( (s = Clsses(sq)) 422 && (t = Find_str_value(info,CLASS,Value_sep)) ){ 423 held = 1; 424 Free_line_list(&l); 425 Split(&l,s,File_sep,0,0,0,0,0,0); 426 for( i = 0; held && i < l.count; ++i ){ 427 held = Globmatch( l.list[i], t ); 428 } 429 Free_line_list(&l); 430 } 431 return(held); 432} 433 434/* 435 * Extract the control file and data file information from the 436 * control file image 437 * 438 * Note: we also handle HP extensions here. 439 * 440 * 1. 4-Digit Job Numbers 441 * ---------------------- 442 * 443 * HP preserves the System V-style 4-digit sequence number, or job number, in 444 * file names and attributes, while BSD uses 3-digit job numbers. 445 * 446 * 447 * 2. Control and Data File Naming Conventions 448 * ------------------------------------------- 449 * 450 * Control files are named in the following format: 451 * 452 * cA<seqn><host> 453 * 454 * <seqn> is the 4-digit sequence number (aka job number). 455 * <host> is the originating host name. 456 * 457 * The data file naming sequence format is: 458 * 459 * dA<seqn><host> through dZ<seqn><host> followed by... 460 * da<seqn><host> through dz<seqn><host> followed by... 461 * eA<seqn><host> through eZ<seqn><host> followed by... 462 * ea<seqn><host> through ez<seqn><host> ... etc. ... 463 * 464 * 465 * So the first data file name in a request begins with "dA", the second with 466 * "dB", the 27th with "da", the 28th with "db", and so forth. 467 * 468 * 469 * 3. HP-Specific BSD Job Attributes (Control File Lines) 470 * ------------------------------------------------------ 471 * 472 * The following control file lines are extensions of RFC-1179: 473 * 474 * R<login> 475 * 476 * Write to the named login's terminal when the job is complete. This is 477 * an alternate to the RFC-1179-style e-mail completion notification. 478 * This notification is selected via the lp "-w" option. 479 * 480 * A<priority> 481 * 482 * Specifies the System V-style priority of the request, a single digit 483 * from 0-7. 484 * 485 * N B<banner> 486 * 487 * Note that this line begins with an "N", a space, and then a "B". The 488 * argument is the banner page title requested via the lp "-t" option. If 489 * that option was not given then the argument is null. 490 * 491 * N O<options> 492 * 493 * Note that this line begins with an "N", a space, and then an "O". The 494 * argument contains the System V-style "-o" options specified in the lp 495 * command line. The option names appear without a leading "-o". The 496 * first option name begins in the fourth character of the line; each 497 * option is separated by a blank. If no "-o" options were given then the 498 * argument is null. 499 * 500 */ 501 502#if defined(JY20031104Append_Z_value) 503void Append_Z_value( struct job *job, char *s ) 504{ 505 char *t; 506 507 /* check for empty string */ 508 if( !s || !*s ) return; 509 t = Find_str_value(&job->info,"Z",Value_sep); 510 if( t && *t ){ 511 t = safestrdup3(t,",",s,__FILE__,__LINE__); 512 Set_str_value(&job->info,"Z",t); 513 if( t ) free(t); t = 0; 514 } else { 515 Set_str_value(&job->info,"Z",s); 516 } 517} 518#endif 519 520#if defined(JY20031104Setup_cf_info) 521int Setup_cf_info( struct job *job, int check_for_existence ) 522{ 523 char *s; 524 int i, c, n, copies = 0, last_format = 0; 525 struct line_list cf_line_list; 526 struct line_list *datafile = 0; 527 struct stat statb; 528 char buffer[SMALLBUFFER], *t; 529 char *file_found; 530 char *names = 0; 531 int returnstatus = 0; 532 int hpformat; 533 534 Init_line_list(&cf_line_list); 535 names = 0; 536 537 hpformat = Find_flag_value(&job->info,HPFORMAT,Value_sep); 538 if( (s = Find_str_value(&job->info,DATAFILES,Value_sep)) ){ 539 Split(&cf_line_list,s,"\001",0,0,0,0,0,0); 540 } else { 541 s = Find_str_value(&job->info,OPENNAME,Value_sep); 542 if( !s ) s = Find_str_value(&job->info,TRANSFERNAME,Value_sep); 543 DEBUG3("Setup_cf_info: control file '%s', hpformat '%d'", s, hpformat ); 544 if( Get_file_image_and_split(s,0,0, &cf_line_list, Line_ends,0,0,0,0,0,0) 545 && check_for_existence ){ 546#ifdef ORIGINAL_DEBUG//JY@1020 547 DEBUG3("Setup_cf_info: missing or empty control file '%s'", s ); 548 SNPRINTF(buffer,sizeof(buffer)) 549 "no control file %s - %s", s, Errormsg(errno) ); 550#endif 551 Set_str_value(&job->info,ERROR,buffer); 552 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 553 returnstatus = 1; 554 goto done; 555 } 556 } 557 558 Free_listof_line_list( &job->datafiles ); 559 560 file_found = 0; 561 datafile = malloc_or_die(sizeof(datafile[0]),__FILE__,__LINE__); 562 memset(datafile,0,sizeof(datafile[0])); 563 564 for( i = 0; i < cf_line_list.count; ++i ){ 565 s = cf_line_list.list[i]; 566 Clean_meta(s); 567 c = cval(s); 568 DEBUG3("Setup_cf_info: doing line '%s'", s ); 569 if( islower(c) ){ 570 t = s; 571 while( (t = strpbrk(t," \t")) ) *t++ = '_'; 572 if( file_found && (safestrcmp(file_found,s+1) || last_format != c) ){ 573 Check_max(&job->datafiles,1); 574 job->datafiles.list[job->datafiles.count++] = (void *)datafile; 575 copies = 0; 576 file_found = 0; 577 datafile = malloc_or_die(sizeof(datafile[0]),__FILE__,__LINE__); 578 memset(datafile,0,sizeof(datafile[0])); 579 } 580 581 last_format = c; 582 buffer[0] = c; buffer[1] = 0; 583 Set_str_value(datafile,FORMAT,buffer); 584 585 ++copies; 586 Set_flag_value(datafile,COPIES,copies); 587 588 Set_str_value(datafile,TRANSFERNAME,s+1); 589 Set_str_value(datafile,OPENNAME,s+1); 590 file_found = Find_str_value(datafile,TRANSFERNAME,Value_sep); 591 DEBUG4("Setup_cf_info: doing file '%s', format '%c', copies %d", 592 file_found, last_format, copies ); 593 594 /* now we check for the status */ 595 if( check_for_existence ){ 596 if( stat(file_found, &statb) == 0 ){ 597 double size; 598 size = statb.st_size; 599 DEBUG4("Setup_cf_info: '%s' - size %0.0f", file_found, size ); 600 Set_double_value(datafile,SIZE,size ); 601 } else { 602#ifdef ORIGINAL_DEBUG//JY@1020 603 SNPRINTF(buffer,sizeof(buffer)) 604 "missing data file %s - %s", file_found, Errormsg(errno) ); 605#endif 606 Set_str_value(&job->info,ERROR,buffer); 607 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 608 returnstatus = 1; 609 goto done; 610 } 611 } 612 } else if( c == 'N' ){ 613 if( hpformat && cval(s+1) == ' '){ 614 /* this is an HP Format option */ 615 /* N B<banner> -> 'T' line */ 616 /* N Ooption option option-> prefix to Z */ 617 c = cval(s+2); 618 if( c == 'B' ){ 619 if( s[3] ) Set_str_value(&job->info,"T",s+3); 620 } else if( c == 'O' ){ 621 s = s+3; 622 if( safestrlen(s) ){ 623 for( t = s; (t = strpbrk(t," ")); ++t ){ 624 *t = ','; 625 } 626 Append_Z_value(job,s); 627 } 628 } 629 continue; 630 } 631 /* if we have a file name AND an 'N' for it, then set up a new file */ 632 if( file_found && (t = Find_str_value(datafile,"N",Value_sep)) 633 /* && safestrcmp(t,s+1) */ ){ 634 Check_max(&job->datafiles,1); 635 job->datafiles.list[job->datafiles.count++] = (void *)datafile; 636 copies = 0; 637 file_found = 0; 638 datafile = malloc_or_die(sizeof(datafile[0]),__FILE__,__LINE__); 639 memset(datafile,0,sizeof(datafile[0])); 640 } 641 Set_str_value(datafile,"N",s+1); 642 if( !names ){ 643 names = safestrdup(s+1,__FILE__,__LINE__); 644 } else { 645 names = safeextend3(names,",",s+1,__FILE__,__LINE__); 646 } 647 } else if( c == 'U' ){ 648 Set_str_value(datafile,"U",s+1); 649 } else { 650 if( hpformat && c == 'Z' ){ 651 Append_Z_value( job, s+1 ); 652 } else if( hpformat && c == 'R' ){ 653 Set_str_value(&job->info,"M",s+1); 654 } else if( hpformat && c == 'A' ){ 655 n = strtol( s+1,0,10); 656 if( n >= 0 && n <=10){ 657 c = n + 'A'; 658 buffer[0] = n + 'A'; 659 buffer[1] = 0; 660 Set_str_value(&job->info,PRIORITY,buffer); 661 } 662 } else if( isupper(c) ){ 663 buffer[0] = c; buffer[1] = 0; 664 DEBUG4("Setup_cf_info: control '%s'='%s'", buffer, s+1 ); 665 Set_str_value(&job->info,buffer,s+1); 666 } 667 } 668 } 669 if( file_found ){ 670 Check_max(&job->datafiles,1); 671 job->datafiles.list[job->datafiles.count++] = (void *)datafile; 672 datafile = 0; 673 } else { 674 free(datafile); 675 datafile = 0; 676 } 677 Set_str_value(&job->info,FILENAMES,names); 678 679 done: 680 681 if( datafile ) free(datafile); datafile=0; 682 if( names ) free(names); names=0; 683 Free_line_list( &cf_line_list ); 684#ifdef ORIGINAL_DEBUG//JY@1020 685 if(DEBUGL4)Dump_job("Setup_cf_info - final",job); 686#endif 687 return(returnstatus); 688} 689#endif 690 691char *Make_hf_image( struct job *job ) 692{ 693 char *outstr, *s; 694 int i; 695 int len = safestrlen(OPENNAME); 696 697 outstr = 0; 698 for( i = 0; i < job->info.count; ++i ){ 699 s = job->info.list[i]; 700 if( !ISNULL(s) && !safestrpbrk(s,Line_ends) && 701 safestrncasecmp(OPENNAME,s,len) ){ 702 outstr = safeextend3(outstr,s,"\n",__FILE__,__LINE__); 703 } 704 } 705 return( outstr ); 706} 707 708/* 709 * Write a hold file 710 */ 711 712int Set_hold_file( struct job *job, struct line_list *perm_check, int fd ) 713{ 714 char *hf_name, *tempfile, *outstr; 715 int status; 716 717 status = 0; 718 outstr = 0; 719 720#ifdef ORIGINAL_DEBUG//JY@1020 721 if(DEBUGL4)Dump_job("Set_hold_file",job); 722#endif 723 Set_str_value(&job->info,UPDATE_TIME,Time_str(0,0)); 724 if( !(hf_name = Find_str_value(&job->info,HF_NAME,Value_sep)) ){ 725 Errorcode = JABORT; 726 FATAL(LOG_ERR)"Set_hold_file: LOGIC ERROR- no HF_NAME in job information"); 727 } 728 outstr = Make_hf_image( job ); 729 if( !fd ){ 730 fd = Make_temp_fd( &tempfile ); 731 if( Write_fd_str(fd, outstr) < 0 ){ 732 LOGERR(LOG_INFO)"Set_hold_file: write to '%s' failed", tempfile ); 733 status = 1; 734 } 735 close(fd); 736 if( status == 0 && rename( tempfile, hf_name ) == -1 ){ 737 LOGERR(LOG_INFO)"Set_hold_file: rename '%s' to '%s' failed", 738 tempfile, hf_name ); 739 status = 1; 740 } 741 } else { 742 if( lseek( fd, 0, SEEK_SET ) == -1 ){ 743 LOGERR_DIE(LOG_ERR) "Set_hold_file: lseek failed" ); 744 } 745 if( ftruncate( fd, 0 ) ){ 746 LOGERR_DIE(LOG_ERR) "Set_hold_file: ftruncate failed" ); 747 } 748 if( Write_fd_str(fd, outstr) < 0 ){ 749 LOGERR(LOG_INFO)"Set_hold_file: write to '%s' failed", hf_name ); 750 status = 1; 751 } 752 /* close(fd); */ 753 } 754 755 if( Lpq_status_file_DYN ){ 756 unlink(Lpq_status_file_DYN ); 757 } 758 759 /* we do this when we have a logger */ 760 if( status == 0 && Logger_fd > 0 ){ 761 char *t, *u; 762 if( perm_check ){ 763 u = Join_line_list( perm_check, "\n" ); 764 t = Escape(u,1); 765 outstr = safeextend5(outstr,"\n",LPC,"=",u,__FILE__,__LINE__); 766 if(u) free(u); u = 0; 767 if(t) free(t); t = 0; 768 } 769#ifdef ORIGINAL_DEBUG//JY@1020 770 send_to_logger(-1, -1, job,UPDATE,outstr); 771#endif 772 } 773 if( outstr ) free( outstr ); outstr = 0; 774 return( status ); 775} 776 777/* 778 * Get_hold_file( struct job *job, char *hf_name ) 779 * 780 * get hold file contents and initialize job->info hash with them 781 */ 782 783void Get_hold_file( struct job *job, char *hf_name ) 784{ 785 char *s; 786 if( (s = safestrchr(hf_name, '=')) ){ 787 hf_name = s+1; 788 } 789 DEBUG1("Get_hold_file: checking on '%s'", hf_name ); 790 791 Get_file_image_and_split( hf_name, 0, 0, 792 &job->info, Line_ends, 1, Value_sep,1,1,1,0); 793 if( !Find_str_value(&job->info,HF_NAME,Value_sep) ){ 794 Set_str_value(&job->info,HF_NAME,hf_name); 795 } 796} 797 798/* 799 * Get Spool Control Information 800 * - simply read the file 801 */ 802 803void Get_spool_control( const char *file, struct line_list *info ) 804{ 805 Free_line_list(info); 806 DEBUG2("Get_spool_control: file '%s'", file ); 807 Get_file_image_and_split( file, 0, 0, 808 info,Line_ends,1,Value_sep,1,1,1,0); 809#ifdef ORIGINAL_DEBUG//JY@1020 810 if(DEBUGL4)Dump_line_list("Get_spool_control- info", info ); 811#endif 812} 813 814/* 815 * Set Spool Control Information 816 * - simply write the file 817 */ 818 819void Set_spool_control( struct line_list *perm_check, const char *file, 820 struct line_list *info ) 821{ 822 char *s, *t, *tempfile; 823 struct line_list l; 824 int fd; 825 826 s = t = tempfile = 0; 827 Init_line_list(&l); 828 fd = Make_temp_fd( &tempfile ); 829 DEBUG2("Set_spool_control: file '%s', tempfile '%s'", 830 file, tempfile ); 831#ifdef ORIGINAL_DEBUG//JY@1020 832 if(DEBUGL4)Dump_line_list("Set_spool_control- info", info ); 833#endif 834 s = Join_line_list(info,"\n"); 835 if( Write_fd_str(fd, s) < 0 ){ 836 Errorcode = JFAIL; 837 LOGERR_DIE(LOG_INFO)"Set_spool_control: cannot write tempfile '%s'", 838 tempfile ); 839 } 840 close(fd); 841 if( rename( tempfile, file ) == -1 ){ 842 Errorcode = JFAIL; 843 LOGERR_DIE(LOG_INFO)"Set_spool_control: rename of '%s' to '%s' failed", 844 tempfile, file ); 845 } 846 /* force and update of the cached status */ 847 848 if( Lpq_status_file_DYN ){ 849 /* do not check to see if this works */ 850 unlink(Lpq_status_file_DYN); 851 } 852 853 if( Logger_fd ){ 854 /* log the spool control file changes */ 855 t = Escape(s,1); 856 Set_str_value(&l,QUEUE,t); 857 if(s) free(s); s = 0; 858 if(t) free(t); t = 0; 859 860 if( perm_check ){ 861 s = Join_line_list( perm_check, "\n" ); 862 t = Escape(s,1); 863 Set_str_value(&l,LPC,t); 864 if(s) free(s); s = 0; 865 if(t) free(t); t = 0; 866 } 867 t = Join_line_list( &l, "\n"); 868 869#ifdef ORIGINAL_DEBUG//JY@1020 870 send_to_logger(-1,-1,0,QUEUE,t); 871#endif 872 } 873 874 Free_line_list(&l); 875 if(s) free(s); s = 0; 876 if(t) free(t); t = 0; 877} 878 879void intval( const char *key, struct line_list *list, struct job *job ) 880{ 881 int i = Find_flag_value(list,key,Value_sep); 882 int len = safestrlen(job->sort_key); 883 SNPRINTF(job->sort_key+len,sizeof(job->sort_key)-len) 884 "|%s.0x%08x",key,i&0xffffffff); 885 DEBUG5("intval: '%s'", job->sort_key ); 886} 887 888void revintval( const char *key, struct line_list *list, struct job *job ) 889{ 890 int i = Find_flag_value(list,key,Value_sep); 891 int len = safestrlen(job->sort_key); 892 SNPRINTF(job->sort_key+len,sizeof(job->sort_key)-len) 893 "|%s.0x%08x",key,(~i)&0xffffffff); 894 DEBUG5("revintval: '%s'", job->sort_key ); 895} 896 897void strzval( const char *key, struct line_list *list, struct job *job ) 898{ 899 char *s = Find_str_value(list,key,Value_sep); 900 int len = safestrlen(job->sort_key); 901 SNPRINTF(job->sort_key+len,sizeof(job->sort_key)-len) 902 "|%s.%d",key,s!=0); 903 DEBUG5("strzval: '%s'", job->sort_key ); 904} 905 906void strnzval( const char *key, struct line_list *list, struct job *job ) 907{ 908 char *s = Find_str_value(list,key,Value_sep); 909 int len = safestrlen(job->sort_key); 910 SNPRINTF(job->sort_key+len,sizeof(job->sort_key)-len) 911 "|%s.%d",key,(s==0 || *s == 0)); 912 DEBUG5("strnzval: '%s'", job->sort_key ); 913} 914 915void strval( const char *key, struct line_list *list, struct job *job, 916 int reverse ) 917{ 918 char *s = Find_str_value(list,key,Value_sep); 919 int len = safestrlen(job->sort_key); 920 int c = 0; 921 922 if(s) c = cval(s); 923 if( reverse ) c = -c; 924 c = 0xFF & (-c); 925 SNPRINTF(job->sort_key+len,sizeof(job->sort_key)-len) 926 "|%s.%02x",key,c); 927 DEBUG5("strval: '%s'", job->sort_key ); 928} 929 930 931/* 932 * Make_sort_key 933 * Make a sort key from the image information 934 */ 935void Make_sort_key( struct job *job ) 936{ 937 job->sort_key[0] = 0; 938 if( Order_routine_DYN ){ 939#if defined(ORDER_ROUTINE) 940 extern char *ORDER_ROUTINE( struct job *job ); 941 ORDER_ROUTINE( &job ); 942#else 943 Errorcode = JABORT; 944 FATAL(LOG_ERR)"Make_sort_key: order_routine requested and ORDER_ROUTINE undefined"); 945#endif 946 } else { 947 /* first key is REMOVE_TIME - remove jobs come last */ 948 intval(REMOVE_TIME,&job->info,job); 949#if 0 950 /* first key is DONE_TIME - done jobs come last */ 951 intval(DONE_TIME,&job->info,job); 952 intval(INCOMING_TIME,&job->info,job); 953 /* next key is ERROR - error jobs jobs come before removed */ 954 intval(ERROR_TIME,&job->info,job); 955#endif 956 /* next key is HOLD - before the error jobs */ 957 intval(HOLD_CLASS,&job->info,job); 958 intval(HOLD_TIME,&job->info,job); 959 /* next key is MOVE - before the held jobs */ 960 strnzval(MOVE,&job->info,job); 961 /* now by priority */ 962 if( Ignore_requested_user_priority_DYN == 0 ){ 963 strval(PRIORITY,&job->info,job,Reverse_priority_order_DYN); 964 } 965 /* now we do TOPQ */ 966 revintval(PRIORITY_TIME,&job->info,job); 967 /* now we do FirstIn, FirstOut */ 968 intval(JOB_TIME,&job->info,job); 969 intval(JOB_TIME_USEC,&job->info,job); 970 /* now we do by job number if two at same time (very unlikely) */ 971 intval(NUMBER,&job->info,job); 972 } 973} 974#ifdef REMOVE 975 976/* 977 * Set up printer 978 * 1. reset configuration information 979 * 2. check the printer name 980 * 3. get the printcap information 981 * 4. set the configuration variables 982 * 5. If run on the server, then check for the Lp_device_DYN 983 * being set. If it is set, then clear the RemotePrinter_DYN 984 * and RemoteHost_DYN. 985 */ 986 987#if defined(JY20031104Setup_printer) 988int Setup_printer( char *prname, char *error, int errlen, int subserver ) 989{ 990 char *s; 991 int status = 0; 992 char name[SMALLBUFFER]; 993 994 DEBUG3( "Setup_printer: checking printer '%s'", prname ); 995 996 /* reset the configuration information, just in case 997 * this is a subserver or being used to get status 998 */ 999 safestrncpy(name,prname); 1000 if( error ) error[0] = 0; 1001 if( (s = Is_clean_name( name )) ){ 1002 SNPRINTF( error, errlen) 1003 "printer '%s' has illegal char at '%s' in name", name, s ); 1004 status = 1; 1005 goto error; 1006 } 1007 lowercase(name); 1008 if( !subserver && Status_fd > 0 ){ 1009 close( Status_fd ); 1010 Status_fd = -1; 1011 } 1012 Set_DYN(&Printer_DYN,name); 1013 Fix_Rm_Rp_info(0,0); 1014 1015 if( Spool_dir_DYN == 0 || *Spool_dir_DYN == 0 ){ 1016 SNPRINTF( error, errlen) 1017"spool queue for '%s' does not exist on server %s\n non-existent printer or you need to run 'checkpc -f'", 1018 name, FQDNHost_FQDN ); 1019 status = 2; 1020 goto error; 1021 } 1022 1023 if( chdir( Spool_dir_DYN ) < 0 ){ 1024#ifdef ORIGINAL_DEBUG//JY@1020 1025 SNPRINTF( error, errlen) 1026 "printer '%s', chdir to '%s' failed '%s'", 1027 name, Spool_dir_DYN, Errormsg( errno ) ); 1028#endif 1029 status = 2; 1030 goto error; 1031 } 1032 1033 /* 1034 * get the override information from the control/spooling 1035 * directory 1036 */ 1037 1038 Get_spool_control( Queue_control_file_DYN, &Spool_control ); 1039 1040 if( Perm_filters_line_list.count ){ 1041 Free_line_list(&Perm_line_list); 1042 Merge_line_list(&Perm_line_list,&RawPerm_line_list,0,0,0); 1043 Filterprintcap( &Perm_line_list, &Perm_filters_line_list, 1044 Printer_DYN ); 1045 } 1046 1047#ifdef ORIGINAL_DEBUG//JY@1020 1048 DEBUG1("Setup_printer: printer now '%s', spool dir '%s'", 1049 Printer_DYN, Spool_dir_DYN ); 1050 if(DEBUGL3){ 1051 Dump_parms("Setup_printer - vars",Pc_var_list); 1052 Dump_line_list("Setup_printer - spool control", &Spool_control ); 1053 } 1054#endif 1055 1056 error: 1057 DEBUG3("Setup_printer: status '%d', error '%s'", status, error ); 1058 return( status ); 1059} 1060#endif 1061 1062/************************************************************************** 1063 * Read_pid( int fd, char *str, int len ) 1064 * - Read the pid from a file 1065 **************************************************************************/ 1066int Read_pid( int fd, char *str, int len ) 1067{ 1068 char line[LINEBUFFER]; 1069 int n; 1070 1071 if( lseek( fd, 0, SEEK_SET ) == -1 ){ 1072 LOGERR_DIE(LOG_ERR) "Read_pid: lseek failed" ); 1073 } 1074 1075 if( str == 0 ){ 1076 str = line; 1077 len = sizeof( line ); 1078 } 1079 str[0] = 0; 1080 if( (n = read( fd, str, len-1 ) ) < 0 ){ 1081 LOGERR_DIE(LOG_ERR) "Read_pid: read failed" ); 1082 } 1083 str[n] = 0; 1084 n = atoi( str ); 1085 DEBUG3( "Read_pid: %d", n ); 1086 return( n ); 1087} 1088 1089/************************************************************************** 1090 * Write_pid( int fd ) 1091 * - Write the pid to a file 1092 **************************************************************************/ 1093int Write_pid( int fd, int pid, char *str ) 1094{ 1095 char line[LINEBUFFER]; 1096 1097 if( lseek( fd, 0, SEEK_SET ) == -1 ){ 1098 LOGERR(LOG_ERR) "Write_pid: lseek failed" ); 1099 return -1; 1100 } 1101 if( ftruncate( fd, 0 ) ){ 1102 LOGERR(LOG_ERR) "Write_pid: ftruncate failed" ); 1103 return -1; 1104 } 1105 1106 if( str == 0 ){ 1107 SNPRINTF( line, sizeof(line)) "%d\n", pid ); 1108 } else { 1109 SNPRINTF( line, sizeof(line)) "%s\n", str ); 1110 } 1111 DEBUG3( "Write_pid: pid %d, str '%s'", pid, str ); 1112 if( Write_fd_str( fd, line ) < 0 ){ 1113 LOGERR(LOG_ERR) "Write_pid: write failed" ); 1114 return -1; 1115 } 1116 return 0; 1117} 1118#endif 1119/*************************************************************************** 1120 * int Patselect( struct line_list *tokens, struct line_list *cf ); 1121 * check to see that the token value matches one of the following 1122 * in the control file: 1123 * token is INTEGER: then matches the job number 1124 * token is string: then matches either the user name or host name 1125 * then try glob matching job ID 1126 * return: 1127 * 0 if match found 1128 * nonzero if not match found 1129 ***************************************************************************/ 1130 1131int Patselect( struct line_list *token, struct line_list *cf, int starting ) 1132{ 1133 int match = 1; 1134 int i, n, val; 1135 char *key, *s, *end; 1136 1137#ifdef ORIGINAL_DEBUG//JY@1020 1138 if(DEBUGL3)Dump_line_list("Patselect- tokens", token ); 1139 if(DEBUGL3)Dump_line_list("Patselect- info", cf ); 1140#endif 1141 for( i = starting; match && i < token->count; ++i ){ 1142 key = token->list[i]; 1143 DEBUG3("Patselect: key '%s'", key ); 1144 /* handle wildcard match */ 1145 if( !(match = safestrcasecmp( key, "all" ))){ 1146 break; 1147 } 1148 end = key; 1149 val = strtol( key, &end, 10 ); 1150 if( *end == 0 ){ 1151 n = Find_decimal_value(cf,NUMBER,Value_sep); 1152 /* we check job number */ 1153 DEBUG3("Patselect: job number check '%d' to job %d", 1154 val, n ); 1155 match = (val != n); 1156 } else { 1157 /* now we check to see if we have a name match */ 1158 if( (s = Find_str_value(cf,LOGNAME,Value_sep)) 1159 && !(match = Globmatch(key,s)) ){ 1160 break; 1161 } 1162 if( (s = Find_str_value(cf,IDENTIFIER,Value_sep)) 1163 && !(match = Globmatch(key,s)) ){ 1164 break; 1165 } 1166 } 1167 } 1168 DEBUG3("Patselect: returning %d", match); 1169 return(match); 1170} 1171 1172/*************************************************************************** 1173 * char * Check_format( int type, char *name, struct control_file *job ) 1174 * Check to see that the file name has the correct format 1175 * name[0] == 'c' or 'd' (type) 1176 * name[1] = 'f' 1177 * name[2] = A-Za-z 1178 * name[3-5] = NNN 1179 * name[6-end] = only alphanumeric and ., _, or - chars 1180 * RETURNS: 0 if OK, error message (string) if not 1181 * 1182 * Summary of HP's Extensions to RFC-1179 1183 * 1. 4-Digit Job Numbers 1184 * ---------------------- 1185 * HP preserves the System V-style 4-digit sequence number, or job number, in 1186 * file names and attributes, while BSD uses 3-digit job numbers. 1187 * 2. Control and Data File Naming Conventions 1188 * ------------------------------------------- 1189 * Control files are named in the following format: 1190 * cA<seqn><host> 1191 * <seqn> is the 4-digit sequence number (aka job number). 1192 * <host> is the originating host name. 1193 * The data file naming sequence format is: 1194 * dA<seqn><host> through dZ<seqn><host> followed by... 1195 * da<seqn><host> through dz<seqn><host> followed by... 1196 * eA<seqn><host> through eZ<seqn><host> followed by... 1197 * ea<seqn><host> through ez<seqn><host> ... etc. ... 1198 * So the first data file name in a request begins with "dA", the second with 1199 * "dB", the 27th with "da", the 28th with "db", and so forth. 1200 1201 ***************************************************************************/ 1202#if defined(JY20031104Check_format) 1203int Check_format( int type, const char *name, struct job *job ) 1204{ 1205 int n, c, hpformat; 1206 const char *s; 1207 char *t; 1208 char msg[SMALLBUFFER]; 1209 1210 DEBUG4("Check_format: type %d, name '%s'", type, name ); 1211 msg[0] = 0; 1212 hpformat = 0; 1213 n = cval(name); 1214 switch( type ){ 1215 case DATA_FILE: 1216 if( n != 'd' ){ 1217 SNPRINTF(msg, sizeof(msg)) 1218 "data file does not start with 'd' - '%s'", 1219 name ); 1220 goto error; 1221 } 1222 break; 1223 case CONTROL_FILE: 1224 if( n != 'c' ){ 1225 SNPRINTF(msg, sizeof(msg)) 1226 "control file does not start with 'c' - '%s'", 1227 name ); 1228 goto error; 1229 } 1230 break; 1231 default: 1232 SNPRINTF(msg, sizeof(msg)) 1233 "bad file type '%c' - '%s' ", type, 1234 name ); 1235 goto error; 1236 } 1237 /* check for second letter */ 1238 n = cval(name+1); 1239 if( n == 'A' ){ 1240 /* HP format */ 1241 hpformat = 1; 1242 } else if( n != 'f' ){ 1243 SNPRINTF(msg, sizeof(msg)) 1244 "second letter must be f not '%c' - '%s' ", n, name ); 1245 goto error; 1246 } else { 1247 n = cval(name+2); 1248 if( !isalpha( n ) ){ 1249 SNPRINTF(msg, sizeof(msg)) 1250 "third letter must be letter not '%c' - '%s' ", n, name ); 1251 goto error; 1252 } 1253 } 1254 if( type == CONTROL_FILE ){ 1255 SNPRINTF(msg,sizeof(msg))"%c",n); 1256 Set_str_value(&job->info,PRIORITY,msg); 1257 msg[0] = 0; 1258 } 1259 /* 1260 we now enter the wonderful world of 'conventions' 1261 cfAnnnHostname 1262 ^^^^ starts with letter (number len = 0, 1, 2, 3) 1263 cfAnnnIPV4.Add.ress (number len = 4, 5, ... ) 1264 ^^^^ starts with number or is a 3com type thing 1265 cfAnnnnnnHostName (len = 6) 1266 ^^^^ starts with letter 1267 cfAnnnnnnIPV4.Add.ress (len = 7, ... ) 1268 ^^^^ starts with number 1269 */ 1270 1271 if( hpformat ){ 1272 /* we have four digits */ 1273 safestrncpy(msg,&name[2]); 1274 t = 0; 1275 n = strtol(msg,&t,10); 1276 } else { 1277 safestrncpy(msg,&name[3]); 1278 for( t = msg; isdigit(cval(t)); ++t ); 1279 c = t - msg; 1280 switch( c ){ 1281 case 0: case 1: case 2: case 3: 1282 break; 1283 case 4: case 5: 1284 c = 3; 1285 break; 1286 default: 1287 if( cval(msg+6) == '.' ) c = 3; 1288 else c = 6; 1289 break; 1290 } 1291 /* get the number */ 1292 t = &msg[c]; 1293 c = *t; 1294 *t = 0; 1295 n = strtol(msg,0,10); 1296 *t = c; 1297 } 1298 1299 DEBUG1("Check_format: name '%s', number %d, file '%s'", name, n, t ); 1300 if( Find_str_value( &job->info,NUMBER,Value_sep) ){ 1301 c = Find_decimal_value( &job->info,NUMBER,Value_sep); 1302 if( c != n ){ 1303 SNPRINTF(msg, sizeof(msg)) 1304 "job numbers differ '%s', old %d and new %d", 1305 name, c, n ); 1306 goto error; 1307 } 1308 } else { 1309 Fix_job_number( job, n ); 1310 } 1311 Clean_name(t); 1312 if( (s = Find_str_value( &job->info,FILE_HOSTNAME,Value_sep)) ){ 1313 if( safestrcasecmp(s,t) ){ 1314 SNPRINTF(msg, sizeof(msg)) 1315 "bad hostname '%s' - '%s' ", t, name ); 1316 goto error; 1317 } 1318 } else { 1319 Set_str_value(&job->info,FILE_HOSTNAME,t); 1320 } 1321 /* clear out error message */ 1322 msg[0] = 0; 1323 1324 error: 1325 if( hpformat ){ 1326 Set_flag_value(&job->info,HPFORMAT,hpformat); 1327 } 1328 if( msg[0] ){ 1329 DEBUG1("Check_format: %s", msg ); 1330 Set_str_value(&job->info,FORMAT_ERROR,msg); 1331 } 1332 return( msg[0] != 0 ); 1333} 1334#endif 1335 1336char *Find_start(char *str, const char *key ) 1337{ 1338 int n = safestrlen(key); 1339 while( (str = strstr(str,key)) && str[n] != '=' ); 1340 if( str ) str += (n+1); 1341 return( str ); 1342} 1343 1344char *Frwarding(struct line_list *l) 1345{ 1346 return( Find_str_value(l,FORWARDING,Value_sep) ); 1347} 1348int Pr_disabled(struct line_list *l) 1349{ 1350 return( Find_flag_value(l,PRINTING_DISABLED,Value_sep) ); 1351} 1352int Sp_disabled(struct line_list *l) 1353{ 1354 return( Find_flag_value(l,SPOOLING_DISABLED,Value_sep) ); 1355} 1356int Pr_aborted(struct line_list *l) 1357{ 1358 return( Find_flag_value(l,PRINTING_ABORTED,Value_sep) ); 1359} 1360int Hld_all(struct line_list *l) 1361{ 1362 return( Find_flag_value(l,HOLD_ALL,Value_sep) ); 1363} 1364char *Clsses(struct line_list *l) 1365{ 1366 return( Find_str_value(l,CLASS,Value_sep) ); 1367} 1368char *Cntrol_debug(struct line_list *l) 1369{ 1370 return( Find_str_value(l,DEBUG,Value_sep) ); 1371} 1372char *Srver_order(struct line_list *l) 1373{ 1374 return( Find_str_value(l,SERVER_ORDER,Value_sep) ); 1375} 1376 1377/* 1378 * Job datastructure management 1379 */ 1380 1381void Init_job( struct job *job ) 1382{ 1383 memset(job,0,sizeof(job[0]) ); 1384} 1385 1386void Free_job( struct job *job ) 1387{ 1388 Free_line_list( &job->info ); 1389 Free_listof_line_list( &job->datafiles ); 1390 Free_line_list( &job->destination ); 1391} 1392 1393void Copy_job( struct job *dest, struct job *src ) 1394{ 1395 Merge_line_list( &dest->info, &src->info, 0,0,0 ); 1396 Merge_listof_line_list( &dest->datafiles, &src->datafiles, 0,0,0 ); 1397 Merge_line_list( &dest->destination, &src->destination, 0,0,0 ); 1398} 1399 1400/************************************************************************** 1401 * static int Fix_job_number(); 1402 * - fixes the job number range and value 1403 **************************************************************************/ 1404 1405char *Fix_job_number( struct job *job, int n ) 1406{ 1407 char buffer[SMALLBUFFER]; 1408 int len = 3, max = 1000; 1409 1410 if( n == 0 ){ 1411 n = Find_decimal_value( &job->info, NUMBER, Value_sep ); 1412 } 1413 if( Long_number_DYN && !Backwards_compatible_DYN ){ 1414 len = 6; 1415 max = 1000000; 1416 } 1417 SNPRINTF(buffer,sizeof(buffer))"%0*d",len, n % max ); 1418 Set_str_value(&job->info,NUMBER,buffer); 1419 return( Find_str_value(&job->info,NUMBER,Value_sep) ); 1420} 1421 1422/************************************************************************ 1423 * Make_identifier - add an identifier field to the job 1424 * the identifier has the format name@host%id 1425 * It is put in the 'A' field on the name. 1426 * 1427 ************************************************************************/ 1428 1429#if defined(JY20031104Make_identifier) 1430char *Make_identifier( struct job *job ) 1431{ 1432 char *user, *host, *s, *id; 1433 char number[32]; 1434 int n; 1435 1436 if( !(s = Find_str_value( &job->info,IDENTIFIER,Value_sep )) ){ 1437 if( !(user = Find_str_value( &job->info,"P",Value_sep ))){ 1438 user = "nobody"; 1439 } 1440 if( !(host= Find_str_value( &job->info,"H",Value_sep ))){ 1441 host = "unknown"; 1442 } 1443 n = Find_decimal_value( &job->info,NUMBER,Value_sep ); 1444 SNPRINTF(number,sizeof(number))"%d",n); 1445 if( (s = safestrchr( host, '.' )) ) *s = 0; 1446 id = safestrdup5(user,"@",host,"+",number,__FILE__,__LINE__); 1447 if( s ) *s = '.'; 1448 Set_str_value(&job->info,IDENTIFIER,id); 1449 if( id ) free(id); id = 0; 1450 s = Find_str_value(&job->info,IDENTIFIER,Value_sep); 1451 } 1452 return(s); 1453} 1454#endif 1455 1456#ifdef ORIGINAL_DEBUG//JY@1020 1457void Dump_job( char *title, struct job *job ) 1458{ 1459 int i; 1460 struct line_list *lp; 1461 if( title ) LOGDEBUG( "*** Job %s *** - 0x%lx", title, Cast_ptr_to_long(job)); 1462#ifdef ORIGINAL_DEBUG//JY@1020 1463 Dump_line_list_sub( "info",&job->info); 1464 LOGDEBUG(" datafiles - count %d", job->datafiles.count ); 1465#endif 1466 for( i = 0; i < job->datafiles.count; ++i ){ 1467 char buffer[SMALLBUFFER]; 1468 SNPRINTF(buffer,sizeof(buffer))" datafile[%d]", i ); 1469 lp = (void *)job->datafiles.list[i]; 1470#ifdef ORIGINAL_DEBUG//JY@1020 1471 Dump_line_list_sub(buffer,lp); 1472#endif 1473 } 1474#ifdef ORIGINAL_DEBUG//JY@1020 1475 Dump_line_list_sub( "destination",&job->destination); 1476#endif 1477 if( title ) LOGDEBUG( "*** end ***" ); 1478} 1479#endif 1480 1481#if defined(JY20031104Job_printable) 1482void Job_printable( struct job *job, struct line_list *spool_control, 1483 int *pprintable, int *pheld, int *pmove, int *perr, int *pdone ) 1484{ 1485 char *s; 1486 char buffer[SMALLBUFFER]; 1487 char destbuffer[SMALLBUFFER]; 1488 struct stat statb; 1489 int n, printable = 0, held = 0, move = 0, error = 0, done = 0,destination, destinations; 1490 1491#ifdef ORIGINAL_DEBUG//JY@1020 1492 if(DEBUGL4)Dump_job("Job_printable - job info",job); 1493 if(DEBUGL4)Dump_line_list("Job_printable - spool control",spool_control); 1494#endif 1495 1496 buffer[0] = 0; 1497 if( job->info.count == 0 ){ 1498 SNPRINTF(buffer,sizeof(buffer)) "removed" ); 1499 } else if( Find_flag_value(&job->info,INCOMING_TIME,Value_sep) ){ 1500 SNPRINTF(buffer,sizeof(buffer)) "incoming" ); 1501 } else if( (error = Find_flag_value(&job->info,ERROR_TIME,Value_sep)) ){ 1502 SNPRINTF(buffer,sizeof(buffer)) "error" ); 1503 } else if( Find_flag_value(&job->info,HOLD_TIME,Value_sep) ){ 1504 SNPRINTF(buffer,sizeof(buffer)) "hold" ); 1505 held = 1; 1506 } else if( (done = Find_flag_value(&job->info,DONE_TIME,Value_sep)) ){ 1507 SNPRINTF(buffer,sizeof(buffer)) "done" ); 1508 } else if( (n = Find_flag_value(&job->info,SERVER,Value_sep)) 1509 && kill( n, 0 ) == 0 ){ 1510 int delta; 1511 time_t now = time((void *)0); 1512 time_t last_change = Find_flag_value(&job->info,START_TIME,Value_sep); 1513 if( !ISNULL(Status_file_DYN) && !stat( Status_file_DYN, &statb ) 1514 && last_change < statb.st_mtime ){ 1515 last_change = statb.st_mtime; 1516 } 1517 if( !ISNULL(Log_file_DYN) && !stat( Log_file_DYN, &statb ) 1518 && last_change < statb.st_mtime ){ 1519 last_change = statb.st_mtime; 1520 } 1521 delta = now - last_change; 1522 if( Stalled_time_DYN && delta > Stalled_time_DYN ){ 1523 SNPRINTF( buffer, sizeof(buffer)) 1524 "stalled(%dsec)", delta ); 1525 } else { 1526 n = Find_flag_value(&job->info,ATTEMPT,Value_sep); 1527 SNPRINTF(buffer,sizeof(buffer)) "active" ); 1528 if( n > 0 ){ 1529 SNPRINTF( buffer, sizeof(buffer)) 1530 "active(attempt-%d)", n+1 ); 1531 } 1532 } 1533 printable = 1; 1534 } else if((s = Find_str_value(&job->info,MOVE,Value_sep)) ){ 1535 SNPRINTF(buffer,sizeof(buffer)) "moved->%s", s ); 1536 move = 1; 1537 } else if( Get_hold_class(&job->info, spool_control ) ){ 1538 SNPRINTF(buffer,sizeof(buffer)) "holdclass" ); 1539 held = 1; 1540 } else { 1541 printable = 1; 1542 } 1543 if( (destinations = Find_flag_value(&job->info,DESTINATIONS,Value_sep)) ){ 1544 printable = 0; 1545 for( destination = 0; destination < destinations; ++destination ){ 1546 Get_destination(job,destination); 1547#ifdef ORIGINAL_DEBUG//JY@1020 1548 if(DEBUGL4)Dump_job("Job_destination_printable - job",job); 1549#endif 1550 destbuffer[0] = 0; 1551 if( Find_flag_value(&job->destination,ERROR_TIME,Value_sep) ){ 1552 SNPRINTF(destbuffer,sizeof(destbuffer)) "error" ); 1553 } else if( Find_flag_value(&job->destination,HOLD_TIME,Value_sep) ){ 1554 SNPRINTF(destbuffer,sizeof(destbuffer)) "hold" ); 1555 held += 1; 1556 } else if( Find_flag_value(&job->destination,DONE_TIME,Value_sep) ){ 1557 SNPRINTF(destbuffer,sizeof(destbuffer)) "done" ); 1558 } else if( (n = Find_flag_value(&job->destination,SERVER,Value_sep)) 1559 && kill( n, 0 ) == 0 ){ 1560 int delta; 1561 n = Find_flag_value(&job->destination,START_TIME,Value_sep); 1562 delta = time((void *)0) - n; 1563 if( Stalled_time_DYN && delta > Stalled_time_DYN ){ 1564 SNPRINTF( destbuffer, sizeof(destbuffer)) 1565 "stalled(%dsec)", delta ); 1566 } else { 1567 n = Find_flag_value(&job->destination,ATTEMPT,Value_sep); 1568 SNPRINTF(destbuffer,sizeof(destbuffer)) "active" ); 1569 if( n > 0 ){ 1570 SNPRINTF( destbuffer, sizeof(destbuffer)) 1571 "active(attempt-%d)", n+1 ); 1572 } 1573 } 1574 printable += 1; 1575 } else if((s = Find_str_value(&job->destination,MOVE,Value_sep)) ){ 1576 SNPRINTF(destbuffer,sizeof(destbuffer)) "moved->%s", s ); 1577 move += 1; 1578 } else if( Get_hold_class(&job->destination, spool_control ) ){ 1579 SNPRINTF(destbuffer,sizeof(destbuffer)) "holdclass" ); 1580 held += 1; 1581 } else { 1582 printable += 1; 1583 } 1584 Set_str_value(&job->destination,PRSTATUS,destbuffer); 1585 Set_flag_value(&job->destination,PRINTABLE,printable); 1586 Set_flag_value(&job->destination,HELD,held); 1587 Update_destination(job); 1588 } 1589 } 1590 1591 Set_str_value(&job->info,PRSTATUS,buffer); 1592 Set_flag_value(&job->info,PRINTABLE,printable); 1593 Set_flag_value(&job->info,HELD,held); 1594 if( pprintable ) *pprintable = printable; 1595 if( pheld ) *pheld = held; 1596 if( pmove ) *pmove = move; 1597 if( perr ) *perr = error; 1598 if( pdone ) *pdone = done; 1599 DEBUG3("Job_printable: printable %d, held %d, move '%d', error '%d', done '%d', status '%s'", 1600 printable, held, move, error, done, buffer ); 1601} 1602#endif 1603 1604#ifdef REMOVE 1605int Server_active( char *file ) 1606{ 1607 struct stat statb; 1608 int serverpid = 0; 1609 int fd = Checkread( file, &statb ); 1610 if( fd >= 0 ){ 1611 serverpid = Read_pid( fd, 0, 0 ); 1612 close(fd); 1613 DEBUG5("Server_active: checking file %s, serverpid %d", file, serverpid ); 1614 if( serverpid && kill(serverpid,0) ){ 1615 serverpid = 0; 1616 } 1617 } 1618 DEBUG3("Server_active: file %s, serverpid %d", file, serverpid ); 1619 return( serverpid ); 1620} 1621#endif 1622 1623/* 1624 * Destination Information 1625 * The destination information is stored in the control file 1626 * as lines of the form: 1627 * NNN=..... where NNN is the destination number 1628 * .... is the escaped destination information 1629 * During normal printing or other activity, the destination information 1630 * is unpacked into the job->destination line list. 1631 */ 1632 1633/* 1634 * Update_destination updates the information with the values in the 1635 * job->destination line list. 1636 */ 1637void Update_destination( struct job *job ) 1638{ 1639 char *s, *t, buffer[SMALLBUFFER]; 1640 int id; 1641 id = Find_flag_value(&job->destination,DESTINATION,Value_sep); 1642 SNPRINTF(buffer,sizeof(buffer))"DEST%d",id); 1643 s = Join_line_list(&job->destination,"\n"); 1644 t = Escape(s,1); 1645 Set_str_value(&job->info,buffer,t); 1646 free(s); 1647 free(t); 1648#ifdef ORIGINAL_DEBUG//JY@1020 1649 if(DEBUGL4)Dump_job("Update_destination",job); 1650#endif 1651} 1652 1653/* 1654 * Get_destination puts the requested information into the 1655 * job->destination structure if it is available. 1656 * returns: 1 if not found, 0 if found; 1657 */ 1658 1659int Get_destination( struct job *job, int n ) 1660{ 1661 char buffer[SMALLBUFFER]; 1662 char *s; 1663 int result = 1; 1664 1665 SNPRINTF(buffer,sizeof(buffer)) "DEST%d", n ); 1666 1667 Free_line_list(&job->destination); 1668 if( (s = Find_str_value(&job->info,buffer,Value_sep)) ){ 1669 s = safestrdup(s,__FILE__,__LINE__); 1670 Unescape(s); 1671 Split(&job->destination,s,Line_ends,1,Value_sep,1,1,1,0); 1672 if(s) free( s ); s = 0; 1673 result = 0; 1674 } 1675 return( result ); 1676} 1677 1678/* 1679 * Get_destination_by_name puts the requested information into the 1680 * job->destination structure if it is available. 1681 * returns: 1 if not found, 0 if found; 1682 */ 1683 1684int Get_destination_by_name( struct job *job, char *name ) 1685{ 1686 int result = 1; 1687 char *s; 1688 1689 Free_line_list(&job->destination); 1690 if( name && (s = Find_str_value(&job->info,name,Value_sep)) ){ 1691 s = safestrdup(s,__FILE__,__LINE__); 1692 Unescape(s); 1693 Split(&job->destination,s,Line_ends,1,Value_sep,1,1,1,0); 1694 if(s) free( s ); s = 0; 1695 result = 0; 1696 } 1697 return( result ); 1698} 1699 1700/* 1701 * Trim_status_file - trim a status file to an acceptible length 1702 */ 1703 1704int Trim_status_file( int status_fd, char *file, int max, int min ) 1705{ 1706 int tempfd, status; 1707 char buffer[LARGEBUFFER]; 1708 struct stat statb; 1709 char *tempfile, *s; 1710 int count; 1711 1712 tempfd = status = -1; 1713 1714 DEBUG1("Trim_status_file: file '%s' max %d, min %d", file, max, min); 1715 1716 /* if the file does not exist, do not create it */ 1717 if( ISNULL(file) ) return( status_fd ); 1718 if( stat( file, &statb ) == 0 ){ 1719 DEBUG1("Trim_status_file: '%s' max %d, min %d, size %ld", file, max, min, 1720 (long)(statb.st_size) ); 1721 if( max > 0 && statb.st_size/1024 > max ){ 1722 status = Checkwrite( file, &statb,O_RDWR,0,0); 1723 tempfd = Make_temp_fd(&tempfile); 1724 if( min > max || min == 0 ){ 1725 min = max/4; 1726 } 1727 if( min == 0 ) min = 1; 1728 DEBUG1("Trim_status_file: trimming to %d K", min); 1729 lseek( status, 0, SEEK_SET ); 1730 lseek( status, -min*1024, SEEK_END ); 1731 while( (count = read( status, buffer, sizeof(buffer) - 1 ) ) > 0 ){ 1732 buffer[count] = 0; 1733 if( (s = safestrchr(buffer,'\n')) ){ 1734 *s++ = 0; 1735 Write_fd_str( tempfd, s ); 1736 break; 1737 } 1738 } 1739 while( (count = read( status, buffer, sizeof(buffer) ) ) > 0 ){ 1740 if( write( tempfd, buffer, count) < 0 ){ 1741 Errorcode = JABORT; 1742 LOGERR_DIE(LOG_ERR) "Trim_status_file: cannot write tempfile" ); 1743 } 1744 } 1745 lseek( tempfd, 0, SEEK_SET ); 1746 lseek( status, 0, SEEK_SET ); 1747 ftruncate( status, 0 ); 1748 while( (count = read( tempfd, buffer, sizeof(buffer) ) ) > 0 ){ 1749 if( write( status, buffer, count) < 0 ){ 1750 Errorcode = JABORT; 1751 LOGERR_DIE(LOG_ERR) "Trim_status_file: cannot write tempfile" ); 1752 } 1753 } 1754 unlink(tempfile); 1755 close(status); 1756 } 1757 close( tempfd ); 1758 if( status_fd > 0 ) close( status_fd ); 1759 status_fd = Checkwrite( file, &statb,0,0,0); 1760 } 1761 return( status_fd ); 1762} 1763 1764/******************************************************************** 1765 * int Fix_control( struct job *job, char *order ) 1766 * fix the order of lines in the control file so that they 1767 * are in the order of the letters in the order string. 1768 * Lines are checked for metacharacters and other trashy stuff 1769 * that might have crept in by user efforts 1770 * 1771 * job - control file area in memory 1772 * order - order of options 1773 * 1774 * order string: Letter - relative position in file 1775 * * matches any character not in string 1776 * can have only one wildcard in string 1777 * Berkeley- HPJCLIMWT1234 1778 * PLP- HPJCLIMWT1234* 1779 * 1780 * RETURNS: 0 if fixed correctly 1781 * non-zero if there is something wrong with this file and it should 1782 * be rejected out of hand 1783 ********************************************************************/ 1784 1785/******************************************************************** 1786 * BSD and LPRng order 1787 * We use these values to determine the order of jobs in the file 1788 * The order of the characters determines the order of the options 1789 * in the control file. A * puts all unspecified options there 1790 ********************************************************************/ 1791 1792 static char BSD_order[] = "HPJCLIMWT1234" ; 1793 static char LPRng_order[] = "HPJCLIMWT1234*" ; 1794 1795#if defined(JY20031104Fix_datafile_info) 1796char *Fix_datafile_info( struct job *job, char *number, char *suffix, 1797 char *xlate_format ) 1798{ 1799 int i, copies, linecount, count, jobcopies, copy, group, offset; 1800 char *s, *Nline, *transfername, *dataline, *jobline; 1801 struct line_list *lp, outfiles; 1802 char prefix[8]; 1803 char fmt[2]; 1804 1805 Init_line_list(&outfiles); 1806 transfername = dataline = Nline = jobline = 0; 1807#ifdef ORIGINAL_DEBUG//JY@1020 1808 if(DEBUGL4)Dump_job("Fix_datafile_info - starting", job ); 1809#endif 1810 1811 /* now we find the number of different data files */ 1812 1813 count = 0; 1814 /* we look through the data file list, looking for jobs with the name 1815 * TRANSFERNAME. If we find a new one, we create the correct form 1816 * of the job datafile 1817 */ 1818 for( linecount = 0; linecount < job->datafiles.count; ++linecount ){ 1819 lp = (void *)job->datafiles.list[linecount]; 1820 transfername = Find_str_value(lp,TRANSFERNAME,Value_sep); 1821 Set_str_value(lp,OTRANSFERNAME,transfername); 1822 if( !(s = Find_casekey_str_value(&outfiles,transfername,Value_sep)) ){ 1823 /* we add the entry */ 1824 offset = count % 52; 1825 group = count / 52; 1826 ++count; 1827 if( (group >= 52) ){ 1828 FATAL(LOG_INFO)"Fix_datafile_info: too many data files"); 1829 } 1830 SNPRINTF(prefix,sizeof(prefix))"d%c%c", 1831 ("fghijklmnopqrstuvwxyzabcde" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" )[group], 1832 ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz")[offset] ); 1833 s = safestrdup3(prefix,number,suffix,__FILE__,__LINE__); 1834 if( transfername ) Set_casekey_str_value(&outfiles,transfername,s); 1835 Set_str_value(lp,TRANSFERNAME,s); 1836 if(s) free(s); s = 0; 1837 } else { 1838 Set_str_value(lp,TRANSFERNAME,s); 1839 } 1840 } 1841 Free_line_list(&outfiles); 1842 Set_decimal_value(&job->info,DATAFILE_COUNT,count); 1843 1844#ifdef ORIGINAL_DEBUG//JY@1020 1845 if(DEBUGL4)Dump_job("Fix_datafile_info - after finding duplicates", job ); 1846#endif 1847 1848 jobcopies = Find_flag_value(&job->info,COPIES,Value_sep); 1849 if( !jobcopies ) jobcopies = 1; 1850 fmt[0] = 'f'; fmt[1] = 0; 1851 DEBUG4("Fix_datafile_info: jobcopies %d", jobcopies ); 1852 for(copy = 0; copy < jobcopies; ++copy ){ 1853 for( linecount = 0; linecount < job->datafiles.count; ++linecount ){ 1854 jobline = 0; 1855 lp = (void *)job->datafiles.list[linecount]; 1856#ifdef ORIGINAL_DEBUG//JY@1020 1857 if(DEBUGL5)Dump_line_list("Fix_datafile_info - info", lp ); 1858#endif 1859 transfername = Find_str_value(lp,TRANSFERNAME,Value_sep); 1860 Nline = Find_str_value(lp,"N",Value_sep); 1861 fmt[0] = 'f'; 1862 if( (s = Find_str_value(lp,FORMAT,Value_sep)) ){ 1863 fmt[0] = *s; 1864 } 1865 if( xlate_format ){ 1866 int l = safestrlen(xlate_format); 1867 for( i = 0; i+1 < l; i+= 2 ){ 1868 if( (xlate_format[i] == fmt[0]) 1869 || (xlate_format[i] == '*') ){ 1870 fmt[0] = xlate_format[i+1]; 1871 break; 1872 } 1873 } 1874 } 1875 copies = Find_flag_value(lp,COPIES,Value_sep); 1876 if( copies == 0 ) copies = 1; 1877 for(i = 0; i < copies; ++i ){ 1878 if( Nline && !Nline_after_file_DYN ){ 1879 jobline = safeextend4(jobline,"N",Nline,"\n",__FILE__,__LINE__); 1880 } 1881 jobline = safeextend4(jobline,fmt,transfername,"\n",__FILE__,__LINE__); 1882 if( Nline && Nline_after_file_DYN ){ 1883 jobline = safeextend4(jobline,"N",Nline,"\n",__FILE__,__LINE__); 1884 } 1885 } 1886 DEBUG4("Fix_datafile_info: file [%d], jobline '%s'", 1887 linecount, jobline); 1888 dataline = safeextend2(dataline,jobline,__FILE__,__LINE__); 1889 if( jobline ) free(jobline); jobline = 0; 1890 } 1891 } 1892 DEBUG4("Fix_datafile_info: adding remove lines" ); 1893 for( linecount = 0; linecount < job->datafiles.count; ++linecount ){ 1894 jobline = 0; 1895 lp = (void *)job->datafiles.list[linecount]; 1896#ifdef ORIGINAL_DEBUG//JY@1020 1897 if(DEBUGL4)Dump_line_list("Fix_datafile_info - info", lp ); 1898#endif 1899 transfername = Find_str_value(lp,TRANSFERNAME,Value_sep); 1900 if( !Find_casekey_str_value(&outfiles,transfername,Value_sep) ){ 1901 jobline = safeextend4(jobline,"U",transfername,"\n",__FILE__,__LINE__); 1902 Set_casekey_str_value(&outfiles,transfername,"YES"); 1903 } 1904 DEBUG4("Fix_datafile_info: file [%d], jobline '%s'", 1905 linecount, jobline); 1906 dataline = safeextend2(dataline,jobline,__FILE__,__LINE__); 1907 if( jobline ) free(jobline); jobline = 0; 1908 } 1909 Free_line_list(&outfiles); 1910 Set_str_value(&job->info,DATAFILES,dataline); 1911 s = Find_str_value(&job->info,DATAFILES,Value_sep); 1912 while( (s = safestrchr(s,'\n')) ) *s++ = '\001'; 1913 return(dataline); 1914} 1915#endif 1916 1917int ordercomp( const void *left, const void *right, const void *orderp) 1918{ 1919 const char *lpos, *rpos, *wildcard, *order; 1920 int cmp; 1921 1922 order = (const char *)orderp; 1923 1924 /* blank lines always come last */ 1925 if( (wildcard = safestrchr( order, '*' )) ){ 1926 wildcard = order + safestrlen(order); 1927 } 1928 lpos = *((const char **)left); 1929 if( lpos == 0 || *lpos == 0 ){ 1930 lpos = order+safestrlen(order); 1931 } else if( !(lpos = safestrchr( order, *lpos )) ){ 1932 lpos = wildcard; 1933 } 1934 rpos = *((const char **)right); 1935 if( rpos == 0 || *rpos == 0 ){ 1936 rpos = order+safestrlen(order); 1937 } else if( !(rpos = safestrchr( order, *rpos )) ){ 1938 rpos = wildcard; 1939 } 1940 cmp = lpos - rpos; 1941 DEBUG4("ordercomp '%s' to '%s' -> %d", 1942 *((const char **)left), *((const char **)right), cmp ); 1943 return( cmp ); 1944} 1945 1946/************************************************************************ 1947 * Fix_control: 1948 * Fix up the control file, setting the various entries 1949 * to be compatible with transfer to the remote location 1950 * 1. info will have fromhost, priority, and number information 1951 * if not, you will need to add it. 1952 * 1953 ************************************************************************/ 1954 1955 struct maxlen{ 1956 int c, len; 1957 } maxclen[] = { 1958 { 'A', 131 }, { 'C', 31 }, { 'D', 1024 }, { 'H', 31 }, { 'I', 31 }, 1959 { 'J', 99 }, { 'L', 31 }, { 'N', 131 }, { 'M', 131 }, { 'N', 131 }, 1960 { 'P', 31 }, { 'Q', 131 }, { 'R', 131 }, { 'S', 131 }, { 'T', 79 }, 1961 { 'U', 131 }, { 'W', 31 }, { 'Z', 1024 }, { '1', 131 }, { '2', 131 }, 1962 { '3', 131 }, { '4', 131 }, 1963 {0,0} 1964 }; 1965 1966#ifdef ORIGINAL_DEBUG//JY@1020 1967void Fix_control( struct job *job, char *filter, char *xlate_format ) 1968{ 1969 char *s, *file_hostname, *number, *priority, 1970 *order; 1971 char buffer[SMALLBUFFER], pr[2]; 1972 int tempfd, tempfc; 1973 int i, n, j, cccc, wildcard, len; 1974 struct line_list controlfile; 1975 1976 Init_line_list(&controlfile); 1977 1978#ifdef ORIGINAL_DEBUG//JY@1020 1979 if(DEBUGL3) Dump_job( "Fix_control: starting", job ); 1980#endif 1981 1982 /* we set the control file with the single letter values in the 1983 hold job file 1984 */ 1985 for( i = 0; i < job->info.count; ++i ){ 1986 int c; 1987 s = job->info.list[i]; 1988 if( s && (c = s[0]) && isupper(c) && c != 'N' && c != 'U' 1989 && s[1] == '=' ){ 1990 /* remove banner from control file */ 1991 if( c == 'L' && Suppress_header_DYN && !Always_banner_DYN ) continue; 1992 s[1] = 0; 1993 Add_line_list( &controlfile, s, Value_sep, 1, 1 ); 1994 Set_str_value(&controlfile,s,s+2); 1995 s[1] = '='; 1996 } 1997 } 1998 1999#ifdef ORIGINAL_DEBUG//JY@1020 2000 if(DEBUGL3) Dump_line_list( "Fix_control: control file", &controlfile ); 2001#endif 2002 2003 n = j = 0; 2004 n = Find_decimal_value( &job->info,NUMBER,Value_sep); 2005 j = Find_decimal_value( &job->info,SEQUENCE,Value_sep); 2006 2007 number = Fix_job_number(job, n+j); 2008 2009 if( !(priority = Find_str_value( &job->destination,PRIORITY,Value_sep)) 2010 && !(priority = Find_str_value( &job->info,PRIORITY,Value_sep)) 2011 && !(priority = Default_priority_DYN) ){ 2012 priority = "A"; 2013 } 2014 pr[0] = *priority; 2015 pr[1] = 0; 2016 2017 file_hostname = Find_str_value(&job->info,FILE_HOSTNAME,Value_sep); 2018 2019 if( !file_hostname ){ 2020 file_hostname = Find_str_value(&job->info,FROMHOST,Value_sep); 2021 if( file_hostname == 0 || *file_hostname == 0 ){ 2022 file_hostname = FQDNHost_FQDN; 2023 } 2024 Set_str_value(&job->info,FILE_HOSTNAME,file_hostname); 2025 file_hostname = Find_str_value(&job->info,FILE_HOSTNAME,Value_sep); 2026 } 2027 2028 if( (Backwards_compatible_DYN || Use_shorthost_DYN) 2029 && (s = safestrchr( file_hostname, '.' )) ){ 2030 *s = 0; 2031 } 2032 2033#ifdef ORIGINAL_DEBUG//JY@1020 2034 if(DEBUGL3) Dump_job( "Fix_control: before fixing", job ); 2035#endif 2036 2037 /* fix control file name */ 2038 2039 s = safestrdup4("cf",pr,number,file_hostname,__FILE__,__LINE__); 2040 Set_str_value(&job->info,TRANSFERNAME,s); 2041 if(s) free(s); s = 0; 2042 2043 /* fix control file contents */ 2044 2045 s = Make_identifier( job ); 2046 2047 if( job->destination.count == 0 ){ 2048 Set_str_value(&controlfile,IDENTIFIER,s); 2049 } else { 2050 s = Find_str_value(&job->destination,IDENTIFIER,Value_sep); 2051 cccc = Find_flag_value(&job->destination,COPIES,Value_sep); 2052 n = Find_flag_value(&job->destination,COPY_DONE,Value_sep); 2053 if( cccc > 1 ){ 2054 SNPRINTF(buffer,sizeof(buffer))"C%d",n+1); 2055 s = safestrdup2(s,buffer,__FILE__,__LINE__); 2056 Set_str_value(&controlfile,IDENTIFIER,s); 2057 if(s) free(s); s = 0; 2058 } else { 2059 Set_str_value(&controlfile,IDENTIFIER,s); 2060 } 2061 } 2062 if( !Find_str_value(&controlfile,DATE,Value_sep) ){ 2063 Set_str_value(&controlfile,DATE, Time_str( 0, 0 ) ); 2064 } 2065 if( (Use_queuename_DYN || Force_queuename_DYN) && 2066 !Find_str_value(&controlfile,QUEUENAME,Value_sep) ){ 2067 s = Force_queuename_DYN; 2068 if( s == 0 ) s = Queue_name_DYN; 2069 if( s == 0 ) s = Printer_DYN; 2070 Set_str_value(&controlfile,QUEUENAME, s ); 2071 } 2072 2073 /* fix up the control file lines overrided by routing */ 2074 buffer[1] = 0; 2075 for( i = 0; i < job->destination.count; ++i ){ 2076 s = job->destination.list[i]; 2077 cccc = cval(s); 2078 buffer[0] = cccc; 2079 if( isupper(cccc) && Find_str_value(&controlfile,buffer,Value_sep) ){ 2080 Set_str_value( &controlfile,buffer,s+1); 2081 } 2082 } 2083 2084 order = Control_file_line_order_DYN; 2085 if( !order && Backwards_compatible_DYN ){ 2086 order = BSD_order; 2087 } else if( !order ){ 2088 order = LPRng_order; 2089 } 2090 wildcard = (safestrchr( order,'*') != 0); 2091 2092 /* 2093 * remove any line not required and fix up line metacharacters 2094 */ 2095 2096 buffer[1] = 0; 2097 for( i = 0; i < controlfile.count; ){ 2098 /* get line and first character on line */ 2099 s = controlfile.list[i]; 2100 cccc = *s; 2101 buffer[0] = cccc; 2102 /* remove any non-listed options */ 2103 if( (!isupper(cccc) && !isdigit(cccc)) || (!safestrchr(order, cccc) && !wildcard) ){ 2104 Set_str_value( &controlfile,buffer,0); 2105 } else { 2106 if( Backwards_compatible_DYN ){ 2107 for( j = 0; maxclen[j].c && cccc != maxclen[j].c ; ++j ); 2108 if( (len = maxclen[j].len) && safestrlen(s+1) > len ){ 2109 s[len+1] = 0; 2110 } 2111 } 2112 ++i; 2113 } 2114 } 2115 2116 /* 2117 * we check to see if order is correct - we need to check to 2118 * see if allowed options in file first. 2119 */ 2120 2121#ifdef ORIGINAL_DEBUG//JY@1020 2122 if(DEBUGL3)Dump_line_list( "Fix_control: before sorting", &controlfile ); 2123#endif 2124 n = Mergesort( controlfile.list, 2125 controlfile.count, sizeof( char *), ordercomp, order ); 2126 if( n ){ 2127 Errorcode = JABORT; 2128 LOGERR_DIE(LOG_ERR) "Fix_control: Mergesort failed" ); 2129 } 2130 2131#ifdef ORIGINAL_DEBUG//JY@1020 2132 if(DEBUGL3) Dump_job( "Fix_control: after sorting", job ); 2133#endif 2134 for( i = 0; i < controlfile.count; ++i ){ 2135 s = controlfile.list[i]; 2136 memmove(s+1,s+2,safestrlen(s+2)+1); 2137 } 2138 s = 0; 2139 2140 { 2141 char *datalines; 2142 char *temp = Join_line_list(&controlfile,"\n"); 2143 DEBUG3( "Fix_control: control info '%s'", temp ); 2144 2145 datalines = Fix_datafile_info( job, number, file_hostname, xlate_format ); 2146 DEBUG3( "Fix_control: data info '%s'", datalines ); 2147 temp = safeextend2(temp,datalines,__FILE__,__LINE__); 2148 if( datalines ) free(datalines); datalines = 0; 2149 Set_str_value(&job->info,CF_OUT_IMAGE,temp); 2150 if( temp ) free(temp); temp = 0; 2151 } 2152 2153 if( filter ){ 2154 DEBUG3("Fix_control: filter '%s'", filter ); 2155 2156 tempfd = Make_temp_fd( 0 ); 2157 tempfc = Make_temp_fd( 0 ); 2158 s = Find_str_value(&job->info,CF_OUT_IMAGE,Value_sep ); 2159 if( Write_fd_str( tempfc, s ) < 0 ){ 2160 Errorcode = JFAIL; 2161 LOGERR_DIE(LOG_INFO) "Fix_control: write to tempfile failed" ); 2162 } 2163 if( lseek( tempfc, 0, SEEK_SET ) == -1 ){ 2164 Errorcode = JFAIL; 2165 LOGERR_DIE(LOG_INFO) "Fix_control: lseek failed" ); 2166 } 2167 if( (n = Filter_file( tempfc, tempfd, "CONTROL_FILTER", 2168 filter, Filter_options_DYN, job, 0, 1 )) ){ 2169 Errorcode = n; 2170 LOGERR_DIE(LOG_ERR) "Fix_control: control filter failed with status '%s'", 2171 Server_status(n) ); 2172 } 2173 s = 0; 2174 if( n < 0 ){ 2175 Errorcode = JFAIL; 2176 LOGERR_DIE(LOG_INFO) "Fix_control: read from tempfd failed" ); 2177 } 2178 s = Get_fd_image( tempfd, 0 ); 2179 if( s == 0 || *s == 0 ){ 2180 Errorcode = JFAIL; 2181 LOGERR_DIE(LOG_INFO) "Fix_control: zero length control filter output" ); 2182 } 2183 DEBUG4("Fix_control: control filter output '%s'", s); 2184 Set_str_value(&job->info,CF_OUT_IMAGE,s); 2185 if(s) free(s); s = 0; 2186 close( tempfc ); tempfc = -1; 2187 close( tempfd ); tempfd = -1; 2188 } 2189} 2190#endif 2191 2192/************************************************************************ 2193 * Create_control: 2194 * Create the control file, setting the various entries. This is done 2195 * on job submission. 2196 * 2197 ************************************************************************/ 2198 2199#if defined(JY20031104Create_control) 2200int Create_control( struct job *job, char *error, int errlen, 2201 char *xlate_format ) 2202{ 2203 char *fromhost, *file_hostname, *number, *priority, *openname; 2204 int status = 0, fd, i; 2205 struct stat statb; 2206 2207#ifdef ORIGINAL_DEBUG//JY@1020 2208 if(DEBUGL3) Dump_job( "Create_control: before fixing", job ); 2209#endif 2210 2211 /* deal with authentication */ 2212 2213 Make_identifier( job ); 2214 2215 if( !(fromhost = Find_str_value(&job->info,FROMHOST,Value_sep)) || Is_clean_name(fromhost) ){ 2216 Set_str_value(&job->info,FROMHOST,FQDNRemote_FQDN); 2217 fromhost = Find_str_value(&job->info,FROMHOST,Value_sep); 2218 } 2219 /* 2220 * accounting name fixup 2221 * change the accounting name ('R' field in control file) 2222 * based on hostname 2223 * hostname(,hostname)*=($K|value)*(;hostname(,hostname)*=($K|value)*)* 2224 * we have a semicolon separated list of entrires 2225 * the RemoteHost_IP is compared to these. If a match is found then the 2226 * user name (if any) is used for the accounting name. 2227 * The user name list has the format: 2228 * ${K} - value from control file or printcap entry - you must use the 2229 * ${K} format. 2230 * username - user name value to substitute. 2231 */ 2232 if( Accounting_namefixup_DYN ){ 2233 struct line_list l, listv; 2234 char *accounting_name = 0; 2235 Init_line_list(&l); 2236 Init_line_list(&listv); 2237 2238 DEBUG1("Create_control: Accounting_namefixup '%s'", Accounting_namefixup_DYN ); 2239 Split(&listv,Accounting_namefixup_DYN,";",0,0,0,0,0,0); 2240 for( i = 0; i < listv.count; ++i ){ 2241 char *s, *t; 2242 int j; 2243 s = listv.list[i]; 2244 if( (t = safestrpbrk(s,"=")) ) *t++ = 0; 2245 Free_line_list(&l); 2246 DEBUG1("Create_control: hostlist '%s'", s ); 2247 Split(&l,s,",",0,0,0,0,0,0); 2248 if( Match_ipaddr_value(&l,&RemoteHost_IP) ){ 2249 Free_line_list(&l); 2250 DEBUG1("Create_control: match, using users '%s'", t ); 2251 Split(&l,t,",",0,0,0,0,0,0); 2252#ifdef ORIGINAL_DEBUG//JY@1020 2253 if(DEBUGL1)Dump_line_list("Create_control: before Fix_dollars", &l ); 2254#endif 2255 Fix_dollars(&l,job,0,0); 2256#ifdef ORIGINAL_DEBUG//JY@1020 2257 if(DEBUGL1)Dump_line_list("Create_control: after Fix_dollars", &l ); 2258#endif 2259 for( j = 0; j < l.count; ++j ){ 2260 if( !ISNULL(l.list[j]) ){ 2261 accounting_name = l.list[j]; 2262 break; 2263 } 2264 } 2265 break; 2266 } 2267 } 2268 DEBUG1("Create_control: accounting_name '%s'", accounting_name ); 2269 if( !ISNULL(accounting_name) ){ 2270 Set_str_value(&job->info,ACCNTNAME,accounting_name ); 2271 } 2272 Free_line_list(&l); 2273 Free_line_list(&listv); 2274 } 2275 2276 if( Force_IPADDR_hostname_DYN ){ 2277 char buffer[SMALLBUFFER]; 2278 const char *const_s; 2279 int family; 2280 /* We will need to create a dummy record. - no host */ 2281 family = RemoteHost_IP.h_addrtype; 2282 const_s = (char *)inet_ntop( family, RemoteHost_IP.h_addr_list.list[0], 2283 buffer, sizeof(buffer) ); 2284 DEBUG1("Create_control: remotehost '%s'", const_s ); 2285 Set_str_value(&job->info,FROMHOST,const_s); 2286 fromhost = Find_str_value(&job->info,FROMHOST,Value_sep); 2287 } 2288 { 2289 char *s, *t; 2290 if( Force_FQDN_hostname_DYN && !safestrchr(fromhost,'.') 2291 && (t = safestrchr(FQDNRemote_FQDN,'.')) ){ 2292 s = safestrdup2(fromhost, t, __FILE__,__LINE__ ); 2293 Set_str_value(&job->info,FROMHOST,s); 2294 if( s ) free(s); s = 0; 2295 fromhost = Find_str_value(&job->info,FROMHOST,Value_sep); 2296 } 2297 } 2298 2299 2300 if( !Find_str_value(&job->info,DATE,Value_sep) ){ 2301 char *s = Time_str(0,0); 2302 Set_str_value(&job->info,DATE,s); 2303 } 2304 if( (Use_queuename_DYN || Force_queuename_DYN) 2305 && !Find_str_value(&job->info,QUEUENAME,Value_sep) ){ 2306 char *s = Force_queuename_DYN; 2307 if( s == 0 ) s = Queue_name_DYN; 2308 if( s == 0 ) s = Printer_DYN; 2309 Set_str_value(&job->info,QUEUENAME,s); 2310 Set_DYN(&Queue_name_DYN,s); 2311 } 2312 if( Hld_all(&Spool_control) || Auto_hold_DYN ){ 2313 Set_flag_value( &job->info,HOLD_TIME,time((void *)0) ); 2314 } else { 2315 Set_flag_value( &job->info,HOLD_TIME,0); 2316 } 2317 2318 number = Find_str_value( &job->info,NUMBER,Value_sep); 2319 2320 priority = Find_str_value( &job->info,PRIORITY,Value_sep); 2321 if( !priority ){ 2322 priority = Default_priority_DYN; 2323 if( !priority ) priority = "A"; 2324 Set_str_value(&job->info,PRIORITY,priority); 2325 priority = Find_str_value(&job->info,PRIORITY,Value_sep); 2326 } 2327 2328 file_hostname = Find_str_value(&job->info,FROMHOST,Value_sep); 2329 if( ISNULL(file_hostname) ) file_hostname = FQDNRemote_FQDN; 2330 if( ISNULL(file_hostname) ) file_hostname = FQDNHost_FQDN; 2331 2332 if( isdigit(cval(file_hostname)) ){ 2333 char * s = safestrdup2("ADDR",file_hostname,__FILE__,__LINE__); 2334 Set_str_value(&job->info,FILE_HOSTNAME,s); 2335 if( s ) free(s); s = 0; 2336 } else { 2337 Set_str_value(&job->info,FILE_HOSTNAME,file_hostname); 2338 } 2339 file_hostname = Find_str_value(&job->info,FILE_HOSTNAME,Value_sep); 2340 2341 /* fix Z options */ 2342 Fix_Z_opts( job ); 2343 /* fix control file name */ 2344 2345 { 2346 char *s = safestrdup4("cf",priority,number,file_hostname,__FILE__,__LINE__); 2347 Set_str_value(&job->info,TRANSFERNAME,s); 2348 if(s) free(s); s = 0; 2349 } 2350 2351 { 2352 /* now we generate the control file image by getting the info 2353 * from the hold file 2354 */ 2355 char *cf, *datalines; 2356 cf = datalines = 0; 2357 for( i = 0; i < job->info.count; ++i ){ 2358 char *t = job->info.list[i]; 2359 int c; 2360 if( t && (c = t[0]) && isupper(c) && c != 'N' && c != 'U' 2361 && t[1] == '=' ){ 2362 t[1] = 0; 2363 cf = safeextend4(cf,t,t+2,"\n",__FILE__,__LINE__); 2364 t[1] = '='; 2365 } 2366 } 2367 2368 DEBUG4("Create_control: first part '%s'", cf ); 2369 datalines = Fix_datafile_info( job, number, file_hostname, xlate_format ); 2370 DEBUG4("Create_control: data info '%s'", datalines ); 2371 cf = safeextend2(cf,datalines,__FILE__,__LINE__); 2372 DEBUG4("Create_control: joined '%s'", cf ); 2373 if( datalines ) free(datalines); datalines = 0; 2374 2375 openname = Find_str_value(&job->info,OPENNAME,Value_sep); 2376 if( !openname ) openname = Find_str_value(&job->info,TRANSFERNAME,Value_sep); 2377 DEBUG4("Create_control: writing to '%s'", openname ); 2378 if( (fd = Checkwrite(openname,&statb,0,1,0)) < 0 2379 || ftruncate(fd,0) || Write_fd_str(fd,cf) < 0 ){ 2380#ifdef ORIGINAL_DEBUG//JY@1020 2381 SNPRINTF(error,errlen)"Write_control: cannot write '%s' - '%s'", 2382 openname, Errormsg(errno) ); 2383#endif 2384 status = 1; 2385 } 2386 Max_open(fd); 2387 if( fd > 0 ) close(fd); fd = -1; 2388 if( cf ) free(cf); cf = 0; 2389 } 2390 2391 2392 return( status ); 2393} 2394#endif 2395 2396/* 2397 * Buffer management 2398 * Set up and put values into an output buffer for 2399 * transmission at a later time 2400 */ 2401void Init_buf(char **buf, int *max, int *len) 2402{ 2403 DEBUG4("Init_buf: buf 0x%lx, max %d, len %d", 2404 Cast_ptr_to_long(*buf), *max, *len ); 2405 if( *max <= 0 ) *max = LARGEBUFFER; 2406 if( *buf == 0 ) *buf = realloc_or_die( *buf, *max+1,__FILE__,__LINE__); 2407 *len = 0; 2408 (*buf)[0] = 0; 2409} 2410 2411void Put_buf_len( const char *s, int cnt, char **buf, int *max, int *len ) 2412{ 2413 DEBUG4("Put_buf_len: starting- buf 0x%lx, max %d, len %d, adding %d", 2414 Cast_ptr_to_long(*buf), *max, *len, cnt ); 2415 if( s == 0 || cnt <= 0 ) return; 2416 if( *max - *len <= cnt ){ 2417 *max += ((LARGEBUFFER + cnt )/1024)*1024; 2418 *buf = realloc_or_die( *buf, *max+1,__FILE__,__LINE__); 2419 DEBUG4("Put_buf_len: update- buf 0x%lx, max %d, len %d", 2420 Cast_ptr_to_long(*buf), *max, *len); 2421 if( !*buf ){ 2422 Errorcode = JFAIL; 2423 LOGERR_DIE(LOG_INFO)"Put_buf_len: realloc %d failed", *len ); 2424 } 2425 } 2426 memcpy( *buf+*len, s, cnt ); 2427 *len += cnt; 2428 (*buf)[*len] = 0; 2429} 2430 2431void Put_buf_str( const char *s, char **buf, int *max, int *len ) 2432{ 2433 if( s && *s ) Put_buf_len( s, safestrlen(s), buf, max, len ); 2434} 2435 2436void Free_buf(char **buf, int *max, int *len) 2437{ 2438 if( *buf ) free(*buf); *buf = 0; 2439 *len = 0; 2440 *max = 0; 2441} 2442