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: lpd_jobs.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $"; 28 29#include "lp.h" 30#include "accounting.h" 31#include "child.h" 32#include "errorcodes.h" 33#include "fileopen.h" 34#include "gethostinfo.h" 35#include "getopt.h" 36#include "getprinter.h" 37#include "getqueue.h" 38#include "linksupport.h" 39#include "lockfile.h" 40#include "lpd_remove.h" 41#include "merge.h" 42#include "permission.h" 43#include "printjob.h" 44#include "proctitle.h" 45#include "sendjob.h" 46#include "sendmail.h" 47#include "stty.h" 48 49#include "lpd_jobs.h" 50#include "lpd_rcvjob.h" 51 52#if defined(USER_INCLUDE) 53# include USER_INCLUDE 54#else 55# if defined(CHOOSER_ROUTINE) 56# error No 'USER_INCLUDE' file with function prototypes specified 57 You need an include file with function prototypes 58# endif 59#endif 60 61 62/**** ENDINCLUDE ****/ 63 64#ifdef REMOVE 65/*************************************************************************** 66 * Commentary: 67 * Patrick Powell Thu May 11 09:26:48 PDT 1995 68 * 69 * Job processing algorithm 70 * 71 * 1. Check to see if there is already a spooler process active. 72 * The active file will contain the PID of the active spooler process. 73 * 2. Build the job queue 74 * 3. For each job in the job queue, service them. 75 * 76 * MULTIPLE Servers for a Single Queue. 77 * In the printcap, the "sv" flag sets the Server_names_DYN variable with 78 * the list of servers to be used for this queue. The "ss" flag sets 79 * the Server_queue_name_DYN flag with the queue that this is a server for. 80 * 81 * Under normal conditions, the following process hierarchy is used: 82 * 83 * server process - printer 'spool queue' 84 * subserver process - first printer in 'Server_name' 85 * subserver process - second printer in 'Server_name' 86 * ... 87 * 88 * The server process does the following: 89 * for each printer in the Server_name list 90 * sort them by the last order that you had in the control file 91 * for each printer in the Server_name list 92 * check the status of the queue, and gets the control file 93 * information and the numbers of jobs waiting. 94 * for each printer in the Server_name list 95 * if printable jobs and printing enabled 96 * start up a subserver 97 * 98 * while(1){ 99 * for all printable jobs do 100 * check to see if there is a queue for them to be 101 * printed on and the the queue is not busy; 102 * if( job does not need a server ) then 103 * do whatever is needed; 104 * update job status(); 105 * else if( no jobs to print and no servers active ) then 106 * break; 107 * else if( no jobs to print or server active ) then 108 * wait for server to exit(); 109 * if( pid is for server printing job) 110 * update job status(); 111 * update server status(); 112 * else 113 * dofork(0) a server process; 114 * record pid of server doing work; 115 * endif 116 * } 117 * 118 * We then check to see if we are a slave (sv) to a master spool queue; 119 * if we are and we are not a child process of the 'master' server, 120 * we exit. 121 * 122 * Note: if we spool something to a slave queue, then we need to start 123 * the master server to make the slave printer work. 124 * 125 * Note: the slave queue processes 126 * will not close the masters lock files; this means a new master 127 * cannot start serving the queue until all the slaves are dead. 128 * Why this action do you ask? The reason is that it is difficult 129 * for a new master to inherit slaves from a dead master. 130 * 131 * It turns out that many implementations of some network 132 * based databased systems and other network database routines are broken, 133 * and have memory leaks or never close file descriptors. Up to the point 134 * where the loop for checking the queue starts, there is a known number 135 * of file descriptors open, and dynamically allocated memory. 136 * After this, it is difficult to predict just what is going to happen. 137 * By forking a 'subserver' process, we firewall the actual memory and 138 * file descriptor screwups into the subserver process. 139 * 140 * When the subserver exits, it returns an error code that the server 141 * process then interprets. This error code is used to either remove the job 142 * or retry it. 143 * 144 * Note that there are conditions under which a job cannot be removed. 145 * We simply abort at that point and let higher level authority (admins) 146 * deal with this. 147 * 148 ***************************************************************************/ 149 150 151/* 152 * Signal handler to set flags and terminate system calls 153 * NOTE: use 'volatile' so that the &*()()&* optimizing compilers 154 * handle the value correctly. 155 */ 156 157 static volatile int Susr1, Chld; 158 159 static void Sigusr1(void) 160{ 161 ++Susr1; 162 (void) plp_signal_break(SIGUSR1, (plp_sigfunc_t)Sigusr1); 163 return; 164} 165 166 static void Sigchld(void) 167{ 168 ++Chld; 169 signal( SIGCHLD, SIG_DFL ); 170 return; 171} 172 173 174/*************************************************************************** 175 * Update_spool_info() 176 * get updated spool control file information 177 ***************************************************************************/ 178 179 180void Update_spool_info( struct line_list *sp ) 181{ 182 struct line_list info; 183 char *sc; 184 185 Init_line_list(&info); 186 187 Set_str_value(&info,SPOOLDIR, Find_str_value(sp,SPOOLDIR,Value_sep) ); 188 Set_str_value(&info,PRINTER, Find_str_value(sp,PRINTER,Value_sep) ); 189 Set_str_value(&info,QUEUE_CONTROL_FILE, Find_str_value(sp,QUEUE_CONTROL_FILE,Value_sep) ); 190 Set_str_value(&info,HF_NAME, Find_str_value(sp,HF_NAME,Value_sep) ); 191 Set_str_value(&info,IDENTIFIER, Find_str_value(sp,IDENTIFIER,Value_sep) ); 192 Set_str_value(&info,SERVER, Find_str_value(sp,SERVER,Value_sep) ); 193 Set_str_value(&info,DONE_TIME, Find_str_value(sp,DONE_TIME,Value_sep) ); 194 195 sc = Find_str_value(&info,QUEUE_CONTROL_FILE,Value_sep); 196 197 DEBUG1("Update_spool_info: file '%s'", sc ); 198 199 Free_line_list(sp); 200 Get_spool_control(sc,sp); 201 Merge_line_list(sp,&info,Value_sep,1,1); 202 Free_line_list(&info); 203} 204 205int cmp_server( const void *left, const void *right, const void *p ) 206{ 207 struct line_list *l, *r; 208 int tr, tl; 209 l = ((struct line_list **)left)[0]; 210 r = ((struct line_list **)right)[0]; 211 tl = Find_flag_value(l,DONE_TIME,Value_sep); 212 tr = Find_flag_value(r,DONE_TIME,Value_sep); 213#ifdef ORIGINAL_DEBUG//JY@1020 214 if(DEBUGL5)Dump_line_list("cmp_server - l",l); 215 if(DEBUGL5)Dump_line_list("cmp_server - r",r); 216 DEBUG5("cmp_server: tl %d, tr %d, cmp %d, p %d", 217 tl, tr, tl - tr, (int)(p!=0) ); 218#endif 219 return( tl - tr ); 220} 221 222 223void Get_subserver_pc( char *printer, struct line_list *subserver_info, int done_time ) 224{ 225 int printable, held, move, err, done; 226 char *path; 227 char buffer[SMALLBUFFER]; 228 229 printable = held = move = err = done = 0; 230 231 DEBUG1("Get_subserver_pc: '%s'", printer ); 232 buffer[0] = 0; 233 if( Setup_printer( printer, buffer, sizeof(buffer), 1 ) ){ 234 Errorcode = JABORT; 235 FATAL(LOG_ERR) "Get_subserver_pc: '%s' - '%s'", printer, buffer); 236 } 237 238 Set_str_value(subserver_info,PRINTER,Printer_DYN); 239 Set_str_value(subserver_info,SPOOLDIR,Spool_dir_DYN); 240 path = Make_pathname( Spool_dir_DYN, Queue_control_file_DYN ); 241 Set_str_value(subserver_info,QUEUE_CONTROL_FILE,path); 242 if( path ) free(path); path = 0; 243 244 Update_spool_info( subserver_info ); 245 246 DEBUG1("Get_subserver_pc: scanning '%s'", Spool_dir_DYN ); 247 Scan_queue( subserver_info, 0, &printable, &held, &move, 1, &err, &done, 0, 0); 248 Set_flag_value(subserver_info,PRINTABLE,printable); 249 Set_flag_value(subserver_info,HELD,held); 250 Set_flag_value(subserver_info,MOVE,move); 251 Set_flag_value(subserver_info,DONE_TIME,done_time); 252 if( !(Save_when_done_DYN || Save_on_error_DYN ) 253 && (Done_jobs_DYN || Done_jobs_max_age_DYN) 254 && (err || done ) ){ 255 Set_flag_value(subserver_info,DONE_REMOVE,1); 256 } 257 258 DEBUG1("Get_subserver_pc: printable %d, held %d, move %d, done_remove %d, fowarding '%s'", 259 printable, held, move, 260 Find_flag_value(subserver_info,DONE_REMOVE,Value_sep), 261 Find_str_value(subserver_info,FORWARDING,Value_sep) ); 262} 263 264#ifdef ORIGINAL_DEBUG//JY@1020 265/*************************************************************************** 266 * Dump_subserver_info() 267 * dump the server information list 268 ***************************************************************************/ 269 270void Dump_subserver_info( char *title, struct line_list *l) 271{ 272 char buffer[LINEBUFFER]; 273 int i; 274 LOGDEBUG("*** Dump_subserver_info: '%s' - %d subservers", 275 title, l->count ); 276 for( i = 0; i < l->count; ++i ){ 277 SNPRINTF(buffer,sizeof(buffer))"server %d",i); 278#ifdef ORIGINAL_DEBUG//JY@1020 279 Dump_line_list_sub(buffer,(struct line_list *)l->list[i]); 280#endif 281 } 282} 283#endif 284 285/*************************************************************************** 286 * Get_subserver_info() 287 * hack up the server information list into a list of servers 288 ***************************************************************************/ 289 290void Get_subserver_info( struct line_list *order, 291 char *list, char *old_order) 292{ 293 struct line_list server_order, server, *pl; 294 int i; 295 char *s; 296 297 Unescape( old_order ); /* this is ugly - we make it forwards compatible */ 298 Init_line_list(&server_order); 299 Init_line_list(&server); 300 301 DEBUG1("Get_subserver_info: old_order '%s', list '%s'",old_order, list); 302 Split(&server_order,old_order,File_sep,0,0,0,1,0,0); 303 Split(&server_order, list,File_sep,0,0,0,1,0,0); 304#ifdef ORIGINAL_DEBUG//JY@1020 305 if(DEBUGL1)Dump_line_list("Get_subserver_info - starting",&server_order); 306#endif 307 308 /* get the info of printers */ 309 for( i = 0; i < server_order.count; ++i ){ 310 s = server_order.list[i]; 311 DEBUG1("Get_subserver_info: doing '%s'",s); 312 if( Find_str_value(&server,s,Value_sep) ){ 313 DEBUG1("Get_subserver_info: already done '%s'",s); 314 continue; 315 } 316 pl = malloc_or_die(sizeof(pl[0]),__FILE__,__LINE__); 317 Init_line_list(pl); 318 Get_subserver_pc( s, pl, i+1 ); 319 Check_max(order,1); 320 DEBUG1("Get_subserver_info: adding to list '%s' at %d",s,order->count); 321 order->list[order->count++] = (char *)pl; 322 Set_str_value(&server,s,s); 323 pl = 0; 324 } 325 Free_line_list(&server_order); 326 Free_line_list(&server); 327#ifdef ORIGINAL_DEBUG//JY@1020 328 if(DEBUGL1)Dump_subserver_info("Get_subserver_info - starting order",order); 329#endif 330} 331 332/*************************************************************************** 333 * Make_temp_copy - make a temporary copy in the directory 334 ***************************************************************************/ 335 336char *Make_temp_copy( char *srcfile, char *destdir ) 337{ 338 char buffer[LARGEBUFFER]; 339 char *path = 0; 340 struct stat statb; 341 int srcfd, destfd, fail, n, len, count; 342 343 fail = 0; 344 srcfd = destfd = -1; 345 346 DEBUG3("Make_temp_copy: '%s' to '%s'", srcfile, destdir); 347 348 destfd = Make_temp_fd_in_dir(&path, destdir); 349 unlink(path); 350 if( link( srcfile, path ) == -1 ){ 351#ifdef ORIGINAL_DEBUG//JY@1020 352 DEBUG3("Make_temp_copy: link '%s' to '%s' failed, '%s'", 353 srcfile, path, Errormsg(errno) ); 354#endif 355 srcfd = Checkread(srcfile, &statb ); 356 if( srcfd < 0 ){ 357 LOGERR(LOG_INFO)"Make_temp_copy: open '%s' failed", srcfile ); 358 fail = 1; 359 goto error; 360 } 361 while( (n = read(srcfd,buffer,sizeof(buffer))) > 0 ){ 362 for( count = len = 0; len < n 363 && (count = write(destfd, buffer+len,n-len)) > 0; 364 len += count ); 365 if( count < 0 ){ 366 LOGERR(LOG_INFO)"Make_temp_copy: copy to '%s' failed", path ); 367 fail = 1; 368 goto error; 369 } 370 } 371 } 372 373 error: 374 if( fail ){ 375 unlink(path); path = 0; 376 } 377 if( srcfd >= 0 ) close(srcfd); srcfd = -1; 378 if( destfd >= 0 ) close(destfd); destfd = -1; 379 return( path ); 380} 381 382/*************************************************************************** 383 * Do_queue_jobs: process the job queue 384 ***************************************************************************/ 385 386 static int Done_count; 387 static time_t Done_time; 388 389int Do_queue_jobs( char *name, int subserver ) 390{ 391 int master = 0; /* this is the master */ 392 int opened_logfile = 0; /* we have not opened the log file */ 393 int lock_fd; /* fd for files */ 394 char buffer[SMALLBUFFER], savename[SMALLBUFFER], errormsg[SMALLBUFFER]; 395 char *path, *s, *id, *tempfile, *transfername, *openname, 396 *new_dest, *move_dest, *pr, *hf_name, *sd, *from, *forwarding; 397 struct stat statb; 398 int i, j, mod, fd, pid, printable, held, move, destinations, 399 destination, use_subserver, job_to_do, working, printing_enabled, 400 all_done, fail, job_index, change, in_tempfd, out_tempfd, len, 401 chooser_did_not_find_server, error, done, done_remove, check_for_done; 402 struct line_list servers, tinfo, *sp, *datafile, chooser_list, chooser_env; 403 plp_block_mask oblock; 404 struct job job; 405 int jobs_printed = 0; 406 407 Init_line_list(&tinfo); 408 409 lock_fd = -1; 410 411 Init_job(&job); 412 Init_line_list(&servers); 413 Init_line_list(&chooser_list); 414 Init_line_list(&chooser_env); 415 id = transfername = 0; 416 in_tempfd = out_tempfd = -1; 417 418 Name = "(Server)"; 419 Set_DYN(&Printer_DYN,name); 420 DEBUG1("Do_queue_jobs: called with name '%s', subserver %d", 421 Printer_DYN, subserver ); 422 name = Printer_DYN; 423 424 if(DEBUGL4){ int fdx; fdx = dup(0); LOGDEBUG("Do_queue_jobs: start next fd %d",fdx); close(fdx); }; 425 426 begin: 427 Set_DYN(&Printer_DYN,name); 428 DEBUG1("Do_queue_jobs: begin name '%s'", Printer_DYN ); 429 tempfile = 0; 430 Free_listof_line_list( &servers ); 431 if( lock_fd != -1 ) close( lock_fd ); lock_fd = -1; 432 433 Errorcode = JABORT; 434 /* you need to have a spool queue */ 435 if( Setup_printer( Printer_DYN, buffer, sizeof(buffer), 0 ) ){ 436 cleanup(0); 437 } 438 if(DEBUGL4){ int fdx; fdx = dup(0); 439 LOGDEBUG("Do_queue_jobs: after Setup_printer next fd %d",fdx); close(fdx); }; 440 441 setproctitle( "lpd %s '%s'", Name, Printer_DYN ); 442 443 again: 444 /* block signals */ 445 plp_block_one_signal(SIGCHLD, &oblock); 446 plp_block_one_signal(SIGUSR1, &oblock); 447 (void) plp_signal(SIGCHLD, SIG_DFL); 448 (void) plp_signal(SIGUSR1, (plp_sigfunc_t)Sigusr1); 449 Susr1 = 0; 450 451 path = Make_pathname( Spool_dir_DYN, Queue_lock_file_DYN ); 452 DEBUG1( "Do_queue_jobs: checking lock file '%s'", path ); 453 lock_fd = Checkwrite( path, &statb, O_RDWR, 1, 0 ); 454 if( lock_fd < 0 ){ 455 LOGERR_DIE(LOG_ERR) _("Do_queue_jobs: cannot open lockfile '%s'"), 456 path ); 457 } 458 if(path) free(path); path = 0; 459 460 /* 461 This code is very tricky, and may cause some headaches 462 First, you want to make sure that you have an active process 463 to do the unspooling. If you CAN lock the lock file, then you 464 are the active process. If you CANNOT lock the lock file 465 then some other process is the active process. 466 467 If some other process is the active process then you want to 468 make sure that you signal it. When the process is exiting 469 then it will first truncate lock file and then close it. 470 We make the brutal assumption that from the time that the 471 process truncates the log file until it exits will be less than 472 the time taken for this process to read the file and send a signal. 473 We help a bit by having the exiting process sleep 2 seconds - 474 i.e. - we make sure that it will take a fairish time. 475 476 This makes sure that processes that read the PID before it is 477 truncated will send the signal to an existing processes. 478 */ 479 480 while( Do_lock( lock_fd, 0 ) < 0 ){ 481 pid = Read_pid( lock_fd, (char *)0, 0 ); 482 DEBUG1( "Do_queue_jobs: server process '%d' may be active", pid ); 483 if( pid == 0 || kill( pid, SIGUSR1 ) ){ 484 plp_usleep(1000); 485 continue; 486 } 487 Errorcode = 0; 488 cleanup(0); 489 } 490 pid = getpid(); 491 DEBUG1( "Do_queue_jobs: writing lockfile '%s' with pid '%d'", 492 Queue_lock_file_DYN, pid ); 493 Write_pid( lock_fd, pid, (char *)0 ); 494 495 /* we now now new queue status so we force update */ 496 if( Lpq_status_file_DYN ){ 497 unlink(Lpq_status_file_DYN); 498 } 499 if( Log_file_DYN && !opened_logfile ){ 500 fd = Trim_status_file( -1, Log_file_DYN, Max_log_file_size_DYN, 501 Min_log_file_size_DYN ); 502 if( fd > 0 && fd != 2 ){ 503 dup2(fd,2); 504 close(fd); 505 } 506 opened_logfile = 1; 507 } 508 509 s = Find_str_value(&Spool_control,DEBUG,Value_sep); 510 if(!s) s = New_debug_DYN; 511 Parse_debug( s, 0); 512 513 if( Server_queue_name_DYN ){ 514 if( subserver == 0 ){ 515 /* you really need to start up the master queue */ 516 name = Server_queue_name_DYN; 517 DEBUG1("Do_queue_jobs: starting up master queue '%s'", name ); 518 goto begin; 519 } 520 Name = "(Sub)"; 521 } 522 /* set up the server name information */ 523 Check_max(&servers,1); 524 sp = malloc_or_die(sizeof(sp[0]),__FILE__,__LINE__); 525 memset(sp,0,sizeof(sp[0])); 526 Set_str_value(sp,PRINTER,Printer_DYN); 527 Set_str_value(sp,SPOOLDIR,Spool_dir_DYN); 528 Set_str_value(sp,QUEUE_CONTROL_FILE,Queue_control_file_DYN); 529 servers.list[servers.count++] = (char *)sp; 530 Update_spool_info(sp); 531 532 change = Find_flag_value(&Spool_control,CHANGE,Value_sep); 533 if( change ){ 534 Set_flag_value(sp,CHANGE,0); 535 Set_flag_value(&Spool_control,CHANGE,0); 536 Set_spool_control(0, Queue_control_file_DYN, &Spool_control); 537 } 538 539 master = 0; 540 if( !ISNULL(Server_names_DYN) ){ 541 DEBUG1( "Do_queue_jobs: Server_names_DYN '%s', Server_order '%s'", 542 Server_names_DYN, Srver_order(&Spool_control) ); 543 if( Server_queue_name_DYN ){ 544 Errorcode = JABORT; 545 FATAL(LOG_ERR)"Do_queue_jobs: serving '%s' and subserver for '%s'", 546 Server_queue_name_DYN, Server_names_DYN ); 547 } 548 549 /* save the Printer_DYN name */ 550 safestrncpy(savename,Printer_DYN); 551 /* we now get the subserver information */ 552 Get_subserver_info( &servers, 553 Server_names_DYN, Srver_order(&Spool_control) ); 554 555 /* reset the main printer */ 556 if( Setup_printer( savename, buffer, sizeof(buffer), 0 ) ){ 557 cleanup(0); 558 } 559 560 master = 1; 561 /* start the queues that need it */ 562 for( i = 1; i < servers.count; ++i ){ 563 sp = (void *)servers.list[i]; 564 pr = Find_str_value(sp,PRINTER,Value_sep); 565 DEBUG1("Do_queue_jobs: subserver '%s' checking for independent action", pr ); 566 if( (s = Find_str_value(sp,SERVER,Value_sep)) ){ 567 DEBUG1("Do_queue_jobs: subserver '%s' active server '%s'", pr,s ); 568 } 569 printable = !Pr_disabled(sp) && !Pr_aborted(sp) 570 && Find_flag_value(sp,PRINTABLE,Value_sep); 571 move = Find_flag_value(sp,MOVE,Value_sep); 572 forwarding = Find_str_value(sp,FORWARDING,Value_sep); 573 change = Find_flag_value(sp,CHANGE,Value_sep); 574 DEBUG1("Do_queue_jobs: subserver '%s', printable %d, move %d, forwarding '%s'", 575 pr, printable, move, forwarding ); 576 /* now see if we need to clean up the old jobs */ 577 done_remove = Find_flag_value(sp,DONE_REMOVE,Value_sep); 578 579 if( printable || move || change || forwarding || done_remove ){ 580 pid = Fork_subserver( &servers, i, 0 ); 581 jobs_printed = 1; 582 } 583 Set_flag_value(sp,CHANGE,0); 584 } 585 } 586 587 588#ifdef ORIGINAL_DEBUG//JY@1020 589 if(DEBUGL3)Dump_subserver_info("Do_queue_jobs - after setup",&servers); 590#endif 591 592 if(DEBUGL4){ int fdx; fdx = dup(0); 593 LOGDEBUG("Do_queue_jobs: after subservers next fd %d",fdx);close(fdx);}; 594 /* get new job values */ 595 if( Scan_queue( &Spool_control, &Sort_order, 596 &printable, &held, &move, 1, &error, &done, 0, 0 ) ){ 597 LOGERR_DIE(LOG_ERR)"Do_queue_jobs: cannot read queue '%s'", 598 Spool_dir_DYN ); 599 } 600 601 DEBUG1( "Do_queue_jobs: printable %d, held %d, move %d, err %d, done %d", 602 printable, held, move, error, done ); 603 604 if(DEBUGL1){ i = dup(0); 605 LOGDEBUG("Do_queue_jobs: after Scan_queue next fd %d", i); close(i); } 606 607 /* remove junk fields from job information */ 608 for( i = 0; i < Sort_order.count; ++i ){ 609 /* fix up the sort stuff */ 610 Free_job(&job); 611 Get_hold_file(&job,Sort_order.list[i] ); 612#ifdef ORIGINAL_DEBUG//JY@1020 613 if(DEBUGL3)Dump_job("Do_queue_jobs - info", &job); 614#endif 615 616 /* debug output */ 617 mod = 0; 618 if( Find_flag_value(&job.info,SERVER,Value_sep ) ){ 619 Set_decimal_value(&job.info,SERVER,0); 620 mod = 1; 621 } 622 if((destinations = Find_flag_value(&job.info,DESTINATIONS,Value_sep))){ 623 if( Find_str_value(&job.info,DESTINATION,Value_sep ) ){ 624 Set_str_value(&job.info,DESTINATION,0); 625 mod = 1; 626 } 627 for( j = 0; j < destinations; ++j ){ 628 Get_destination(&job,j); 629 if( Find_flag_value(&job.destination,SERVER,Value_sep) ){ 630 mod = 1; 631 Set_decimal_value(&job.destination,SERVER,0); 632 Update_destination(&job); 633 } 634 } 635 } 636 if( mod ) Set_hold_file(&job, 0, 0 ); 637 } 638 639 640 Free_job(&job); 641 642 check_for_done = 1; 643 644 while(1){ 645 DEBUG1( "Do_queue_jobs: MAIN LOOP" ); 646 if(DEBUGL4){ int fdx; fdx = dup(0); 647 LOGDEBUG("Do_queue_jobs: MAIN LOOP next fd %d",fdx); close(fdx); }; 648 Unlink_tempfiles(); 649 650 /* check for changes to spool control information */ 651 plp_unblock_all_signals( &oblock ); 652 plp_set_signal_mask( &oblock, 0 ); 653 654 if( (Done_jobs_DYN > 0 && Done_count > Done_jobs_DYN) 655 || (Done_jobs_max_age_DYN > 0 656 && Done_time 657 && (time(0) - Done_time) > Done_jobs_max_age_DYN) ){ 658 Susr1 = 1; 659 } 660 DEBUG1( "Do_queue_jobs: Susr1 before scan %d, check_for_done %d", 661 Susr1, check_for_done ); 662 while( Susr1 ){ 663 Susr1 = 0; 664 Done_time = 0; 665 Done_count = 0; 666 DEBUG1( "Do_queue_jobs: rescanning" ); 667 668 Get_spool_control( Queue_control_file_DYN, &Spool_control); 669 if( Scan_queue( &Spool_control, &Sort_order, 670 &printable, &held, &move, 1, &error, &done, 0, 0 ) ){ 671 LOGERR_DIE(LOG_ERR)"Do_queue_jobs: cannot read queue '%s'", 672 Spool_dir_DYN ); 673 } 674 DEBUG1( "Do_queue_jobs: printable %d, held %d, move %d, error %d, done %d", 675 printable, held, move, error, done ); 676 677 for( i = 0; i < servers.count; ++i ){ 678 sp = (void *)servers.list[i]; 679 Update_spool_info( sp ); 680 change = Find_flag_value(sp,CHANGE,Value_sep); 681 pid = Find_flag_value(sp,SERVER,Value_sep); 682 if( i > 0 && change && pid == 0 ){ 683 pid = Fork_subserver( &servers, i, 0 ); 684 jobs_printed = 1; 685 } 686 Set_flag_value(sp,CHANGE,0); 687 } 688#ifdef ORIGINAL_DEBUG//JY@1020 689 if(DEBUGL1) Dump_subserver_info( "Do_queue_jobs - rescan", 690 &servers ); 691#endif 692 693 /* check for changes to spool control information */ 694 plp_unblock_all_signals( &oblock); 695 plp_set_signal_mask( &oblock, 0); 696 DEBUG1( "Do_queue_jobs: Susr1 at end of scan %d", Susr1 ); 697 /* now check to see if you remove jobs */ 698 check_for_done = 0; 699 if( !(Save_when_done_DYN || Save_on_error_DYN ) 700 && (Done_jobs_DYN || Done_jobs_max_age_DYN) 701 && (error || done) ){ 702 check_for_done = 1; 703 } 704 } 705 706#ifdef ORIGINAL_DEBUG//JY@1020 707 if(DEBUGL4) Dump_line_list("Do_queue_jobs - sort order printable", 708 &Sort_order ); 709#endif 710 711 Remove_done_jobs(); 712 713 /* make sure you can print */ 714 printing_enabled 715 = !(Pr_disabled(&Spool_control) || Pr_aborted(&Spool_control)); 716 forwarding = Find_str_value(&Spool_control,FORWARDING,Value_sep); 717 DEBUG3("Do_queue_jobs: printing_enabled '%d', forwarding '%s'", 718 printing_enabled, forwarding ); 719 720 openname = transfername = hf_name = id = move_dest = new_dest = 0; 721 destination = use_subserver = job_to_do = -1; 722 working = destinations = chooser_did_not_find_server = 0; 723 724#ifdef ORIGINAL_DEBUG//JY@1020 725 if(DEBUGL2) Dump_subserver_info("Do_queue_jobs- checking for server", 726 &servers ); 727#endif 728 for( j = 0; j < servers.count; ++j ){ 729 sp = (void *)servers.list[j]; 730 pid = Find_flag_value(sp,SERVER,Value_sep); 731 pr = Find_str_value(sp,PRINTER,Value_sep); 732 DEBUG2("Do_queue_jobs: printer '%s', server %d", pr, pid ); 733 if( pid ){ 734 ++working; 735 } 736 } 737 738 for( job_index = 0; job_to_do < 0 && job_index < Sort_order.count; 739 ++job_index ){ 740 741 Free_job(&job); 742 id = move_dest = new_dest = 0; 743 destination = use_subserver = job_to_do = -1; 744 destinations = 0; 745 746 if( !Sort_order.list[job_index] ) continue; 747 DEBUG3("Do_queue_jobs: job_index [%d] '%s'", job_index, 748 Sort_order.list[job_index] ); 749 Get_hold_file( &job, Sort_order.list[job_index] ); 750 751#ifdef ORIGINAL_DEBUG//JY@1020 752 if(DEBUGL4)Dump_job("Do_queue_jobs: job ",&job); 753#endif 754 if( job.info.count == 0 ) continue; 755 756 /* check to see if active */ 757 if( (pid = Find_flag_value(&job.info,SERVER,Value_sep)) ){ 758 DEBUG3("Do_queue_jobs: [%d] active %d", job_index, pid ); 759 continue; 760 } 761 762 /* get printable status */ 763 Setup_cf_info( &job, 1 ); 764 Job_printable(&job,&Spool_control,&printable,&held,&move,&error,&done); 765 if( (!(printable && (printing_enabled || forwarding)) && !move) || held ){ 766 DEBUG3("Do_queue_jobs: [%d] not processable", job_index ); 767 /* free( Sort_order.list[job_index] ); Sort_order.list[job_index] = 0; */ 768 continue; 769 } 770 if( Check_print_perms(&job) == P_REJECT ){ 771 Set_str_value(&job.info,ERROR,"no permission to print"); 772 Set_nz_flag_value(&job.info,ERROR_TIME,time(0)); 773 if( Set_hold_file( &job, 0, 0 ) ){ 774 /* you cannot update hold file!! */ 775 setstatus( &job, _("cannot update hold file for '%s'"), 776 id); 777 FATAL(LOG_ERR) 778 _("Do_queue_jobs: cannot update hold file for '%s'"), 779 id); 780 } 781 if( !(Save_on_error_DYN || Done_jobs_DYN || Done_jobs_max_age_DYN) ){ 782 setstatus( &job, _("removing job '%s' - no permissions"), id); 783 Remove_job( &job ); 784 free( Sort_order.list[job_index] ); Sort_order.list[job_index] = 0; 785 } 786 continue; 787 } 788 789 /* get destination information */ 790 destinations = Find_flag_value(&job.info,DESTINATIONS,Value_sep); 791 if( !destinations ){ 792 move_dest = new_dest = Find_str_value(&job.info,MOVE,Value_sep); 793 if( !new_dest ) new_dest = Frwarding(&Spool_control); 794 } else { 795 all_done = 0; 796 for( j = 0; !new_dest && j < destinations; ++j ){ 797 Get_destination(&job,j); 798 if( Find_flag_value(&job.destination,SERVER,Value_sep) ){ 799 break; 800 } 801 if( Find_flag_value(&job.destination,DONE_TIME,Value_sep ) ){ 802 ++all_done; 803 continue; 804 } 805 if( Find_flag_value(&job.destination,ERROR_TIME,Value_sep) 806 || Find_flag_value(&job.destination,HOLD_TIME,Value_sep) ){ 807 continue; 808 } 809 if( (move_dest = new_dest = Find_str_value( &job.destination, 810 MOVE,Value_sep)) ){ 811 destination = j; 812 break; 813 } 814 if( Find_flag_value(&job.destination, PRINTABLE, Value_sep ) 815 && printing_enabled ){ 816 new_dest = Find_str_value( &job.destination, 817 DEST,Value_sep ); 818 destination = j; 819 break; 820 } 821 } 822 if( !new_dest ){ 823 printable = 0; 824 } 825 if( all_done == destinations ){ 826 DEBUG3("Do_queue_jobs: destinations %d, done %d", 827 destinations, all_done ); 828 Update_status( &job, JSUCC ); 829 continue; 830 } 831 } 832 833 DEBUG3("Do_queue_jobs: new_dest '%s', printable %d, master %d, destinations %d, destination %d", 834 new_dest, printable, master, destinations, destination ); 835 if( new_dest ){ 836 sp = (void *)servers.list[0]; 837 if( Find_flag_value(sp,SERVER,Value_sep) ){ 838 continue; 839 } 840 use_subserver = 0; 841 job_to_do = job_index; 842 } else if( printing_enabled && printable ){ 843 /* 844 * find the subserver with a class that will print this job 845 * if master = 1, then we start with 1 846 */ 847 Free_line_list( &chooser_list ); 848 Free_line_list( &chooser_env ); 849 DEBUG1("Do_queue_jobs: chooser '%s', chooser_routine %lx", 850 Chooser_DYN, Cast_ptr_to_long(Chooser_routine_DYN) ); 851 for( j = master; use_subserver < 0 && j < servers.count; ++j ){ 852 sp = (void *)servers.list[j]; 853 s = Find_str_value(sp,PRINTER,Value_sep); 854 DEBUG1("Do_queue_jobs: checking '%s'", s ); 855 if( Pr_disabled(sp) 856 || Pr_aborted(sp) 857 || Sp_disabled(sp) 858 || Find_flag_value(sp,SERVER,Value_sep)){ 859 DEBUG1("Do_queue_jobs: cannot use [%d] '%s'", 860 j, s ); 861 continue; 862 } 863 if( Get_hold_class(&job.info,sp) ){ 864 DEBUG1("Do_queue_jobs: cannot use [%d] '%s' class conflict", 865 j, s ); 866 /* we found a server that was not available */ 867 continue; 868 } 869 if( Chooser_DYN == 0 && Chooser_routine_DYN == 0 ){ 870 use_subserver = j; 871 job_to_do = job_index; 872 } else { 873 char *t; 874 /* add to the list of possible servers */ 875 Set_flag_value(&chooser_list,s,j); 876 if( !Chooser_routine_DYN ){ 877 /* get the environment values for the possible server */ 878 t = Join_line_list_with_sep(sp,"\n"); 879 Set_str_value(&chooser_env,s,t); 880 if( t ) free(t); t = 0; 881 t = Find_str_value( &chooser_env,"PRINTERS",Value_sep ); 882 if( t ){ 883 t = safestrdup3(t,",",s,__FILE__,__LINE__); 884 Set_str_value( &chooser_env,"PRINTERS",t ); 885 if( t ) free(t); t = 0; 886 } else { 887 Set_str_value( &chooser_env,"PRINTERS",s ); 888 } 889 } 890 } 891 } 892 /* we now have to find out if we really need to call the chooser 893 * if we are working and a single queue, then we do not 894 * :sv == "" - then we do 895 */ 896 DEBUG1("Do_queue_jobs: Chooser %s, working %d, master %d", Chooser_DYN, working, master); 897 if( (Chooser_routine_DYN || Chooser_DYN) && working && master == 0 ){ 898 chooser_did_not_find_server = 1; 899 } else if( Chooser_routine_DYN ){ 900#if defined(CHOOSER_ROUTINE) 901 extern int CHOOSER_ROUTINE( struct line_list *servers, 902 struct line_list *available, int *use_subserver ); 903 /* return status for job */ 904 DEBUG1("Do_queue_jobs: using CHOOSER_ROUTINE %s", STR(CHOOSER_ROUTINE) ); 905 j = CHOOSER_ROUTINE( &servers, &chooser_list, &use_subserver ); 906 if( j ){ 907 SETSTATUS(&job)"CHOOSER_ROUTINE exit status %s", Server_status(j)); 908 chooser_did_not_find_server = 1; 909 if( j != JFAIL && j != JABORT ){ 910 Update_status( &job, j ); 911 } 912 if( j == JABORT ){ 913 Errorcode = JABORT; 914 FATAL(LOG_ERR) "Do_queue_jobs: Chooser_routine aborted" ); 915 } 916 } else if( use_subserver >= 0 ){ 917 /* we use this subserver */ 918 job_to_do = job_index; 919 } else { 920 /* we did not find a server queue */ 921 chooser_did_not_find_server = 1; 922 } 923#else 924 Errorcode = JABORT; 925 fatal(LOG_ERR,"Do_queue_jobs: 'chooser_routine' select and no routine defined"); 926#endif 927 } else if( Chooser_DYN ){ 928 if( in_tempfd > 0 ) close( in_tempfd ); in_tempfd = -1; 929 if( out_tempfd > 0 ) close( out_tempfd ); out_tempfd = -1; 930 in_tempfd = Make_temp_fd(0); 931 out_tempfd = Make_temp_fd(0); 932 s = Find_str_value( &chooser_env,"PRINTERS",Value_sep ); 933 if( s && (Write_fd_str( in_tempfd, s ) < 0 934 || Write_fd_str( in_tempfd, "\n" ) < 0) ){ 935 Errorcode = JABORT; 936 LOGERR_DIE(LOG_ERR) "Do_queue_jobs: write(%d) failed", in_tempfd); 937 } 938 /* we invoke the chooser with the list 939 * of printers we have found in the order 940 */ 941 if( lseek(in_tempfd,0,SEEK_SET) == -1 ){ 942 Errorcode = JFAIL; 943 LOGERR_DIE(LOG_INFO)"Do_queue_jobs: fseek(%d) failed", 944 out_tempfd); 945 } 946 j = Filter_file( in_tempfd, out_tempfd, "CHOOSER", 947 Chooser_DYN, Filter_options_DYN, &job, &chooser_env, 1 ); 948 if( j ){ 949 SETSTATUS(&job)"CHOOSER exit status %s", Server_status(j)); 950 chooser_did_not_find_server = 1; 951 if( j != JFAIL && j != JABORT ){ 952 Update_status( &job, j ); 953 } 954 if( j == JABORT ){ 955 Errorcode = JABORT; 956 FATAL(LOG_ERR) "Do_queue_jobs: Chooser aborted" ); 957 } 958 } else { 959 if( lseek(out_tempfd,0,SEEK_SET) == -1 ){ 960 Errorcode = JFAIL; 961 LOGERR_DIE(LOG_INFO)"Do_queue_jobs: fseek(%d) failed", 962 out_tempfd); 963 } 964 len = read( out_tempfd, buffer,sizeof(buffer)-1 ); 965 if( len >= 0 ){ 966 buffer[len] = 0; 967 } else { 968 Errorcode = JFAIL; 969 LOGERR_DIE(LOG_INFO)"Do_queue_jobs: read(%d) failed", 970 out_tempfd); 971 } 972 while( isspace(cval(buffer)) ){ 973 memmove(buffer,buffer+1,safestrlen(buffer+1)+1); 974 } 975 if( (s = strpbrk(buffer,Whitespace)) ){ 976 *s = 0; 977 } 978 if( buffer[0] ){ 979 /* we found a server queue */ 980 SETSTATUS(&job)"CHOOSER selected '%s'", buffer); 981 if( Find_str_value( &chooser_list,buffer,Value_sep ) ){ 982 use_subserver = Find_flag_value(&chooser_list,buffer,Value_sep); 983 job_to_do = job_index; 984 } else if( strchr( buffer,'@') ){ 985 /* we are routing to a remote queue not in list */ 986 use_subserver = 0; 987 job_to_do = job_index; 988 Set_str_value( &job.info,NEW_DEST,buffer); 989 new_dest = Find_str_value( &job.info,NEW_DEST,Value_sep); 990 } else { 991 LOGMSG(LOG_ERR)"Do_queue_jobs: CHOOSER selection '%s' not a subserver", 992 buffer ); 993 } 994 } else { 995 /* we did not find a server queue */ 996 chooser_did_not_find_server = 1; 997 } 998 } 999 } 1000 if( in_tempfd >= 0 ) close( in_tempfd ); in_tempfd = -1; 1001 if( out_tempfd >= 0 ) close( out_tempfd ); out_tempfd = -1; 1002 Free_line_list( &chooser_env ); 1003 Free_line_list( &chooser_list ); 1004 } 1005 } 1006 1007 /* first, we see if there is no work and no server active */ 1008 DEBUG1("Do_queue_jobs: job_to_do %d, use_subserver %d, working %d", 1009 job_to_do, use_subserver, working ); 1010 1011 if( job_to_do < 0 && !working && chooser_did_not_find_server == 0 ){ 1012 DEBUG1("Do_queue_jobs: nothing to do"); 1013 break; 1014 } 1015 1016 /* now we see if we have to wait */ 1017 if( use_subserver < 0 ){ 1018 if( chooser_did_not_find_server ){ 1019 setstatus(0, "chooser did not find subserver, waiting %d sec", 1020 Chooser_interval_DYN ); 1021#ifdef ORIGINAL_DEBUG//JY@1020 1022 Wait_for_subserver( Chooser_interval_DYN, &servers ); 1023#endif 1024 } else if( working ){ 1025 if( servers.count > 1 ){ 1026 setstatus(0, "waiting for server queue process to exit" ); 1027 } else { 1028 setstatus(0, "waiting for subserver to exit" ); 1029 } 1030#ifdef ORIGINAL_DEBUG//JY@1020 1031 Wait_for_subserver( 0, &servers ); 1032#endif 1033 } 1034 continue; 1035 } 1036 1037 /* 1038 * get the job information 1039 */ 1040 hf_name = Find_str_value(&job.info,HF_NAME,Value_sep); 1041 id = Find_str_value(&job.info,IDENTIFIER,Value_sep); 1042 if( !id ){ 1043 Errorcode = JABORT; 1044 FATAL(LOG_ERR) 1045 _("Do_queue_jobs: LOGIC ERROR - no identifer '%s'"), hf_name); 1046 } 1047 1048 /* 1049 * set the hold file information 1050 */ 1051 1052 if( destination >= 0 ){ 1053 SNPRINTF(buffer,sizeof(buffer))"DEST%d",destination ); 1054 Set_str_value(&job.info,DESTINATION,buffer); 1055 } 1056 1057 Set_decimal_value(&job.info,SERVER,getpid()); 1058 Set_flag_value(&job.info,START_TIME,time((void *)0)); 1059 1060 sp = (void *)servers.list[use_subserver]; 1061 Set_str_value(sp,HF_NAME,0); 1062 Set_str_value(sp,IDENTIFIER,0); 1063 1064 pr = Find_str_value(sp,PRINTER,Value_sep); 1065 DEBUG1("Do_queue_jobs: starting job '%s' on '%s'", id, pr ); 1066 1067 if( Set_hold_file( &job, 0, 0 ) ){ 1068 /* you cannot update hold file!! */ 1069 setstatus( &job, _("cannot update hold file '%s'"), hf_name); 1070 FATAL(LOG_ERR) 1071 _("Do_queue_jobs: cannot update hold file '%s'"), hf_name); 1072 } 1073 1074 if( Status_file_DYN ){ 1075 DEBUG1("Do_queue_jobs: trimming status file '%s'/'%s'", Spool_dir_DYN, Status_file_DYN ); 1076 fd = Trim_status_file( -1, Status_file_DYN, Max_status_size_DYN, 1077 Min_status_size_DYN ); 1078 if( fd > 0 ) close(fd); 1079 fd = -1; 1080 } 1081 1082 if( use_subserver > 0 ){ 1083 /* we set up a copy of the job descriptor to use to make 1084 the job in the new directory */ 1085 int holdfile_fd = -1; 1086 struct job jcopy; 1087 Init_job(&jcopy); 1088 Copy_job(&jcopy,&job); 1089 1090 sd = Find_str_value(sp,SPOOLDIR,Value_sep); 1091 pr = Find_str_value(sp,PRINTER,Value_sep); 1092 1093 DEBUG1("Do_queue_jobs: subserver '%s', spool dir '%s' for job '%s'", 1094 pr, sd, id ); 1095 setstatus(&job, "transferring '%s' to subserver '%s'", id, pr ); 1096 1097 for( i = 0; i < jcopy.datafiles.count; ++i ){ 1098 datafile = (void *)jcopy.datafiles.list[i]; 1099 Set_str_value( datafile, OPENNAME, 0 ); 1100 } 1101 Set_str_value(&jcopy.info,OPENNAME,0); 1102 Set_str_value(&jcopy.info,HF_NAME,0); 1103#ifdef ORIGINAL_DEBUG//JY@1020 1104 if(DEBUGL2)Dump_job("Do_queue_jobs: subserver jcopy", &jcopy ); 1105#endif 1106 1107 fail = 0; 1108 for( i = 0; i < jcopy.datafiles.count; ++i ){ 1109 datafile = (void *)jcopy.datafiles.list[i]; 1110#ifdef ORIGINAL_DEBUG//JY@1020 1111 if(DEBUGL3)Dump_line_list("Do_queue_jobs - copying datafiles", 1112 datafile); 1113#endif 1114 from = Find_str_value(datafile,TRANSFERNAME,Value_sep); 1115 path = Make_temp_copy( from, sd ); 1116 DEBUG3("Do_queue_jobs: sd '%s', from '%s', path '%s'", 1117 sd, from, path ); 1118 if( path ){ 1119 Set_str_value( datafile, OPENNAME, path ); 1120 } else { 1121 fail = 1; 1122 break; 1123 } 1124 } 1125 if( !fail ){ 1126 from = Find_str_value(&jcopy.info,TRANSFERNAME,Value_sep); 1127 path = Make_temp_copy(from,sd); 1128 DEBUG3("Do_queue_jobs: sd '%s', from '%s', path '%s'", 1129 sd, from, path ); 1130 if( path ){ 1131 Set_str_value( &jcopy.info,OPENNAME,path ); 1132 } else { 1133 fail = 1; 1134 } 1135 } 1136 /* if we fail to copy, make a note of it */ 1137 if( fail ){ 1138 SNPRINTF(buffer,sizeof(buffer))"cannot copy '%s' to subserver '%s' queue directory '%s'", 1139 id, pr, sd ); 1140 Set_str_value(&job.info,ERROR,buffer); 1141 Set_nz_flag_value(&job.info,ERROR_TIME,time(0)); 1142 setstatus(&job, "%s", buffer); 1143 path = Find_str_value(&jcopy.info,OPENNAME,Value_sep); 1144 if( path ) unlink(path); 1145 for( i = 0; i < jcopy.datafiles.count; ++i ){ 1146 datafile = (void *)jcopy.datafiles.list[i]; 1147 path = Find_str_value(datafile,OPENNAME,Value_sep); 1148 if( path ) unlink(path); 1149 } 1150 Update_status(&job, JFAIL); 1151 Free_job(&jcopy); 1152 continue; 1153 } 1154#ifdef ORIGINAL_DEBUG//JY@1020 1155 if(DEBUGL2)Dump_job("Do_queue_jobs: subserver jcopy new", &jcopy ); 1156#endif 1157 1158 /* set up the new context */ 1159 safestrncpy(savename,Printer_DYN); 1160 buffer[0] = 0; 1161 1162 /* we have to chdir to the destination directory */ 1163 if( Setup_printer( pr, buffer, sizeof(buffer), 1 ) ){ 1164 Errorcode = JABORT; 1165 FATAL(LOG_ERR) "Do_queue_jobs: subserver '%s' setup failed - %s'", 1166 pr, buffer ); 1167 } 1168 1169 /* get the job set up */ 1170 i = Check_for_missing_files( &jcopy, 0, errormsg, sizeof(errormsg), 0, &holdfile_fd ); 1171 if( holdfile_fd >= 0 ) close( holdfile_fd ); holdfile_fd = -1; 1172 Free_job(&jcopy); 1173 1174 /* now we switch back to the old context */ 1175 if( Setup_printer( savename, buffer, sizeof(buffer), 1 ) ){ 1176 Errorcode = JABORT; 1177 FATAL(LOG_ERR) "Do_queue_jobs: subserver '%s' setup failed '%s'", 1178 savename, buffer ); 1179 } 1180 /* now handle error conditions */ 1181 if( i ){ 1182 SNPRINTF(buffer,sizeof(buffer))"transfer '%s' to subserver '%s' failed - %s", 1183 id, pr, errormsg ); 1184 Set_str_value(&job.info,ERROR,buffer); 1185 Set_nz_flag_value(&job.info,ERROR_TIME,time(0)); 1186 setstatus(&job, "%s", buffer); 1187 Update_status(&job, JFAIL); 1188 continue; 1189 } 1190 1191 /* now we deal with the job in the original queue */ 1192 Update_status(&job, JSUCC); 1193 1194 Set_str_value(sp,IDENTIFIER,id); 1195#ifdef ORIGINAL_DEBUG//JY@1020 1196 setstatus(&job, "transfer '%s' to subserver '%s' finished", id, pr ); 1197 setmessage(&job,STATE,"COPYTO %s",pr); 1198 setstatus(&job, "starting subserver '%s'", pr ); 1199#endif 1200 pid = Fork_subserver( &servers, use_subserver, 0 ); 1201 jobs_printed = 1; 1202 } else { 1203 Free_line_list(&tinfo); 1204 Set_str_value(&tinfo,HF_NAME,hf_name); 1205 Set_str_value(&tinfo,NEW_DEST,new_dest); 1206 Set_str_value(&tinfo,MOVE_DEST,move_dest); 1207 if( (pid = Fork_subserver( &servers, 0, &tinfo )) < 0 ){ 1208 setstatus( &job, _("sleeping, waiting for processes to exit")); 1209 plp_sleep(1); 1210 } else { 1211 Set_str_value(sp,HF_NAME,hf_name); 1212 Set_str_value(sp,IDENTIFIER,id); 1213 } 1214 jobs_printed = 1; 1215 } 1216 } 1217 1218 /* now we reset the server order */ 1219 1220 Errorcode = JSUCC; 1221 Free_job(&job); 1222 Free_line_list(&tinfo); 1223 if( Server_names_DYN ){ 1224 if( jobs_printed ) setstatus( 0, "no more jobs to process in load balance queue" ); 1225 jobs_printed = 0; 1226 for( i = 1; i < servers.count; ++i ){ 1227 sp = (void *)servers.list[i]; 1228 s = Find_str_value(sp,PRINTER,Value_sep); 1229 Add_line_list(&tinfo,s,0,0,0); 1230 } 1231 s = Join_line_list_with_sep(&tinfo,","); 1232 Set_str_value(&Spool_control,SERVER_ORDER,s); 1233 Set_spool_control(0, Queue_control_file_DYN, &Spool_control); 1234 if(s) free(s); s = 0; 1235 Free_line_list(&tinfo); 1236 } 1237 Free_listof_line_list(&servers); 1238 1239 /* truncate and close the lock file then wait a short time for signal */ 1240 ftruncate( lock_fd, 0 ); 1241 close( lock_fd ); 1242 lock_fd = -1; 1243 /* force status update */ 1244 if( Lpq_status_file_DYN ){ 1245 unlink(Lpq_status_file_DYN); 1246 } 1247 plp_unblock_all_signals( &oblock); 1248 plp_usleep(500); 1249 DEBUG1( "Do_queue_jobs: Susr1 at end %d", Susr1 ); 1250 if( Susr1 ){ 1251 DEBUG1("Do_queue_jobs: SIGUSR1 just before exit" ); 1252 Susr1 = 0; 1253 goto again; 1254 } 1255 cleanup(0); 1256 return(0); 1257} 1258 1259#ifdef ORIGINAL_DEBUG//JY@1020 1260/*************************************************************************** 1261 * Remote_job() 1262 * Send a job to a remote server. This code is actually trickier 1263 * than it looks, as the Send_job code takes most of the heat. 1264 * 1265 ***************************************************************************/ 1266 1267int Remote_job( struct job *job, int lpd_bounce, char *move_dest, char *id ) 1268{ 1269 int status, tempfd, n; 1270 double job_size; 1271 char buffer[SMALLBUFFER], *s, *tempfile, *oldid, *newid, *old_lp_value; 1272 struct line_list *lp, *firstfile; 1273 struct job jcopy; 1274 struct stat statb; 1275 1276 DEBUG1("Remote_job: %s", id ); 1277 /* setmessage(job,STATE,"SENDING"); */ 1278 status = 0; 1279 Init_job(&jcopy); 1280 1281 Set_str_value(&job->info,PRSTATUS,0); 1282 Set_str_value(&job->info,ERROR,0); 1283 Set_flag_value(&job->info,ERROR_TIME,0); 1284 1285 Setup_user_reporting(job); 1286 1287 if( Accounting_remote_DYN && Accounting_file_DYN ){ 1288 if( Accounting_start_DYN ){ 1289 status = Do_accounting( 0, 1290 Accounting_start_DYN, job, Connect_interval_DYN ); 1291 } 1292 DEBUG1("Remote_job: accounting status %s", Server_status(status) ); 1293 if( status ){ 1294 SNPRINTF(buffer,sizeof(buffer)) 1295 "accounting check failed '%s'", Server_status(status)); 1296 SETSTATUS(job)"%s", buffer ); 1297 switch(status){ 1298 case JFAIL: break; 1299 case JHOLD: /* Set_flag_value(&job->info,HOLD_TIME,time((void *)0)); */ break; 1300 case JREMOVE: /* Set_flag_value(&job->info,REMOVE_TIME,time((void *)0)); */ break; 1301 default: 1302 Set_str_value(&job->info,ERROR,buffer); 1303 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 1304 Set_hold_file(job, 0, 0 ); 1305 break; 1306 } 1307 goto exit; 1308 } 1309 } 1310 1311 Errorcode = status = 0; 1312 1313 Copy_job(&jcopy,job); 1314#ifdef ORIGINAL_DEBUG//JY@1020 1315 if(DEBUGL2)Dump_job("Remote_job - jcopy", &jcopy ); 1316#endif 1317 if( lpd_bounce ){ 1318#ifdef ORIGINAL_DEBUG//JY@1020 1319 if(DEBUGL2) Dump_job( "Remote_job - before filtering", &jcopy ); 1320#endif 1321 tempfd = Make_temp_fd(&tempfile); 1322 1323 old_lp_value = safestrdup(Find_str_value( &PC_entry_line_list, "lp", Value_sep), 1324 __FILE__,__LINE__ ); 1325 Set_str_value( &PC_entry_line_list, LP, tempfile ); 1326 Print_job( tempfd, -1, &jcopy, 0, 0, 0 ); 1327 Set_str_value( &PC_entry_line_list, LP, old_lp_value ); 1328 if( old_lp_value ) free(old_lp_value); old_lp_value = 0; 1329 1330 if( fstat( tempfd, &statb ) ){ 1331 LOGERR(LOG_INFO)"Remote_job: fstatb failed" ); 1332 status = JFAIL; 1333 } 1334 if( (close(tempfd) == -1 ) ){ 1335 status = JFAIL; 1336 LOGERR(LOG_INFO)"Remote_job: close(%d) failed", 1337 tempfd); 1338 } 1339 if( statb.st_size == 0 ){ 1340 LOGMSG( LOG_ERR) "Remote_job: zero length job after filtering"); 1341 status = JABORT; 1342 } 1343 if( status ) goto exit; 1344 job_size = statb.st_size; 1345 Free_listof_line_list(&jcopy.datafiles); 1346 lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__); 1347 memset(lp,0,sizeof(lp[0])); 1348 Check_max(&jcopy.datafiles,1); 1349 jcopy.datafiles.list[jcopy.datafiles.count++] = (void *)lp; 1350 Set_str_value(lp,OPENNAME,tempfile); 1351 Set_str_value(lp,TRANSFERNAME,tempfile); 1352 s = 0; 1353 if( (firstfile = (void *)(job->datafiles.list[0])) ){ 1354 s = Find_str_value( firstfile, "N", Value_sep ); 1355 } 1356 Set_str_value(lp,"N",s?s:"(lpd_filter)"); 1357 Set_flag_value(lp,COPIES,1); 1358 Set_double_value(lp,SIZE,job_size); 1359 Fix_bq_format( 'f', lp ); 1360 } else if( !move_dest ) { 1361 int err = Errorcode; 1362 Errorcode = 0; 1363 if( Generate_banner_DYN ){ 1364 Add_banner_to_job( &jcopy ); 1365 } 1366 Filter_files_in_job( &jcopy, -1, 0 ); 1367 status = Errorcode; 1368 Errorcode = err; 1369 if( status ){ 1370 goto done; 1371 } 1372 } 1373 1374 /* fix up the control file */ 1375 Fix_control( &jcopy, Control_filter_DYN, Xlate_format_DYN ); 1376 oldid = Find_str_value(&job->info,IDENTIFIER,Value_sep ); 1377 newid = Find_str_value(&jcopy.destination,IDENTIFIER,Value_sep ); 1378 if( newid == 0 ){ 1379 newid = Find_str_value(&jcopy.info,IDENTIFIER,Value_sep ); 1380 } 1381 n = Find_flag_value( &jcopy.info, DATAFILE_COUNT, Value_sep ); 1382 if( Max_datafiles_DYN > 0 && n > Max_datafiles_DYN ){ 1383 Errorcode = JABORT; 1384 FATAL(LOG_ERR) 1385 _("Remote_job: %d datafiles and only allowed %d"), 1386 n, Max_datafiles_DYN ); 1387 } 1388#ifdef ORIGINAL_DEBUG//JY@1020 1389 setmessage(job,STATE,"SENDING OLDID=%s NEWID=%s DEST=%s@%s", 1390 oldid, newid, RemotePrinter_DYN, RemoteHost_DYN ); 1391 if(DEBUGL3)Dump_job("Send_job - after Fix_control", &jcopy ); 1392#endif 1393 status = Send_job( &jcopy, job, Connect_timeout_DYN, Connect_interval_DYN, 1394 Max_connect_interval_DYN, Send_job_rw_timeout_DYN, 0 ); 1395 DEBUG1("Remote_job: %s, status '%s'", id, Link_err_str(status) ); 1396 buffer[0] = 0; 1397 1398#ifdef ORIGINAL_DEBUG//JY@1020 1399 if(DEBUGL2)Dump_job("Remote_job - final jcopy value", &jcopy ); 1400#endif 1401 done: 1402 s = 0; 1403 if( status ){ 1404 s = Find_str_value(&jcopy.info,ERROR,Value_sep); 1405 if( !s ){ 1406 s = "Mystery error from Send_job"; 1407 } 1408 Set_str_value(&job->info,ERROR,s); 1409 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 1410 } 1411 s = 0; 1412 1413 Free_job(&jcopy); 1414 1415 switch( status ){ 1416 case JSUCC: 1417 case JABORT: 1418 case JFAIL: 1419 case JREMOVE: 1420 break; 1421 case LINK_ACK_FAIL: 1422 SNPRINTF(buffer,sizeof(buffer)) 1423 _("link failure while sending job '%s'"), id ); 1424 s = buffer; 1425 status = JFAIL; 1426 break; 1427 case LINK_PERM_FAIL: 1428 SNPRINTF(buffer,sizeof(buffer)) 1429 _("no permission to spool job '%s'"), id ); 1430 s = buffer; 1431 status = JREMOVE; 1432 break; 1433 default: 1434 SNPRINTF(buffer,sizeof(buffer)) 1435 _("failed to send job '%s'"), id ); 1436 s = buffer; 1437 status = JFAIL; 1438 break; 1439 } 1440 if( s ){ 1441 if( !Find_str_value(&job->info,ERROR,Value_sep) ){ 1442 Set_str_value(&job->info,ERROR,s); 1443 } 1444 if( !Find_flag_value(&job->info,ERROR_TIME,Value_sep) ){ 1445 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 1446 } 1447 } 1448 1449 Set_str_value(&job->info,PRSTATUS,Server_status(status)); 1450 1451 Set_hold_file(job, 0, 0 ); 1452 1453 if( Accounting_remote_DYN && Accounting_file_DYN ){ 1454 if( Accounting_end_DYN ){ 1455 Do_accounting( 1, Accounting_end_DYN, job, 1456 Connect_interval_DYN ); 1457 } 1458 } 1459 exit: 1460 return( status ); 1461} 1462#endif 1463 1464/*************************************************************************** 1465 * Local_job() 1466 * Send a job to a local printer. 1467 ***************************************************************************/ 1468 1469int Local_job( struct job *job, char *id ) 1470{ 1471 int status, fd, status_fd, pid, poll_for_status; 1472 char *old_lp_value; 1473 char buffer[SMALLBUFFER]; 1474 1475 status_fd = fd = -1; 1476 1477 DEBUG1("Local_job: starting %s", id ); 1478#ifdef ORIGINAL_DEBUG//JY@1020 1479 setmessage(job,STATE,"PRINTING"); 1480#endif 1481 Errorcode = status = 0; 1482 Set_str_value(&job->info,PRSTATUS,0); 1483 Set_str_value(&job->info,ERROR,0); 1484 Set_flag_value(&job->info,ERROR_TIME,0); 1485 1486 Setup_user_reporting(job); 1487 1488 SETSTATUS(job)"subserver pid %d starting", getpid()); 1489 1490 if( Accounting_file_DYN && Local_accounting_DYN ){ 1491 SETSTATUS(job)"accounting at start"); 1492#ifdef ORIGINAL_DEBUG//JY@1020 1493 if( Accounting_start_DYN ){ 1494 status = Do_accounting( 0, 1495 Accounting_start_DYN, job, Connect_interval_DYN ); 1496 } 1497#endif 1498 1499 DEBUG1("Local_job: accounting status %s", Server_status(status) ); 1500 if( status ){ 1501 SNPRINTF(buffer,sizeof(buffer)) 1502 "accounting check failed '%s'", Server_status(status)); 1503 SETSTATUS(job)"%s", buffer ); 1504 switch(status){ 1505 case JFAIL: break; 1506 case JHOLD: /* Set_flag_value(&job->info,HOLD_TIME,time((void *)0)); */ break; 1507 case JREMOVE: /* Set_flag_value(&job->info,REMOVE_TIME,time((void *)0)); */ break; 1508 default: 1509 Set_str_value(&job->info,ERROR,buffer); 1510 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 1511 Set_hold_file(job, 0, 0 ); 1512 break; 1513 } 1514 goto exit; 1515 } 1516 } 1517 Errorcode = status = 0; 1518 1519 SETSTATUS(job)"opening device '%s'", Lp_device_DYN); 1520 pid = 0; 1521 fd = Printer_open(Lp_device_DYN, &status_fd, job, 1522 Send_try_DYN, Connect_interval_DYN, Max_connect_interval_DYN, 1523 Connect_grace_DYN, Connect_timeout_DYN, &pid, &poll_for_status ); 1524 1525 /* note: we NEVER return fd == 0 or horrible things have happened */ 1526 DEBUG1("Local_job: fd %d", fd ); 1527 if( fd <= 0 ){ 1528 status = JFAIL; 1529 goto exit; 1530 } 1531 SETSTATUS(job)"printing job '%s'", id ); 1532 /* Print_job( output_device, status_device, job, timeout, poll_for_status, filter ) */ 1533 old_lp_value = safestrdup(Find_str_value( &PC_entry_line_list, LP, Value_sep), 1534 __FILE__,__LINE__ ); 1535 Set_str_value( &PC_entry_line_list, LP, Lp_device_DYN ); 1536 status = Print_job( fd, status_fd, job, Send_job_rw_timeout_DYN, poll_for_status, 0 ); 1537 Set_str_value( &PC_entry_line_list, LP, old_lp_value ); 1538 if( old_lp_value ) free(old_lp_value); old_lp_value = 0; 1539 /* we close close device */ 1540 DEBUG1("Local_job: shutting down fd %d", fd ); 1541 1542 fd = Shutdown_or_close( fd ); 1543 DEBUG1("Local_job: after shutdown fd %d, status_fd %d", fd, status_fd ); 1544 if( status_fd > 0 ){ 1545 /* we shut down this connection as well */ 1546 status_fd = Shutdown_or_close( status_fd ); 1547 /* we wait for eof on status_fd */ 1548 buffer[0] = 0; 1549 if( status_fd > 0 ){ 1550 Get_status_from_OF(job,"LP",pid, 1551 status_fd, buffer, sizeof(buffer)-1, Send_job_rw_timeout_DYN, 1552 0, 0, Status_file_DYN ); 1553 } 1554 } 1555 if( fd > 0 ) close( fd ); fd = -1; 1556 if( status_fd > 0 ) close( status_fd ); status_fd = -1; 1557 if( pid > 0 ){ 1558 SETSTATUS(job)"waiting for printer filter to exit"); 1559 status = Wait_for_pid( pid, "LP", 0, Send_job_rw_timeout_DYN ); 1560 } 1561 DEBUG1("Local_job: status %s", Server_status(status) ); 1562 1563 Set_str_value(&job->info,PRSTATUS,Server_status(status)); 1564 if( Accounting_file_DYN && Local_accounting_DYN ){ 1565 SETSTATUS(job)"accounting at end"); 1566#ifdef ORIGINAL_DEBUG//JY@1020 1567 if( Accounting_end_DYN ){ 1568 Do_accounting( 1, Accounting_end_DYN, job, 1569 Connect_interval_DYN ); 1570 } 1571#endif 1572 } 1573 SETSTATUS(job)"finished '%s', status '%s'", id, Server_status(status)); 1574 1575 exit: 1576 if( fd != -1 ) close(fd); fd = -1; 1577 if( status_fd != -1 ) close(status_fd); status_fd = -1; 1578 return( status ); 1579} 1580 1581int Fork_subserver( struct line_list *server_info, int use_subserver, 1582 struct line_list *parms ) 1583{ 1584 char *pr; 1585 struct line_list *sp; 1586 int pid; 1587 struct line_list pl; 1588 1589 Init_line_list(&pl); 1590 if( parms == 0 ) parms = &pl; 1591 sp = (void *)server_info->list[use_subserver]; 1592 Set_str_value(sp,PRSTATUS,0); 1593 Set_decimal_value(sp,SERVER,0); 1594 1595 pr = Find_str_value(sp,PRINTER,Value_sep); 1596 Set_str_value(parms,PRINTER,pr); 1597 Set_flag_value(parms,SUBSERVER,use_subserver); 1598 DEBUG1( "Fork_subserver: starting '%s'", pr ); 1599 if( use_subserver > 0 ){ 1600#ifdef JYDEBUG//JYWeng 1601aaaaaa=fopen("/tmp/qqqqq", "a"); 1602fprintf(aaaaaa, "+++++++++++++++++++++++++++++++++++++++++++++\n"); 1603fprintf(aaaaaa, "Fork_subserver: Start_worker(queue)\n"); 1604fprintf(aaaaaa, "+++++++++++++++++++++++++++++++++++++++++++++\n"); 1605fclose(aaaaaa); 1606#endif 1607 pid = Start_worker( "queue",parms, 0 ); 1608 } else { 1609#ifdef JYDEBUG//JYWeng 1610aaaaaa=fopen("/tmp/qqqqq", "a"); 1611fprintf(aaaaaa, "+++++++++++++++++++++++++++++++++++++++++++++\n"); 1612fprintf(aaaaaa, "Fork_subserver: Start_worker(printer)\n"); 1613fprintf(aaaaaa, "+++++++++++++++++++++++++++++++++++++++++++++\n"); 1614fclose(aaaaaa); 1615#endif 1616 pid = Start_worker( "printer",parms, 0 ); 1617 } 1618 1619 if( pid > 0 ){ 1620 Set_decimal_value(sp,SERVER,pid); 1621 } else { 1622 LOGERR(LOG_ERR) _("Fork_subserver: fork failed") ); 1623 } 1624 Free_line_list(parms); 1625 return( pid ); 1626} 1627 1628#ifdef ORIGINAL_DEBUG//JY@1020 1629/*************************************************************************** 1630 * struct server_info *Wait_for_subserver( struct line_list *servers, 1631 * int block ) 1632 * wait for a server process to exit 1633 * if none present return 0 1634 * look up the process in the process table 1635 * update the process table status 1636 * return the process table entry 1637 ***************************************************************************/ 1638 1639void Wait_for_subserver( int timeout, struct line_list *servers 1640 /*, struct line_list *order */ ) 1641{ 1642 pid_t pid; 1643 plp_status_t procstatus; 1644 int found, sigval, status, i, done; 1645 struct line_list *sp = 0; 1646 struct job job; 1647 char buffer[SMALLBUFFER], *pr, *hf_name, *id; 1648 1649 /* 1650 * wait for the process to finish or a signal to be delivered 1651 */ 1652 1653 Init_job(&job); 1654 sigval = errno = 0; 1655 1656 done = 0; 1657 again: 1658 while( (pid = plp_waitpid( -1, &procstatus, WNOHANG )) > 0 ){ 1659 ++done; 1660 DEBUG1("Wait_for_subserver: pid %d, status '%s'", pid, 1661 Decode_status(&procstatus)); 1662 if( WIFSIGNALED( procstatus ) ){ 1663 sigval = WTERMSIG( procstatus ); 1664 DEBUG1("Wait_for_subserver: pid %d terminated by signal '%s'", 1665 pid, Sigstr( sigval ) ); 1666 switch( sigval ){ 1667 /* generated by the program */ 1668 case 0: 1669 case SIGINT: 1670 case SIGKILL: 1671 case SIGQUIT: 1672 case SIGTERM: 1673 case SIGUSR1: 1674 status = JFAIL; 1675 break; 1676 default: 1677 status = JSIGNAL; 1678 break; 1679 } 1680 } else { 1681 status = WEXITSTATUS( procstatus ); 1682 if( status > 0 && status < 32 ) status += JFAIL-1; 1683 } 1684 DEBUG1( "Wait_for_subserver: pid %d final status %s", 1685 pid, Server_status(status) ); 1686 1687 if( status != JSIGNAL ){ 1688 SNPRINTF(buffer,sizeof(buffer)) 1689 _("subserver pid %d exit status '%s'"), 1690 pid, Server_status(status)); 1691 } else { 1692 SNPRINTF(buffer,sizeof(buffer)) 1693 _("subserver pid %d died with signal '%s'"), 1694 pid, Sigstr(sigval)); 1695 status = JABORT; 1696 } 1697#ifdef ORIGINAL_DEBUG//JY@1020 1698 if(DEBUGL4) Dump_subserver_info("Wait_for_subserver", servers ); 1699#endif 1700 1701 for( found = i = 0; !found && i < servers->count; ++i ){ 1702 sp = (void *)servers->list[i]; 1703 if( pid == Find_flag_value(sp,SERVER,Value_sep) ){ 1704 DEBUG3("Wait_for_subserver: found %d", pid ); 1705 found = 1; 1706 ++done; 1707 1708 Free_job(&job); 1709 Set_decimal_value(sp,SERVER,0); 1710 Set_flag_value(sp,DONE_TIME,time((void *)0)); 1711 1712 /* we get the hold file information */ 1713 hf_name = Find_str_value(sp,HF_NAME,Value_sep); 1714 Get_hold_file( &job, hf_name ); 1715 Setup_cf_info( &job, 0 ); 1716 1717 pr = Find_str_value(sp,PRINTER,Value_sep); 1718 id = Find_str_value(sp,IDENTIFIER,Value_sep); 1719 DEBUG1( "Wait_for_subserver: server pid %d for '%s' for '%s' '%s' finished", 1720 pid, pr, hf_name, id ); 1721 1722 /* see if you can get the hold file and update the status */ 1723 Update_status( &job, status ); 1724 Set_str_value(sp,HF_NAME,0); 1725 Set_str_value(sp,IDENTIFIER,0); 1726 Update_spool_info(sp); 1727 if( i == 0 ){ 1728 /* this is the information for the master spool queue */ 1729 Get_spool_control(Queue_control_file_DYN, &Spool_control ); 1730 } 1731 } 1732 } 1733 Free_job(&job); 1734 /* sort server order */ 1735 if( Mergesort( servers->list+1, servers->count-1, 1736 sizeof( servers->list[0] ), cmp_server, 0 ) ){ 1737 FATAL(LOG_ERR) 1738 _("Wait_for_subserver: Mergesort failed") ); 1739 } 1740#ifdef ORIGINAL_DEBUG//JY@1020 1741 if(DEBUGL4) Dump_subserver_info( 1742 "Wait_for_subserver: after sorting", servers ); 1743#endif 1744 } 1745 if( !done ){ 1746 /* we need to unblock signals and wait for event */ 1747 Chld = 0; 1748 Set_timeout_break( timeout ); 1749 (void) plp_signal(SIGCHLD, (plp_sigfunc_t)Sigchld); 1750 plp_sigpause(); 1751 Clear_timeout(); 1752 signal( SIGCHLD, SIG_DFL ); 1753 if( Chld ) goto again; 1754 } 1755 1756 Free_job(&job); 1757} 1758#endif 1759 1760/*************************************************************************** 1761 * int Decode_transfer_failure( int attempt, struct job *job, int status ) 1762 * When you get a job failure more than a certain number of times, 1763 * you check the 'Send_failure_action_DYN' variable 1764 * This can be abort, retry, or remove 1765 * If retry, you keep retrying; if abort you shut the queue down; 1766 * if remove, you remove the job and try again. 1767 ***************************************************************************/ 1768 1769 static struct keywords keys[] = { 1770 {"succ", N_("succ"), INTEGER_K, (void *)0, JSUCC,0,0}, 1771 {"jsucc", N_("jsucc"), INTEGER_K, (void *)0, JSUCC,0,0}, 1772 {"success", N_("success"), INTEGER_K, (void *)0, JSUCC,0,0}, 1773 {"jsuccess", N_("jsuccess"), INTEGER_K, (void *)0, JSUCC,0,0}, 1774 {"abort", N_("abort"), INTEGER_K, (void *)0, JABORT,0,0}, 1775 {"jabort", N_("jabort"), INTEGER_K, (void *)0, JABORT,0,0}, 1776 {"hold", N_("hold"), INTEGER_K, (void *)0, JHOLD,0,0}, 1777 {"jhold", N_("jhold"), INTEGER_K, (void *)0, JHOLD,0,0}, 1778 {"remove", N_("remove"), INTEGER_K, (void *)0, JREMOVE,0,0}, 1779 {"jremove", N_("jremove"), INTEGER_K, (void *)0, JREMOVE,0,0}, 1780 { 0,0,0,0,0,0,0 } 1781}; 1782 1783int Decode_transfer_failure( int attempt, struct job *job ) 1784{ 1785 struct keywords *key; 1786 int result, n, len, c; 1787 char line[SMALLBUFFER], *outstr; 1788 1789 result = JREMOVE; 1790 outstr = Send_failure_action_DYN; 1791 if( outstr ) while( isspace(cval(outstr)) ) ++outstr; 1792 DEBUG1("Decode_transfer_failure: send_failure_action '%s'", outstr ); 1793 if( outstr && cval(outstr) == '|' ){ 1794 /* check to see if it is a filter */ 1795 int out_tempfd, in_tempfd; 1796 1797 outstr = 0; 1798 SNPRINTF( line, sizeof(line)) "%d\n", attempt ); 1799 out_tempfd = Make_temp_fd( 0); 1800 in_tempfd = Make_temp_fd( 0); 1801 if( Write_fd_str(in_tempfd,line) < 0 ){ 1802 Errorcode = JFAIL; 1803 LOGERR_DIE(LOG_INFO)"Decode_transfer_failure: write(%d) failed", 1804 in_tempfd); 1805 } 1806 if( lseek(in_tempfd,0,SEEK_SET) == -1 ){ 1807 Errorcode = JFAIL; 1808 LOGERR_DIE(LOG_INFO)"Decode_transfer_failure: fseek(%d) failed", 1809 in_tempfd); 1810 } 1811 n = Filter_file( in_tempfd, out_tempfd, "TRANSFER_FAILURE", 1812 Send_failure_action_DYN, Filter_options_DYN, job, 0, 1 ); 1813 DEBUG1("Decode_transfer_failure: exit status %s", Server_status(n)); 1814 if( n ){ 1815 result = n; 1816 setstatus( job, "send_failure_action filter exit status '%s'", 1817 Server_status(result) ); 1818 } else { 1819 if( lseek(out_tempfd,0,SEEK_SET) == -1 ){ 1820 Errorcode = JFAIL; 1821 LOGERR_DIE(LOG_INFO)"Decode_transfer_failure: fseek(%d) failed", 1822 out_tempfd); 1823 } 1824 len = read( out_tempfd, line,sizeof(line)-1 ); 1825 if( len >= 0 ){ 1826 line[len] = 0; 1827 } else { 1828 Errorcode = JFAIL; 1829 LOGERR_DIE(LOG_INFO)"Decode_transfer_failure: read(%d) failed", 1830 out_tempfd); 1831 } 1832 while( (c = cval(line)) && strchr( Whitespace, c) ){ 1833 memmove( line, line+1, safestrlen(line+1)+1 ); 1834 } 1835 while( (len = safestrlen(line)) && (c = cval(line+len-1)) 1836 && strchr( Whitespace, c) ){ 1837 line[len-1] = 0; 1838 } 1839 setstatus( job, "send_failure_action filter returned '%s'", 1840 outstr ); 1841 } 1842 close( out_tempfd ); out_tempfd = -1; 1843 close( in_tempfd ); in_tempfd = -1; 1844 } 1845 if( outstr && *outstr ){ 1846 DEBUG1("Decode_transfer_failure: outstr '%s'", outstr ); 1847 for( key = keys; key->keyword; ++key ){ 1848 DEBUG1("Decode_transfer_failure: comparing '%s' to '%s'", 1849 outstr, key->keyword ); 1850 if( safestrcasecmp( key->keyword, outstr ) == 0 ){ 1851 result = key->maxval; 1852 break; 1853 } 1854 } 1855 } 1856 DEBUG1("Decode_transfer_failure: result '%s'", Server_status(result) ); 1857 setstatus( job, "send_failure_action '%s'", Server_status(result) ); 1858 return( result ); 1859} 1860 1861void Update_status( struct job *job, int status ) 1862{ 1863 char buffer[SMALLBUFFER]; 1864 char *id, *did, *strv, *hf_name; 1865 struct line_list *destination; 1866 int copy, copies, attempt, destinations, n, done = 0; 1867 1868 did = 0; 1869 destinations = 0; 1870 destination = 0; 1871 Set_decimal_value(&job->info,SERVER,0); 1872 1873 id = Find_str_value(&job->info,IDENTIFIER,Value_sep); 1874 if( !id ){ 1875#ifdef ORIGINAL_DEBUG//JY@1020 1876 if(DEBUGL1)Dump_job("Update_status - no ID", job ); 1877#endif 1878 return; 1879 } 1880 1881 if( (destinations = Find_flag_value(&job->info,DESTINATIONS,Value_sep)) ){ 1882 did = Find_str_value(&job->info,DESTINATION,Value_sep ); 1883 if( !Get_destination_by_name( job, did ) ){ 1884 destination = &job->destination; 1885 did = Find_str_value(destination,IDENTIFIER,Value_sep); 1886 if(!did) did = Find_str_value(destination,TRANSFERNAME,Value_sep); 1887 Set_decimal_value(destination,SERVER,0); 1888 } 1889 } 1890#ifdef ORIGINAL_DEBUG//JY@1020 1891 setmessage(job,STATE,"EXITSTATUS %s", Server_status(status)); 1892#endif 1893 1894 again: 1895 DEBUG1("Update_status: again - status '%s', id '%s', dest id '%s'", 1896 Server_status(status), id, did ); 1897 1898#ifdef ORIGINAL_DEBUG//JY@1020 1899 setmessage(job,STATE,"PROCESSSTATUS %s", Server_status(status)); 1900#endif 1901 switch( status ){ 1902 /* hold the destination stuff */ 1903 case JHOLD: 1904 if( destination ){ 1905 Set_flag_value(destination,HOLD_TIME,time((void *)0) ); 1906 Update_destination(job); 1907 } else { 1908 Set_flag_value(&job->info,HOLD_TIME, time((void *)0) ); 1909 Set_flag_value(&job->info,PRIORITY_TIME, 0 ); 1910 } 1911 Set_hold_file( job, 0, 0 ); 1912 break; 1913 1914 case JSUCC: /* successful, remove job */ 1915#ifdef ORIGINAL_DEBUG//JY@1020 1916 if(DEBUGL3)Dump_job("Update_status - JSUCC start", job ); 1917#endif 1918 if( destination ){ 1919 done = 0; 1920 copies = Find_flag_value(&job->info,SEQUENCE,Value_sep); 1921 Set_flag_value(&job->info,SEQUENCE,copies+1); 1922 copies = Find_flag_value(destination,COPIES,Value_sep); 1923 copy = Find_flag_value(destination,COPY_DONE,Value_sep); 1924 n = Find_flag_value(destination,DESTINATION,Value_sep); 1925 if( Find_str_value(destination,MOVE,Value_sep) ){ 1926 Set_flag_value(destination,DONE_TIME,time((void *)0)); 1927 setstatus( job, "%s@%s: route job '%s' moved", 1928 Printer_DYN, FQDNHost_FQDN, did ); 1929 done = 1; 1930 } else { 1931 ++copy; 1932 Set_flag_value(destination,COPY_DONE,copy); 1933 if( copies ){ 1934 setstatus( job, 1935 "%s@%s: route job '%s' printed copy %d of %d", 1936 Printer_DYN, FQDNHost_FQDN, id, copy, copies ); 1937 } 1938 if( copy >= copies ){ 1939 Set_flag_value(destination,DONE_TIME,time((void *)0)); 1940 done = 1; 1941 ++n; 1942 } 1943 } 1944 Update_destination(job); 1945 id = Find_str_value(&job->info,IDENTIFIER,Value_sep); 1946 if( done && n >= destinations ){ 1947 Set_flag_value(&job->info,DONE_TIME,time((void *)0)); 1948 setstatus( job, "%s@%s: job '%s' printed", 1949 Printer_DYN, FQDNHost_FQDN, id ); 1950 goto done_job; 1951 } 1952 Set_hold_file( job, 0, 0 ); 1953 break; 1954 } else { 1955 copies = Find_flag_value(&job->info,COPIES,Value_sep); 1956 copy = Find_flag_value(&job->info,COPY_DONE,Value_sep); 1957 id = Find_str_value(&job->info,IDENTIFIER,Value_sep); 1958 if( !id ){ 1959 Errorcode = JABORT; 1960 FATAL(LOG_ERR) 1961 _("Update_status: no identifier for '%s'"), 1962 Find_str_value(&job->info,HF_NAME,Value_sep) ); 1963 } 1964 1965 if( Find_str_value(&job->info,MOVE,Value_sep) ){ 1966 Set_flag_value(&job->info,DONE_TIME,time((void *)0)); 1967 setstatus( job, "%s@%s: job '%s' moved", 1968 Printer_DYN, FQDNHost_FQDN, id ); 1969 } else { 1970 ++copy; 1971 Set_flag_value(&job->info,COPY_DONE,copy); 1972 if( copies ){ 1973 setstatus( job, "%s@%s: job '%s' printed copy %d of %d", 1974 Printer_DYN, FQDNHost_FQDN, id, copy, copies ); 1975 } 1976 if( copy >= copies ){ 1977 Set_flag_value(&job->info,DONE_TIME,time((void *)0)); 1978#ifdef ORIGINAL_DEBUG//JY@1020 1979 Sendmail_to_user( status, job ); 1980#endif 1981 setstatus( job, "%s@%s: job '%s' printed", 1982 Printer_DYN, FQDNHost_FQDN, id ); 1983 } else { 1984 Set_hold_file( job, 0, 0 ); 1985 break; 1986 } 1987 } 1988 done_job: 1989 hf_name = Find_str_value(&job->info,HF_NAME,Value_sep); 1990 DEBUG3("Update_status: done_job, id '%s', hf '%s'", id, hf_name ); 1991 if( hf_name ){ 1992 Set_flag_value(&job->info,REMOVE_TIME,time((void *)0)); 1993 Set_hold_file( job, 0, 0 ); 1994#ifdef ORIGINAL_DEBUG//JY@1020 1995 if(DEBUGL3)Dump_job("Update_status - done_job", job ); 1996#endif 1997 if( (Save_when_done_DYN || Done_jobs_DYN || Done_jobs_max_age_DYN) ){ 1998 setstatus( job, _("job '%s' saved"), id ); 1999 ++Done_count; 2000 if( !Done_time ) Done_time = time(0); 2001 } else { 2002 if( Remove_job( job ) ){ 2003 setstatus( job, _("could not remove job '%s'"), id); 2004 } else { 2005 setstatus( job, _("job '%s' removed"), id ); 2006 } 2007 } 2008 } 2009 } 2010 break; 2011 2012 case JTIMEOUT: 2013 case JFAIL: /* failed, retry ?*/ 2014 status = JFAIL; 2015 if( destination ){ 2016 attempt = Find_flag_value(destination,ATTEMPT,Value_sep); 2017 ++attempt; 2018 Set_flag_value(destination,ATTEMPT,attempt); 2019 Update_destination(job); 2020 } else { 2021 attempt = Find_flag_value(&job->info,ATTEMPT,Value_sep); 2022 ++attempt; 2023 Set_flag_value(&job->info,ATTEMPT,attempt); 2024 } 2025 DEBUG1( "Update_status: JFAIL - attempt %d, max %d", 2026 attempt, Send_try_DYN ); 2027 Set_hold_file( job, 0, 0 ); 2028 2029 if( Send_try_DYN > 0 && attempt >= Send_try_DYN ){ 2030 char buf[60]; 2031 2032 /* check to see what the failure action 2033 * should be - abort, failure; default is remove 2034 */ 2035 setstatus( job, _("job '%s', attempt %d, allowed %d"), 2036 id, attempt, Send_try_DYN ); 2037 status = Decode_transfer_failure( attempt, job ); 2038 switch( status ){ 2039 case JSUCC: strv = _("treating as successful"); break; 2040 case JFAIL: strv = _("retrying job"); break; 2041 case JFAILNORETRY: strv = _("no retry"); break; 2042 case JABORT: strv = _("aborting server"); break; 2043 case JREMOVE: strv = _("removing job - status JREMOVE"); break; 2044 case JHOLD: strv = _("holding job"); break; 2045 default: 2046 SNPRINTF( buf, sizeof(buf)) 2047 _("unexpected status 0x%x"), status ); 2048 strv = buf; 2049 status = JABORT; 2050 break; 2051 } 2052 setstatus( job, _("job '%s', %s"), id, strv ); 2053 } 2054 if( status == JFAIL ){ 2055 if( Send_try_DYN > 0 ){ 2056 setstatus( job, _("job '%s' attempt %d, trying %d times"), 2057 id, attempt, Send_try_DYN ); 2058 } else { 2059 setstatus( job, _("job '%s' attempt %d, trying indefinitely"), 2060 id, attempt); 2061 } 2062 if( destination ){ 2063 Set_str_value(destination,ERROR,0); 2064 Set_flag_value(destination,ERROR_TIME,0); 2065 Set_str_value(destination,PRSTATUS,0); 2066 } else { 2067 Set_str_value(&job->info,ERROR,0); 2068 Set_flag_value(&job->info,ERROR_TIME,0); 2069 Set_str_value(&job->info,PRSTATUS,0); 2070 } 2071 Set_hold_file( job, 0, 0 ); 2072 } else { 2073 goto again; 2074 } 2075 break; 2076 2077 case JFAILNORETRY: /* do not try again */ 2078 SNPRINTF( buffer, sizeof(buffer)) _("failed, no retry") ); 2079 if( destination ){ 2080 attempt = Find_flag_value(destination,ATTEMPT,Value_sep); 2081 ++attempt; 2082 if( !Find_str_value(destination,ERROR,Value_sep) ){ 2083 Set_str_value(destination,ERROR,buffer); 2084 } 2085 if( !Find_flag_value(destination,ERROR_TIME,Value_sep) ){ 2086 Set_nz_flag_value(destination,ERROR_TIME,time(0)); 2087 } 2088 Set_flag_value(destination,ATTEMPT,attempt); 2089 Update_destination(job); 2090 Set_hold_file( job, 0, 0 ); 2091 } else { 2092 attempt = Find_flag_value(&job->info,ATTEMPT,Value_sep); 2093 ++attempt; 2094 Set_flag_value(&job->info,ATTEMPT,attempt); 2095 if( !Find_str_value(&job->info,ERROR,Value_sep) ){ 2096 Set_str_value(&job->info,ERROR,buffer); 2097 } 2098 if( !Find_flag_value(&job->info,ERROR_TIME,Value_sep) ){ 2099 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 2100 } 2101 Set_nz_flag_value(&job->info,REMOVE_TIME, time( (void *)0) ); 2102 Set_hold_file( job, 0, 0 ); 2103#ifdef ORIGINAL_DEBUG//JY@1020 2104 Sendmail_to_user( status, job ); 2105#endif 2106 if( (Save_on_error_DYN || Done_jobs_DYN || Done_jobs_max_age_DYN) ){ 2107 setstatus( job, _("job '%s' saved"), id ); 2108 ++Done_count; 2109 if( !Done_time ) Done_time = time(0); 2110 } else { 2111 setstatus( job, _("removing job '%s' - JFAILNORETRY"), id); 2112 if( Remove_job( job ) ){ 2113 setstatus( job, _("could not remove job '%s'"), id); 2114 } else { 2115 setstatus( job, _("job '%s' removed"), id ); 2116 } 2117 } 2118 } 2119 break; 2120 2121 default: 2122 case JABORT: /* abort, do not try again */ 2123 SNPRINTF(buffer,sizeof(buffer)) _("aborting operations") ); 2124 Set_flag_value(&job->info,PRIORITY_TIME,0); 2125 if( destination ){ 2126 if( !Find_str_value(destination,ERROR,Value_sep) ){ 2127 Set_str_value(destination,ERROR,buffer); 2128 } 2129 if( !Find_flag_value(destination,ERROR_TIME,Value_sep) ){ 2130 Set_nz_flag_value(destination,ERROR_TIME,time(0)); 2131 } 2132 strv = Find_str_value(destination,ERROR,Value_sep); 2133 Update_destination(job); 2134 setstatus( job, "job '%s', destination '%s', error '%s'", 2135 id,did,strv ); 2136 } else { 2137 if( !Find_str_value(&job->info,ERROR,Value_sep) ){ 2138 Set_str_value(&job->info,ERROR,buffer); 2139 } 2140 if( !Find_flag_value(&job->info,ERROR_TIME,Value_sep) ){ 2141 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 2142 } 2143 strv = Find_str_value(&job->info,ERROR,Value_sep); 2144 setstatus( job, "job '%s' error '%s'",id, strv); 2145 Set_nz_flag_value(&job->info,REMOVE_TIME, time( (void *)0) ); 2146 Set_hold_file( job, 0, 0 ); 2147#ifdef ORIGINAL_DEBUG//JY@1020 2148 Sendmail_to_user( status, job ); 2149#endif 2150 if( (Save_on_error_DYN || Done_jobs_DYN || Done_jobs_max_age_DYN) ){ 2151 setstatus( job, _("job '%s' saved"), id ); 2152 ++Done_count; 2153 if( !Done_time ) Done_time = time(0); 2154 } else { 2155 setstatus( job, _("removing job '%s' - JABORT"), id); 2156 if( Remove_job( job ) ){ 2157 setstatus( job, _("could not remove job '%s'"), id); 2158 } else { 2159 setstatus( job, _("job '%s' removed"), id ); 2160 } 2161 } 2162 } 2163 if( Stop_on_abort_DYN ){ 2164 setstatus( job, _("stopping printing on filter JABORT exit code") ); 2165 Set_flag_value( &Spool_control,PRINTING_ABORTED,1 ); 2166 Set_spool_control(0, Queue_control_file_DYN, &Spool_control); 2167 } 2168 break; 2169 2170 case JREMOVE: /* failed, remove job */ 2171 if( destination ){ 2172 if( !Find_str_value(destination,ERROR,Value_sep) ){ 2173 SNPRINTF( buffer, sizeof(buffer)) 2174 _("removing destination due to errors") ); 2175 Set_str_value(destination,ERROR,buffer); 2176 } 2177 if( !Find_flag_value(destination,ERROR_TIME,Value_sep) ){ 2178 Set_nz_flag_value(destination,ERROR_TIME,time(0)); 2179 } 2180 Update_destination(job); 2181 Set_hold_file( job, 0, 0 ); 2182 } else { 2183 if( !Find_str_value(&job->info,ERROR,Value_sep) ){ 2184 SNPRINTF( buffer, sizeof(buffer)) 2185 _("too many errors") ); 2186 Set_str_value(&job->info,ERROR,buffer); 2187 } 2188 if( !Find_flag_value(&job->info,ERROR_TIME,Value_sep) ){ 2189 Set_nz_flag_value(&job->info,ERROR_TIME,time(0)); 2190 } 2191 Set_nz_flag_value(&job->info,REMOVE_TIME, time( (void *)0) ); 2192 Set_hold_file( job, 0, 0 ); 2193#ifdef ORIGINAL_DEBUG//JY@1020 2194 Sendmail_to_user( status, job ); 2195#endif 2196 if( (Save_on_error_DYN || Done_jobs_DYN || Done_jobs_max_age_DYN) ){ 2197 setstatus( job, _("job '%s' saved"), id ); 2198 ++Done_count; 2199 if( !Done_time ) Done_time = time(0); 2200 } else { 2201 setstatus( job, _("removing job '%s' - JREMOVE"), id); 2202 if( Remove_job( job ) ){ 2203 setstatus( job, _("could not remove job '%s'"), id); 2204 } else { 2205 setstatus( job, _("job '%s' removed"), id ); 2206 } 2207 } 2208 } 2209 break; 2210 } 2211#ifdef ORIGINAL_DEBUG//JY@1020 2212 if(DEBUGL3)Dump_job("Update_status: exit result", job ); 2213#endif 2214} 2215 2216/*************************************************************************** 2217 * int Check_print_perms 2218 * check the printing permissions 2219 ***************************************************************************/ 2220 2221int Check_print_perms( struct job *job ) 2222{ 2223 char *s; 2224 int permission; 2225 2226 memset( &Perm_check, 0, sizeof(Perm_check) ); 2227 Perm_check.service = 'P'; 2228 Perm_check.printer = Printer_DYN; 2229 Perm_check.user = Find_str_value(&job->info,LOGNAME,Value_sep); 2230 Perm_check.remoteuser = Perm_check.user; 2231 Perm_check.authuser = Find_str_value(&job->info,AUTHUSER,Value_sep); 2232 Perm_check.authfrom = Find_str_value(&job->info,AUTHFROM,Value_sep); 2233 Perm_check.authtype = Find_str_value(&job->info,AUTHTYPE,Value_sep); 2234 Perm_check.authca = Find_str_value(&job->info,AUTHCA,Value_sep); 2235 s = Find_str_value(&job->info,FROMHOST,Value_sep); 2236 if( s && Find_fqdn( &PermHost_IP, s ) ){ 2237 Perm_check.host = &PermHost_IP; 2238 } 2239 s = Find_str_value(&job->info,REMOTEHOST,Value_sep); 2240 if( s && Find_fqdn( &RemoteHost_IP, s ) ){ 2241 Perm_check.remotehost = &RemoteHost_IP; 2242 } else { 2243 Perm_check.remotehost = Perm_check.host; 2244 } 2245 Perm_check.unix_socket = Find_flag_value(&job->info,UNIXSOCKET,Value_sep); 2246 Perm_check.port = Find_flag_value(&job->info,REMOTEPORT,Value_sep); 2247 permission = Perms_check( &Perm_line_list,&Perm_check, job, 1 ); 2248 DEBUG3("Check_print_perms: permission '%s'", perm_str(permission) ); 2249 return( permission ); 2250} 2251 2252 2253void Setup_user_reporting( struct job *job ) 2254{ 2255 char *host = Find_str_value(&job->info,MAILNAME,Value_sep); 2256 char *port = 0, *protocol = "UDP", *s; 2257 int prot_num = SOCK_DGRAM; 2258 2259 DEBUG1("Setup_user_reporting: Allow_user_logging %d, host '%s'", 2260 Allow_user_logging_DYN, host ); 2261 if( !Allow_user_logging_DYN || host==0 2262 || safestrchr(host,'@') || !safestrchr(host,'%') ){ 2263 return; 2264 } 2265 2266 host = safestrdup(host,__FILE__,__LINE__); 2267 /* OK, we try to open a connection to the logger */ 2268 if( (s = safestrchr( host, '%')) ){ 2269 /* *s++ = 0; */ 2270 port = s; 2271 } 2272 if( (s = safestrchr( port, ',')) ){ 2273 *s++ = 0; 2274 protocol = s; 2275 if( safestrcasecmp( protocol, "TCP" ) == 0 ){ 2276 protocol = "TCP"; 2277 prot_num = SOCK_STREAM; 2278 } 2279 } 2280 2281 DEBUG3("setup_logger_fd: host '%s', port '%s', protocol %d", 2282 host, port, prot_num ); 2283 Mail_fd = Link_open_type(host, 10, prot_num, 0, 0 ); 2284 DEBUG3("Setup_user_reporting: Mail_fd '%d'", Mail_fd ); 2285 2286 if( Mail_fd > 0 && prot_num == SOCK_STREAM && Exit_linger_timeout_DYN > 0 ){ 2287 Set_linger( Mail_fd, Exit_linger_timeout_DYN ); 2288 } 2289 if( host ) free(host); host = 0; 2290} 2291 2292void Service_worker( struct line_list *args ) 2293{ 2294 int pid, unspooler_fd, destinations, attempt, n, lpd_bounce; 2295 struct line_list *destination; 2296 char *s, *path, *hf_name, *new_dest, *move_dest, 2297 *id, *did; 2298 struct stat statb; 2299 char buffer[SMALLBUFFER]; 2300 struct job job; 2301 2302 Name="(Worker)"; 2303 destination = 0; 2304 attempt = 0; 2305 2306 Init_job(&job); 2307 2308 Set_DYN(&Printer_DYN, Find_str_value(args,PRINTER,Value_sep)); 2309 setproctitle( "lpd %s '%s'", Name, Printer_DYN ); 2310 2311 DEBUG1("Service_worker: begin"); 2312 2313 (void) plp_signal(SIGUSR1, (plp_sigfunc_t)cleanup_USR1); 2314 Errorcode = JABORT; 2315 2316 /* you need to have a spool queue */ 2317 if( Setup_printer( Printer_DYN, buffer, sizeof(buffer), 0 ) ){ 2318 cleanup(0); 2319 } 2320 2321 if(DEBUGL4){ int fd; fd = dup(0); 2322 LOGDEBUG("Service_worker: after Setup_printer next fd %d",fd); close(fd); }; 2323 2324 pid = getpid(); 2325 DEBUG1( "Service_worker: pid %d", pid ); 2326 path = Make_pathname( Spool_dir_DYN, Queue_unspooler_file_DYN ); 2327 if( (unspooler_fd = Checkwrite( path, &statb, O_RDWR, 1, 0 )) < 0 ){ 2328 LOGERR_DIE(LOG_ERR) _("Service_worker: cannot open lockfile '%s'"), 2329 path ); 2330 } 2331 if(path) free(path); path = 0; 2332 Write_pid( unspooler_fd, pid, (char *)0 ); 2333 close(unspooler_fd); unspooler_fd = -1; 2334 2335 DEBUG3("Service_worker: checking path '%s'", path ); 2336 2337 hf_name = Find_str_value(args,HF_NAME,Value_sep); 2338 Get_hold_file( &job, hf_name ); 2339 2340 if( Setup_cf_info( &job, 1 ) ){ 2341 DEBUG3("Service_worker: missing files"); 2342 Errorcode = 0; 2343 cleanup(0); 2344 } 2345 2346 Set_str_value(&job.info,NEW_DEST, Find_str_value(args,NEW_DEST,Value_sep)); 2347 Set_str_value(&job.info,MOVE_DEST, Find_str_value(args,MOVE_DEST,Value_sep)); 2348 Set_decimal_value(&job.info,SERVER,getpid()); 2349 2350 Free_line_list(args); 2351 2352 n = Set_hold_file( &job, 0, 0 ); 2353 if( n ){ 2354 /* you cannot update hold file!! */ 2355 setstatus( &job, _("cannot update hold file for '%s'"), 2356 hf_name ); 2357 FATAL(LOG_ERR) 2358 _("Service_worker: cannot update hold file for '%s'"), 2359 hf_name ); 2360 } 2361 2362 id = Find_str_value(&job.info,IDENTIFIER,Value_sep); 2363 if( !id ){ 2364 FATAL(LOG_ERR) 2365 _("Service_worker: no identifier for '%s'"), 2366 Find_str_value(&job.info,HF_NAME,Value_sep) ); 2367 } 2368 2369 if( (destinations = Find_flag_value(&job.info,DESTINATIONS,Value_sep)) ){ 2370 did = Find_str_value(&job.info,DESTINATION,Value_sep ); 2371 if( !Get_destination_by_name( &job, did ) ){ 2372 destination = &job.destination; 2373 attempt = Find_flag_value(destination,ATTEMPT,Value_sep); 2374 } 2375 } else { 2376 attempt = Find_flag_value(&job.info,ATTEMPT,Value_sep); 2377 } 2378 DEBUG3("Service_worker: attempt %d", attempt ); 2379 new_dest = Find_str_value(&job.info,NEW_DEST,Value_sep); 2380 move_dest = Find_str_value(&job.info,MOVE_DEST,Value_sep); 2381 lpd_bounce = Lpd_bounce_DYN; 2382 if( move_dest ){ 2383 lpd_bounce = 0; 2384 new_dest = move_dest; 2385 } 2386 2387 /* 2388 * The following code is implementing job handling as follows. 2389 * if new_dest has a value then 2390 * new_dest has format 'pr' or 'pr@host' 2391 * if pr@host then 2392 * set RemotePrinter_DYN and RemoteHost_DYN 2393 * else 2394 * set RemotePrinter_DYN to pr 2395 * set RemoteHost_DYN to FQDNHost_FQDN 2396 */ 2397 2398 if( new_dest ){ 2399 Set_DYN( &RemoteHost_DYN, 0); 2400 Set_DYN( &RemotePrinter_DYN, 0); 2401 Set_DYN( &Lp_device_DYN, 0); 2402 2403 Set_DYN( &RemotePrinter_DYN, new_dest ); 2404 if( (s = safestrchr(RemotePrinter_DYN, '@')) ){ 2405 *s++ = 0; 2406 Set_DYN( &RemoteHost_DYN, s ); 2407 if( (s = safestrchr(s,'%')) ){ 2408 *s++ = 0; 2409 Set_DYN( &Lpd_port_DYN,s ); 2410 } 2411 } 2412 if( !RemoteHost_DYN ){ 2413 Set_DYN( &RemoteHost_DYN, LOCALHOST); 2414 } 2415 } 2416 2417 /* we put a timeout before each attempt */ 2418 if( attempt > 0 ){ 2419 n = 8; 2420 if( attempt < n ) n = attempt; 2421 n = Connect_interval_DYN * (1 << (n-1)) + Connect_grace_DYN; 2422 if( Max_connect_interval_DYN > 0 && n > Max_connect_interval_DYN ){ 2423 n = Max_connect_interval_DYN; 2424 } 2425 DEBUG1("Service_worker: attempt %d, sleeping %d", attempt, n); 2426 if( n > 0 ){ 2427 setstatus( &job, "attempt %d, sleeping %d before retry", attempt+1, n ); 2428 plp_sleep(n); 2429 } 2430 } 2431#ifdef ORIGINAL_DEBUG//JY@1020 2432 2433 if( RemotePrinter_DYN ){ 2434 Name = "(Worker - Remote)"; 2435 DEBUG1( "Service_worker: sending '%s' to '%s@%s'", 2436 id, RemotePrinter_DYN, RemoteHost_DYN ); 2437 setproctitle( "lpd %s '%s'", Name, Printer_DYN ); 2438 if( Remote_support_DYN ) uppercase( Remote_support_DYN ); 2439 if( safestrchr( Remote_support_DYN, 'R' ) ){ 2440 Errorcode = Remote_job( &job, lpd_bounce, move_dest, id ); 2441 } else { 2442 Errorcode = JABORT; 2443 setstatus( &job, "no remote support to `%s@%s'", 2444 RemotePrinter_DYN, RemoteHost_DYN ); 2445 } 2446 } else { 2447#endif 2448 Name = "(Worker - Print)"; 2449 DEBUG1( "Service_worker: printing '%s'", id ); 2450 setproctitle( "lpd %s '%s'", Name, Printer_DYN ); 2451 Errorcode = Local_job( &job, id ); 2452#ifdef ORIGINAL_DEBUG//JY@1020 2453 } 2454#endif 2455 cleanup(0); 2456} 2457 2458/*************************************************************************** 2459 * int Printer_open: opens the Printer_DYN 2460 ***************************************************************************/ 2461 2462/* 2463 * int Printer_open( 2464 * lp_device - open this device 2465 * char error, int errlen - record errors 2466 * int max_attempts - max attempts to open device or socket 2467 * int interval, - interval between attempts 2468 * int max_interval, - maximum interval 2469 * int grace, - minimum time between attempts 2470 * int connect_timeout - time to wait for connection success 2471 * int *pid - if we have a filter program, return pid 2472 * returns: 2473 * file descriptor 2474 */ 2475 2476int Printer_open( char *lp_device, int *status_fd, struct job *job, 2477 int max_attempts, int interval, int max_interval, int grace, 2478 int connect_tmout, int *filterpid, int *poll_for_status ) 2479{ 2480 int attempt, err = 0, n, device_fd, c, in[2], pid, readable, mask; 2481 struct stat statb; 2482 time_t tm; 2483 char tm_str[32]; 2484 char *host, *port, *filter; 2485 struct line_list args; 2486 2487 Init_line_list(&args); 2488 host = port = filter = 0; 2489 *filterpid = 0; 2490 DEBUG1( "Printer_open: device '%s', max_attempts %d, grace %d, interval %d, max_interval %d", 2491 lp_device, max_attempts, grace, interval, max_interval ); 2492 time( &tm ); 2493 tm_str[0] = 0; 2494 if( lp_device == 0 ){ 2495 FATAL(LOG_ERR) "Printer_open: printer '%s' missing lp_device value", 2496 Printer_DYN ); 2497 } 2498 2499 *status_fd = device_fd = -1; 2500 *poll_for_status = 0; 2501 /* we repeat until we get the device or exceed maximum attempts */ 2502 for( attempt = 0; device_fd < 0 && (max_attempts <= 0 || attempt < max_attempts); ++attempt ){ 2503 if( grace ) plp_sleep(grace); 2504 c = lp_device[0]; 2505 switch( c ){ 2506 case '|': 2507#if !defined(HAVE_SOCKETPAIR) 2508 FATAL(LOG_ERR)"Printer_open: requires socketpair() system call for output device to be filter"); 2509#else 2510 if( socketpair( AF_UNIX, SOCK_STREAM, 0, in ) == -1 ){ 2511 Errorcode = JFAIL; 2512 LOGERR_DIE(LOG_INFO)"Printer_open: socketpair() for filter input failed"); 2513 } 2514#endif 2515 Max_open(in[0]); Max_open(in[1]); 2516 DEBUG3("Printer_open: fd in[%d,%d]", in[0], in[1] ); 2517 /* set up file descriptors */ 2518 Free_line_list(&args); 2519 Check_max(&args,10); 2520 args.list[args.count++] = Cast_int_to_voidstar(in[0]); /* stdin */ 2521 args.list[args.count++] = Cast_int_to_voidstar(in[0]); /* stdout */ 2522 args.list[args.count++] = Cast_int_to_voidstar(in[0]); /* stderr */ 2523 if( (pid = Make_passthrough( lp_device, Filter_options_DYN, &args, 2524 job, 0 )) < 0 ){ 2525 Errorcode = JFAIL; 2526 LOGERR_DIE(LOG_INFO) 2527 "Printer_open: could not create LP_FILTER process"); 2528 } 2529 args.count = 0; 2530 Free_line_list(&args); 2531 2532 *filterpid = pid; 2533 device_fd = in[1]; 2534 *status_fd = in[1]; 2535 if( (close( in[0] ) == -1 ) ){ 2536 LOGERR_DIE(LOG_INFO)"Printer_open: close(%d) failed", in[0]); 2537 } 2538 break; 2539 2540 case '/': 2541 DEBUG3( "Printer_open: Is_server %d, DaemonUID %d, DaemonGID %d, UID %d, EUID %d, GID %d, EGID %d", 2542 Is_server, DaemonUID, DaemonGID, 2543 getuid(), geteuid(), getgid(), getegid() ); 2544 device_fd = Checkwrite_timeout( connect_tmout, lp_device, &statb, 2545 (Read_write_DYN || Lock_it_DYN) ?(O_RDWR):(O_APPEND|O_WRONLY), 2546 0, Nonblocking_open_DYN ); 2547 err = errno; 2548 if( device_fd > 0 ){ 2549 if( Lock_it_DYN ){ 2550 int status; 2551 /* 2552 * lock the device so that multiple servers can 2553 * use it 2554 */ 2555 status = 0; 2556 if( isatty( device_fd ) ){ 2557 status = LockDevice( device_fd, 0 ); 2558 } else if( S_ISREG(statb.st_mode ) ){ 2559 status = Do_lock( device_fd, 0 ); 2560 } 2561 if( status < 0 ){ 2562 err = errno; 2563#ifdef ORIGINAL_DEBUG//JY@1020 2564 setstatus( job, 2565 "lock '%s' failed - %s", lp_device, Errormsg(errno) ); 2566#endif 2567 close( device_fd ); 2568 device_fd = -1; 2569 } 2570 } 2571#ifdef ORIGINAL_DEBUG//JY@1020 2572 if( isatty( device_fd ) ){ 2573 Do_stty( device_fd ); 2574 } 2575#endif 2576 *status_fd = device_fd; 2577 } 2578 break; 2579 default: 2580 if( safestrchr( lp_device, '%' ) ){ 2581 /* we have a host%port form */ 2582 host = lp_device; 2583 } else { 2584 Errorcode = JABORT; 2585 FATAL(LOG_ERR) "Printer_open: printer '%s', bad 'lp' entry '%s'", 2586 Printer_DYN, lp_device ); 2587 } 2588 DEBUG1( "Printer_open: doing link open '%s'", lp_device ); 2589 *status_fd = device_fd = Link_open( host, connect_tmout, 0, 0 ); 2590 err = errno; 2591 break; 2592 } 2593 2594 if( device_fd < 0 ){ 2595#ifdef ORIGINAL_DEBUG//JY@1020 2596 DEBUG1( "Printer_open: open '%s' failed, max_attempts %d, attempt %d '%s'", 2597 lp_device, max_attempts, attempt, Errormsg(err) ); 2598#endif 2599 if( max_attempts && attempt <= max_attempts ){ 2600 n = 8; 2601 if( attempt < n ) n = attempt; 2602 n = interval*( 1 << n ); 2603 if( max_interval > 0 && n > max_interval ) n = max_interval; 2604#ifdef ORIGINAL_DEBUG//JY@1020 2605 setstatus( job, "cannot open '%s' - '%s', attempt %d, sleeping %d", 2606 lp_device, Errormsg( err), attempt+1, n ); 2607#endif 2608 if( n > 0 ){ 2609 plp_sleep(n); 2610 } 2611 } else { 2612#ifdef ORIGINAL_DEBUG//JY@1020 2613 setstatus( job, "cannot open '%s' - '%s', attempt %d", 2614 lp_device, Errormsg( err), attempt+1 ); 2615#endif 2616 } 2617 } 2618 } 2619 if( device_fd >= 0 ){ 2620 int fd = *status_fd; 2621 if( fstat( fd, &statb ) < 0 ) { 2622 LOGERR_DIE(LOG_INFO)"Printer_open: fstat() on status_fd %d failed", fd); 2623 } 2624 /* we can only read status from a device, fifo, or socket */ 2625 if( (mask = fcntl( fd, F_GETFL, 0 )) == -1 ){ 2626 Errorcode = JABORT; 2627 LOGERR_DIE(LOG_ERR) "Printer_open: cannot fcntl fd %d", fd ); 2628 } 2629 DEBUG2( "Printer_open: status_fd %d fcntl 0%o", fd, mask ); 2630 mask &= O_ACCMODE; 2631 /* first, check to see if we have RD or RW */ 2632 readable = 1; 2633 switch( mask ){ 2634 case O_WRONLY: 2635 readable = 0; 2636 if( fd == device_fd ){ 2637 *status_fd = -1; 2638 } else { 2639 Errorcode = JABORT; 2640 FATAL(LOG_ERR) "Printer_open: LOGIC ERROR: status_fd %d WRITE ONLY", fd ); 2641 } 2642 break; 2643 } 2644 /* we handle the case where we have a device like a parallel port 2645 * or a USB port which does NOT support 'select()' 2646 * AND where there may be some really strange status at the end 2647 * of the printing operation 2648 * AND we cannot close the connection UNTIL we get the status 2649 * This is really silly but we need to handle it. Note that the 2650 * IFHP filter has to do exactly the same thing... Sigh... 2651 */ 2652 if( readable && S_ISCHR(statb.st_mode) && !isatty(device_fd) ){ 2653 *poll_for_status = 1; 2654 } 2655 } 2656 2657 DEBUG1 ("Printer_open: '%s' is fd %d", lp_device, device_fd); 2658 return( device_fd ); 2659} 2660 2661void Add_banner_to_job( struct job *job ) 2662{ 2663 char *banner_name, *tempfile; 2664 struct line_list *lp; 2665 int tempfd; 2666 2667 Errorcode = 0; 2668 banner_name = Find_str_value(&job->info, BNRNAME, Value_sep ); 2669 if( banner_name == 0 ){ 2670 banner_name = Find_str_value( &job->info,LOGNAME,Value_sep); 2671 } 2672 if( banner_name == 0 ) banner_name = "ANONYMOUS"; 2673 Set_str_value(&job->info,BNRNAME,banner_name); 2674 banner_name = Find_str_value(&job->info, BNRNAME, Value_sep ); 2675 DEBUG1("Add_banner_to_job: banner name '%s'", banner_name ); 2676 if( !Banner_last_DYN ){ 2677 DEBUG1("Add_banner_to_job: banner at start"); 2678 Init_buf(&Outbuf, &Outmax, &Outlen ); 2679 Print_banner( banner_name, Banner_start_DYN, job ); 2680 tempfd = Make_temp_fd(&tempfile); 2681 if( Write_fd_len( tempfd, Outbuf, Outlen ) < 0 ){ 2682 LOGERR(LOG_INFO)"Add_banner_to_job: write to '%s' failed", tempfile ); 2683 Errorcode = JABORT; 2684 return; 2685 } 2686 close(tempfd); 2687 lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__); 2688 memset(lp,0,sizeof(lp[0])); 2689 Check_max(&job->datafiles,1); 2690 memmove( &job->datafiles.list[1], &job->datafiles.list[0], 2691 job->datafiles.count * sizeof(job->datafiles.list[0]) ); 2692 job->datafiles.list[0] = (void *)lp; 2693 ++job->datafiles.count; 2694 2695 Set_str_value(lp,OPENNAME,tempfile); 2696 Set_str_value(lp,TRANSFERNAME,tempfile); 2697 Set_str_value(lp,"N","BANNER"); 2698 Set_str_value(lp,FORMAT,"f"); 2699 } 2700 if( Banner_last_DYN || Banner_end_DYN) { 2701 Init_buf(&Outbuf, &Outmax, &Outlen ); 2702 Print_banner( banner_name, Banner_end_DYN, job ); 2703 tempfd = Make_temp_fd(&tempfile); 2704 if( Write_fd_len( tempfd, Outbuf, Outlen ) < 0 ){ 2705 LOGERR(LOG_INFO)"Add_banner_to_job: write to '%s' failed", tempfile ); 2706 Errorcode = JABORT; 2707 return; 2708 } 2709 close(tempfd); 2710 lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__); 2711 memset(lp,0,sizeof(lp[0])); 2712 Check_max(&job->datafiles,1); 2713 job->datafiles.list[job->datafiles.count] = (void *)lp; 2714 ++job->datafiles.count; 2715 Set_str_value(lp,OPENNAME,tempfile); 2716 Set_str_value(lp,TRANSFERNAME,tempfile); 2717 Set_str_value(lp,"N","BANNER"); 2718 Set_str_value(lp,FORMAT,"f"); 2719 } 2720#ifdef ORIGINAL_DEBUG//JY@1020 2721 if(DEBUGL3)Dump_job("Add_banner_to_job", job); 2722#endif 2723} 2724 2725/* change the format of the output of a filter 2726 * bq_format=IoIo...D 2727 * I is input type or '*' for all types 2728 * o is output type 2729 * D is default 2730 * If no default, preserve the original type 2731 */ 2732 2733void Fix_bq_format( int format, struct line_list *datafile ) 2734{ 2735 char fmt[2], *s; 2736 fmt[0] = format; fmt[1] = 0; 2737 if( (s = Bounce_queue_format_DYN) ){ 2738 lowercase( s ); 2739 while( s[0] ){ 2740 if( s[1] ){ 2741 if( format == cval(s) || cval(s) == '*' ){ 2742 fmt[0] = s[1]; 2743 break; 2744 } 2745 } else { 2746 if( cval(s) != '*' ){ 2747 fmt[0] = s[0]; 2748 } 2749 break; 2750 } 2751 s += 2; 2752 } 2753 } 2754 Set_str_value(datafile,FORMAT,fmt); 2755} 2756 2757/* 2758 * Filter all the files in the print job 2759 */ 2760void Filter_files_in_job( struct job *job, int outfd, char *user_filter ) 2761{ 2762 struct line_list *datafile; 2763 char *tempfile, *openname, *format, *s, *filter, *id, *old_lp_value; 2764 char filter_name[8], filter_title[64], msg[SMALLBUFFER], 2765 filtermsgbuffer[SMALLBUFFER]; 2766 struct stat statb; 2767 int tempfd, fd, n, pid, count, if_error[2]; 2768 struct line_list files; 2769 2770 Init_line_list(&files); 2771 DEBUG1("Filter_files_in_job: starting, user_filter '%s'", user_filter); 2772 if(DEBUGL3){ 2773 struct stat statb; int i; 2774 LOGDEBUG("Filter_files_in_job: START open fd's"); 2775 for( i = 0; i < 20; ++i ){ 2776 if( fstat(i,&statb) == 0 ){ 2777 LOGDEBUG(" fd %d (0%o)", i, statb.st_mode&S_IFMT); 2778 } 2779 } 2780 } 2781 Errorcode = 0; 2782 old_lp_value = safestrdup(Find_str_value( &PC_entry_line_list, "lp", Value_sep ), 2783 __FILE__,__LINE__ ); 2784 2785 id = Find_str_value(&job->info,IDENTIFIER,Value_sep); 2786 tempfd = -1; 2787 for( count = 0; count < job->datafiles.count; ++count ){ 2788 datafile = (void *)job->datafiles.list[count]; 2789#ifdef ORIGINAL_DEBUG//JY@1020 2790 if(DEBUGL4)Dump_line_list("Filter_files_in_job - datafile", datafile ); 2791#endif 2792 2793 openname = Find_str_value(datafile,OPENNAME,Value_sep); 2794 if( !openname ) openname = Find_str_value(datafile,TRANSFERNAME,Value_sep); 2795 format = Find_str_value(datafile,FORMAT,Value_sep); 2796 2797 Set_str_value(&job->info,FORMAT,format); 2798 Set_str_value(&job->info,DF_NAME,openname); 2799 Set_str_value(&job->info,"N", Find_str_value(datafile,"N",Value_sep) ); 2800 2801 /* 2802 * now we check to see if there is an input filter 2803 */ 2804 SNPRINTF(filter_name,sizeof(filter_name))"%s","if"); 2805 filter_name[0] = cval(format); 2806 filter = user_filter; 2807 switch( cval(format) ){ 2808 case 'p': case 'f': case 'l': 2809 filter_name[0] = 'i'; 2810 if( !filter ) filter = IF_Filter_DYN; 2811 break; 2812 case 'a': case 'i': case 'o': case 's': 2813 SETSTATUS(job)"bad data file format '%c', using 'f' format", cval(format) ); 2814 filter_name[0] = 'i'; 2815 format = "f"; 2816 if( !filter ) filter = IF_Filter_DYN; 2817 break; 2818 } 2819 if( !filter ){ 2820 filter = Find_str_value(&PC_entry_line_list, 2821 filter_name,Value_sep); 2822 } 2823 if( !filter){ 2824 filter = Find_str_value(&Config_line_list,filter_name, 2825 Value_sep); 2826 } 2827 if( filter == 0 ) filter = Filter_DYN; 2828 DEBUG3("Filter_files_in_job: format '%s', filter '%s'", format, filter ); 2829 2830 if( filter == 0 ){ 2831 continue; 2832 } 2833 2834 uppercase(filter_name); 2835 if( filter ){ 2836 s = filter; 2837 if( cval(s) == '(' ){ 2838 ++s; 2839 while( isspace(cval(s))) ++s; 2840 } else { 2841 if( !(s = strchr(filter,'/')) ) s = filter; 2842 } 2843 SNPRINTF(msg, sizeof(msg)) "%s", s ); 2844 if( (s = strpbrk(msg,Whitespace)) ) *s = 0; 2845 if( (s = strrchr(msg,'/')) ) memmove(msg,s+1,safestrlen(s+1)+1); 2846 } 2847 SNPRINTF(filter_title,sizeof(filter_title))"%s filter '%s'", 2848 filter_name, msg ); 2849 2850 if( (fd = Checkread( openname, &statb )) < 0 ){ 2851 Errorcode = JFAIL; 2852 LOGMSG( LOG_ERR) "Filter_files_in_job: job '%s', cannot open data file '%s'", 2853 id, openname ); 2854 goto end_of_job; 2855 } 2856 SETSTATUS(job)"processing '%s', size %0.0f, format '%s', %s", 2857 openname, (double)statb.st_size, format, filter_title ); 2858 if( cval(format) == 'p' ){ 2859 DEBUG3("Filter_files_in_job: using 'p' formatter '%s'", Pr_program_DYN ); 2860 SETSTATUS(job)"format 'p' pretty printer '%s'", Pr_program_DYN); 2861 if( Pr_program_DYN == 0 ){ 2862 SETSTATUS(job)"no 'p' format filter available" ); 2863 Errorcode = JABORT; 2864 goto end_of_job; 2865 } 2866 tempfd = Make_temp_fd(&tempfile); 2867 Set_str_value(datafile,OPENNAME,tempfile); 2868 n = Filter_file( fd, tempfd, "PR_PROGRAM", 2869 Pr_program_DYN, 0, job, 0, 1 ); 2870 if( n ){ 2871 Errorcode = JABORT; 2872 LOGERR(LOG_INFO)"Filter_files_in_job: could not make '%s' process", 2873 Pr_program_DYN ); 2874 goto end_of_job; 2875 } 2876 close(fd); fd = tempfd; tempfd = -1; 2877 if( fstat(fd, &statb ) == -1 ){ 2878 Errorcode = JABORT; 2879 LOGERR(LOG_INFO)"Filter_files_in_job: fstat() failed"); 2880 } 2881 SETSTATUS(job)"data file '%s', size now %0.0f", 2882 openname, (double)statb.st_size ); 2883 format = "f"; 2884 Set_str_value(datafile,FORMAT,format); 2885 } 2886 if( filter ){ 2887 DEBUG3("Filter_files_in_job: format '%s' starting filter '%s'", 2888 format, filter ); 2889 DEBUG2("Filter_files_in_job: filter_stderr_to_status_file %d, ps '%s'", 2890 Filter_stderr_to_status_file_DYN, Status_file_DYN ); 2891 if_error[0] = if_error[1] = -1; 2892 if( Filter_stderr_to_status_file_DYN && Status_file_DYN && *Status_file_DYN ){ 2893 if_error[1] = Checkwrite( Status_file_DYN, &statb, O_WRONLY|O_APPEND, 0, 0 ); 2894 } else if( pipe( if_error ) == -1 ){ 2895 Errorcode = JFAIL; 2896 LOGERR(LOG_INFO)"Filter_files_in_job: pipe() failed"); 2897 goto end_of_job; 2898 } 2899 Max_open(if_error[0]); Max_open(if_error[1]); 2900 DEBUG3("Filter_files_in_job: %s fd if_error[%d,%d]", filter_title, 2901 if_error[0], if_error[1] ); 2902 s = 0; 2903 if( Backwards_compatible_filter_DYN ) s = BK_filter_options_DYN; 2904 if( s == 0 ) s = Filter_options_DYN; 2905 2906 Free_line_list(&files); 2907 Check_max(&files, 10 ); 2908 files.list[files.count++] = Cast_int_to_voidstar(fd); /* stdin */ 2909 2910 if( outfd > 0 ){ 2911 files.list[files.count++] = Cast_int_to_voidstar(outfd); /* stdout */ 2912 } else { 2913 tempfd = Make_temp_fd(&tempfile); 2914 Set_str_value( &PC_entry_line_list, LP, tempfile ); 2915 Set_str_value(datafile,OPENNAME,tempfile); 2916 files.list[files.count++] = Cast_int_to_voidstar(tempfd); /* stdout */ 2917 } 2918 2919 files.list[files.count++] = Cast_int_to_voidstar(if_error[1]); /* stderr */ 2920 if( (pid = Make_passthrough( filter, s, &files, job, 0 )) < 0 ){ 2921 Errorcode = JFAIL; 2922 LOGERR(LOG_INFO)"Filter_files_in_job: could not make %s process", 2923 filter_title ); 2924 goto end_of_job; 2925 } 2926 files.count = 0; 2927 Free_line_list(&files); 2928 2929 if( fd > 0 ) close(fd); fd = -1; 2930 if( tempfd > 0 ) close(tempfd); tempfd = -1; 2931 if( (close(if_error[1]) == -1 ) ){ 2932 Errorcode = JFAIL; 2933 LOGERR_DIE(LOG_INFO)"Filter_files_in_job: X5 close(%d) failed", 2934 if_error[1]); 2935 } 2936 if_error[1] = -1; 2937 Init_buf(&Outbuf, &Outmax, &Outlen ); 2938 2939 filtermsgbuffer[0] = 0; 2940 if( if_error[0] != -1 ){ 2941 n = Get_status_from_OF(job,filter_title,pid, 2942 if_error[0], filtermsgbuffer, sizeof(filtermsgbuffer)-1, 2943 0, 0, 0, Status_file_DYN ); 2944 if( filtermsgbuffer[0] ){ 2945 SETSTATUS(job) "%s filter msg - '%s'", filter_title, filtermsgbuffer ); 2946 } 2947 if( n ){ 2948 Errorcode = n; 2949 SETSTATUS(job)"%s filter problems, error '%s'", 2950 filter_title, Server_status(n)); 2951 goto end_of_job; 2952 } 2953 close(if_error[0]); 2954 if_error[0] = -1; 2955 } 2956 /* now we get the exit status for the filter */ 2957 n = Wait_for_pid( pid, filter_title, 0, 0 ); 2958 if( n ){ 2959 Errorcode = n; 2960 SETSTATUS(job)"%s filter exit status '%s'", 2961 filter_title, Server_status(n)); 2962 goto end_of_job; 2963 } 2964 SETSTATUS(job) "%s filter finished", filter_title ); 2965 Fix_bq_format( cval(format), datafile ); 2966 } 2967 DEBUG3("Filter_files_in_job: finished file"); 2968 } 2969 end_of_job: 2970 if( old_lp_value ) free( old_lp_value ); old_lp_value = 0; 2971 Free_line_list(&files); 2972 if(DEBUGL3){ 2973 struct stat statb; int i; 2974 LOGDEBUG("Filter_files_in_job: END open fd's"); 2975 for( i = 0; i < 20; ++i ){ 2976 if( fstat(i,&statb) == 0 ){ 2977 LOGDEBUG(" fd %d (0%o)", i, statb.st_mode&S_IFMT); 2978 } 2979 } 2980 } 2981#ifdef ORIGINAL_DEBUG//JY@1020 2982 if(DEBUGL3)Dump_job("Filter_files_in_job", job); 2983#endif 2984} 2985 2986void Service_queue( struct line_list *args ) 2987{ 2988 int subserver; 2989 2990 Set_DYN(&Printer_DYN, Find_str_value(args, PRINTER,Value_sep) ); 2991 subserver = Find_flag_value( args, SUBSERVER, Value_sep ); 2992 2993 Free_line_list(args); 2994 Do_queue_jobs( Printer_DYN, subserver ); 2995 cleanup(0); 2996} 2997 2998 2999int Remove_done_jobs( void ) 3000{ 3001 struct job job; 3002 char *id; 3003 int removed = 0; 3004 time_t tm; 3005 int job_index, info_index, pid, remove, error, done, incoming; 3006 struct line_list info; 3007 char tval[SMALLBUFFER]; 3008 3009 DEBUG3("Remove_done_jobs: save_when_done %d, save_on_error %d, done_jobs %d, d_j_max_age %d", 3010 Save_when_done_DYN, Save_on_error_DYN, 3011 Done_jobs_DYN, Done_jobs_max_age_DYN ); 3012 if( Save_when_done_DYN || Save_on_error_DYN 3013 || !(Done_jobs_DYN > 0 || Done_jobs_max_age_DYN > 0) ){ 3014 return( 0 ); 3015 } 3016 3017 Init_line_list(&info); 3018 time( &tm ); 3019 Init_job(&job); 3020 for( job_index = 0; job_index < Sort_order.count; ++job_index ){ 3021 char *hold_file = Sort_order.list[job_index]; 3022 Free_job(&job); 3023 if( ISNULL(hold_file) ) continue; 3024 DEBUG3("Remove_done_jobs: done_jobs - job_index [%d] '%s'", job_index, 3025 hold_file); 3026 Get_hold_file( &job, hold_file ); 3027#ifdef ORIGINAL_DEBUG//JY@1020 3028 if(DEBUGL4)Dump_job("Remove_done_jobs: done_jobs - job ",&job); 3029#endif 3030 if( job.info.count == 0 ) continue; 3031 /* get status from hold file */ 3032 id = Find_str_value(&job.info,IDENTIFIER,Value_sep); 3033 done = Find_flag_value(&job.info,DONE_TIME,Value_sep); 3034 error = Find_flag_value(&job.info,ERROR_TIME,Value_sep); 3035 incoming = Find_flag_value(&job.info,INCOMING_TIME,Value_sep); 3036 remove = Find_flag_value(&job.info,REMOVE_TIME,Value_sep); 3037 DEBUG3("Remove_done_jobs: remove 0x%x, done 0x%x, error 0x%x, incoming 0x%x", 3038 remove, done, error, incoming ); 3039 if( !remove ) continue; 3040 if( (pid = Find_flag_value(&job.info,SERVER,Value_sep)) && kill( pid, 0 ) == 0 ){ 3041 DEBUG3("Remove_done_jobs: '%s' active %d", hold_file, pid ); 3042 continue; 3043 } 3044 if( Done_jobs_max_age_DYN > 0 3045 && ( (error && (tm - error) > Done_jobs_max_age_DYN) 3046 || (done && (tm - done) > Done_jobs_max_age_DYN) ) ){ 3047 setstatus( &job, _("job '%s' removed- status expired"), id ); 3048 /* Setup_cf_info( &job, 0 ); */ 3049 Remove_job( &job ); 3050 } else if( Done_jobs_DYN > 0 ){ 3051 SNPRINTF(tval,sizeof(tval)) "0x%08x", remove ); 3052 Set_str_value(&info, tval, hold_file ); 3053 } 3054 } 3055 3056#ifdef ORIGINAL_DEBUG//JY@1020 3057 if(DEBUGL1)Dump_line_list("Remove_done_jobs - removal candidates",&info); 3058 DEBUG1( "Remove_done_jobs: checking for removal - remove_count %d", Done_jobs_DYN ); 3059#endif 3060 3061 for( info_index = 0; info_index < info.count - Done_jobs_DYN; ++info_index ){ 3062 char *hold_file = info.list[info_index]; 3063 if( (hold_file = safestrchr( hold_file, '=' )) ){ 3064 ++hold_file; 3065 } else { 3066 Errorcode = JABORT; 3067 fatal(LOG_ERR,"Remove_done_jobs: bad hold file format '%s'", 3068 info.list[info_index]); 3069 } 3070 DEBUG1( "Remove_done_jobs: [%d] hold_file '%s'", 3071 info_index, hold_file ); 3072 Free_job(&job); 3073 Get_hold_file( &job, hold_file ); 3074 Setup_cf_info( &job, 0 ); 3075 Remove_job( &job ); 3076 removed = 1; 3077 } 3078 Free_job(&job); 3079 Free_line_list(&info); 3080 if( removed && Lpq_status_file_DYN ){ 3081 unlink(Lpq_status_file_DYN); 3082 } 3083 return( removed ); 3084} 3085#endif 3086