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_logger.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $"; 28 29 30#include "lp.h" 31#include "child.h" 32#include "errorcodes.h" 33#include "fileopen.h" 34#include "getopt.h" 35#include "getprinter.h" 36#include "getqueue.h" 37#include "linksupport.h" 38#include "proctitle.h" 39 40#include "lpd_logger.h" 41 42/*************************************************************************** 43 * Setup_logger() 44 * 45 * We will have a process that sits and listens for log data, and then 46 * forwards it to the destination. This process will have some odd properities. 47 * 48 * 1. It will never update its destination. This means you will have to 49 * kill the logger to get it to accept a new destination. 50 ***************************************************************************/ 51 52 53 54/* 55 * Start_logger - helper function to setup logger process 56 */ 57 58int Start_logger( int log_fd ) 59{ 60 struct line_list args, passfd; 61 int fd = Logger_fd; 62 int pid; 63 64 Init_line_list(&passfd); 65 Init_line_list(&args); 66 67 Logger_fd = -1; 68 Setup_lpd_call( &passfd, &args ); 69 Logger_fd = fd; 70 71 Set_str_value(&args,CALL,"logger"); 72 73 Check_max(&passfd,2); 74 Set_decimal_value(&args,INPUT,passfd.count); 75 passfd.list[passfd.count++] = Cast_int_to_voidstar(log_fd); 76 77 pid = Make_lpd_call( "logger", &passfd, &args ); 78 passfd.count = 0; 79 Free_line_list( &args ); 80 Free_line_list( &passfd ); 81 DEBUG1("Start_logger: log_fd %d, status_pid %d", log_fd, pid ); 82 return(pid); 83} 84 85int Dump_queue_status(int outfd) 86{ 87 int i, count, fd; 88 char *s, *sp, *pr; 89 struct line_list info; 90 struct job job; 91 char buffer[SMALLBUFFER]; 92 /* char *esc_lf_2 = Escape("\n", 2); */ 93 /* char *esc_lf_2 = "%25250a"; */ 94 char *esc_lf_1 = "%250a"; 95 struct stat statb; 96 97 s = sp = 0; 98 Init_job(&job); 99 Init_line_list(&info); 100 if(All_line_list.count == 0 ){ 101 Get_all_printcap_entries(); 102 } 103 DEBUGF(DLOG2)("Dump_queue_status: writing to fd %d", outfd ); 104 for( i = 0; i < All_line_list.count; ++i ){ 105 Set_DYN(&Printer_DYN,0); 106 pr = All_line_list.list[i]; 107 DEBUGF(DLOG2)("Dump_queue_status: checking '%s'", pr ); 108 if( Setup_printer( pr, buffer, sizeof(buffer), 0 ) ) continue; 109 Free_line_list( &Sort_order ); 110 if( Scan_queue( &Spool_control, &Sort_order, 0,0,0,0,0,0,0,0 ) ){ 111 continue; 112 } 113 Free_line_list(&info); 114 Set_str_value(&info,PRINTER,Printer_DYN); 115 Set_str_value(&info,HOST,FQDNHost_FQDN); 116 Set_decimal_value(&info,PROCESS,getpid()); 117 Set_str_value(&info,UPDATE_TIME,Time_str(0,0)); 118 119 if( Write_fd_str( outfd, "DUMP=" ) < 0 ){ return(1); } 120 s = Join_line_list(&info,"\n"); 121 sp = Escape(s, 1); 122 if( Write_fd_str( outfd, sp ) < 0 ){ return(1); } 123 124 if( s ) free(s); s = 0; 125 if( sp ) free(sp); sp = 0; 126 127 if( Write_fd_str( outfd, "VALUE=" ) < 0 ){ return(1); } 128 129 if( Write_fd_str( outfd, "QUEUE%3d" ) < 0 ){ return(1); } 130 if( (fd = Checkread( Queue_control_file_DYN, &statb )) > 0 ){ 131 while( (count = read(fd, buffer, sizeof(buffer)-1)) > 0 ){ 132 buffer[count] = 0; 133 s = Escape(buffer,3); 134 if( Write_fd_str( outfd, s ) < 0 ){ return(1); } 135 if(s) free(s); s = 0; 136 } 137 close(fd); 138 } 139 if( Write_fd_str( outfd, esc_lf_1 ) < 0 ){ return(1); } 140 141 if( Write_fd_str( outfd, "PRSTATUS%3d" ) < 0 ){ return(1); } 142 if( (fd = Checkread( Queue_status_file_DYN, &statb )) > 0 ){ 143 while( (count = read(fd, buffer, sizeof(buffer)-1)) > 0 ){ 144 buffer[count] = 0; 145 s = Escape(buffer,3); 146 if( Write_fd_str( outfd, s ) < 0 ){ return(1); } 147 if(s) free(s); s = 0; 148 } 149 close(fd); 150 } 151 if( Write_fd_str( outfd, esc_lf_1 ) < 0 ){ return(1); } 152 153 for( count = 0; count < Sort_order.count; ++count ){ 154 Free_job(&job); 155 Get_hold_file( &job, Sort_order.list[count] ); 156 157 if( job.info.count == 0 ) continue; 158 if( Write_fd_str( outfd, "UPDATE%3d" ) < 0 ){ return(1); } 159 s = Join_line_list(&job.info,"\n"); 160 sp = Escape(s, 3); 161 if( Write_fd_str( outfd, sp ) < 0 ){ return(1); } 162 if( s ) free(s); s = 0; 163 if( sp ) free(sp); sp = 0; 164 if( Write_fd_str( outfd, esc_lf_1 ) < 0 ){ return(1); } 165 } 166 if( Write_fd_str( outfd, "\n" ) < 0 ){ return(1); } 167 } 168 169 if( Write_fd_str( outfd, "END\n" ) < 0 ){ return(1); } 170 Set_DYN(&Printer_DYN,0); 171 172 Free_line_list( &Sort_order ); 173 Free_line_list(&info); 174 Free_job(&job); 175 if( s ) free(s); s = 0; 176 if( sp ) free(sp); sp = 0; 177 return(0); 178} 179 180void Logger( struct line_list *args ) 181{ 182 char *s, *path, *tempfile; 183 int writefd,m, timeout, readfd; 184 time_t start_time, current_time; 185 int elapsed, left, err; 186 struct timeval timeval, *tp; 187 fd_set readfds, writefds; /* for select() */ 188 char inbuffer[LARGEBUFFER]; 189 char outbuffer[LARGEBUFFER]; 190 int outlen = 0, input_read = 0; 191 char host[SMALLBUFFER]; 192 int status_fd = -1; 193 int input_fd = -1; 194 struct stat statb; 195 196 Errorcode = JABORT; 197 198 199 Name = "LOG2"; 200 setproctitle( "lpd %s", Name ); 201 202 DEBUGFC(DLOG2)Dump_line_list("Logger - args", args ); 203 204 timeout = Logger_timeout_DYN; 205 path = Logger_path_DYN; 206 207 /* we copy to a local buffer */ 208 host[0] = 0; 209 safestrncpy(host, Logger_destination_DYN ); 210 /* OK, we try to open a connection to the logger */ 211 if( !(s = safestrchr( host, '%')) ){ 212 int len = strlen(host); 213 SNPRINTF(host+len, sizeof(host)-len) "%2001" ); 214 } 215 216 readfd = Find_flag_value(args,INPUT,Value_sep); 217 Free_line_list(args); 218 219 writefd = -2; 220 /* now we set up the IO file */ 221 Set_nonblock_io(readfd); 222 223 DEBUGF(DLOG2)("Logger: host '%s'", host ); 224 225 time( &start_time ); 226 status_fd = Make_temp_fd( &tempfile ); 227 input_fd = Checkread( tempfile, &statb ); 228 unlink(tempfile); 229 230 while( 1 ){ 231 tp = 0; 232 left = 0; 233 /* try to see if more output is left */ 234 if( outlen == 0 && input_read ){ 235 if( (m = read( input_fd, inbuffer, sizeof(inbuffer)-1 )) > 0 ){ 236 inbuffer[m] = 0; 237 memcpy( outbuffer, inbuffer, m+1 ); 238 outlen = m; 239 DEBUGF(DLOG2)("Logger: queue status '%s'", outbuffer ); 240 } else if( m < 0 ){ 241 Errorcode = JABORT; 242 LOGERR_DIE(LOG_INFO)"Logger: read error %s", tempfile); 243 } 244 if( m < (int)sizeof(inbuffer)-1 ){ 245 /* we can truncate the files */ 246 if( lseek( status_fd, 0, SEEK_SET) == -1 ){ 247 Errorcode = JABORT; 248 LOGERR_DIE(LOG_INFO) "Logger: lseek failed write file '%s'", tempfile); 249 } 250 if( lseek( input_fd, 0, SEEK_SET) == -1 ){ 251 Errorcode = JABORT; 252 LOGERR_DIE(LOG_INFO) "Logger: lseek failed read file '%s'", tempfile); 253 } 254 if( ftruncate( status_fd, 0 ) ){ 255 Errorcode = JABORT; 256 LOGERR_DIE(LOG_INFO) "Logger: ftruncate failed file '%s'", tempfile); 257 } 258 input_read = 0; 259 } 260 } 261 /* now lets see if the input has been closed 262 * do not exit until you have sent last buffer information 263 */ 264 if( readfd < 0 && outlen == 0 ){ 265 DEBUGF(DLOG2)("Logger: exiting - no work to do"); 266 Errorcode = 0; 267 break; 268 } 269 /* the destination is not on line yet 270 * try to reopen 271 */ 272 if( writefd < 0 ){ 273 time( ¤t_time ); 274 elapsed = current_time - start_time; 275 left = timeout - elapsed; 276 DEBUGF(DLOG2)("Logger: writefd fd %d, max timeout %d, left %d", 277 writefd, timeout, left ); 278 if( left <= 0 || writefd == -2 ){ 279 writefd = Link_open(host, Connect_timeout_DYN, 0, 0 ); 280 DEBUGF(DLOG2)("Logger: open fd %d", writefd ); 281 if( writefd >= 0 ){ 282 Set_nonblock_io( writefd ); 283 if( lseek( status_fd, 0, SEEK_SET) == -1 ){ 284 Errorcode = JABORT; 285 LOGERR_DIE(LOG_INFO) "Logger: lseek failed write file '%s'", tempfile); 286 } 287 if( lseek( input_fd, 0, SEEK_SET) == -1 ){ 288 Errorcode = JABORT; 289 LOGERR_DIE(LOG_INFO) "Logger: lseek failed read file '%s'", tempfile); 290 } 291 if( ftruncate( status_fd, 0 ) ){ 292 Errorcode = JABORT; 293 LOGERR_DIE(LOG_INFO) "Logger: ftruncate failed file '%s'", tempfile); 294 } 295 if( Dump_queue_status(status_fd) ){ 296 DEBUGF(DLOG2)("Logger: Dump_queue_status failed - %s", Errormsg(errno) ); 297 Errorcode = JABORT; 298 LOGERR_DIE(LOG_INFO) "Logger: cannot write file '%s'", tempfile); 299 } 300 input_read = 1; 301 /* we try again */ 302 continue; 303 } else { 304 writefd = -1; 305 } 306 time( &start_time ); 307 time( ¤t_time ); 308 DEBUGF(DLOG2)("Logger: writefd now fd %d", writefd ); 309 } 310 if( writefd < 0 && timeout > 0 ){ 311 memset( &timeval, 0, sizeof(timeval) ); 312 elapsed = current_time - start_time; 313 left = timeout - elapsed; 314 timeval.tv_sec = left; 315 tp = &timeval; 316 DEBUGF(DLOG2)("Logger: timeout now %d", left ); 317 } 318 } 319 FD_ZERO( &writefds ); 320 FD_ZERO( &readfds ); 321 m = 0; 322 if( writefd >= 0 ){ 323 if( outlen ){ 324 FD_SET( writefd, &writefds ); 325 if( m <= writefd ) m = writefd+1; 326 } 327 FD_SET( writefd, &readfds ); 328 if( m <= writefd ) m = writefd+1; 329 } 330 if( readfd >= 0 ){ 331 FD_SET( readfd, &readfds ); 332 if( m <= readfd ) m = readfd+1; 333 } 334 errno = 0; 335 DEBUGF(DLOG2)("Logger: starting select, timeout '%s', left %d", 336 tp?"yes":"no", left ); 337 m = select( m, 338 FD_SET_FIX((fd_set *))&readfds, 339 FD_SET_FIX((fd_set *))&writefds, 340 FD_SET_FIX((fd_set *))0, tp ); 341 err = errno; 342 DEBUGF(DLOG2)("Logger: select returned %d, errno '%s'", 343 m, Errormsg(err) ); 344 if( m < 0 ){ 345 if( err != EINTR ){ 346 Errorcode = JABORT; 347 LOGERR_DIE(LOG_INFO)"Logger: select error"); 348 } 349 } else if( m > 0 ){ 350 if( writefd >=0 && FD_ISSET( writefd, &readfds ) ){ 351 /* we have EOF on the file descriptor */ 352 DEBUGF(DLOG2)("Logger: eof on writefd fd %d", writefd ); 353 close( writefd ); 354 outlen = 0; 355 writefd = -2; 356 } 357 if( readfd >=0 && FD_ISSET( readfd, &readfds ) ){ 358 DEBUGF(DLOG2)("Logger: read possible on fd %d", readfd ); 359 inbuffer[0] = 0; 360 m = read( readfd, inbuffer, sizeof(inbuffer)-1 ); 361 if( m >= 0) inbuffer[m] = 0; 362 DEBUGF(DLOG2)("Logger: read count %d '%s'", m, inbuffer ); 363 if( m > 0 && writefd >= 0 ){ 364 if( Write_fd_len( status_fd, inbuffer, m ) ){ 365 LOGERR_DIE(LOG_INFO)"Logger: write error on tempfile fd %d", status_fd); 366 } 367 input_read = 1; 368 } else if( m == 0 ) { 369 /* we have a 0 length read - this is EOF */ 370 Errorcode = 0; 371 DEBUGF(DLOG1)("Logger: eof on input fd %d", readfd); 372 close(readfd); 373 readfd = -1; 374 } else if( m < 0 ){ 375 Errorcode = JABORT; 376 LOGERR_DIE(LOG_INFO)"Logger: read error on input fd %d", readfd); 377 } 378 } 379 if( writefd >=0 && FD_ISSET( writefd, &writefds ) && outlen ){ 380 DEBUGF(DLOG2)("Logger: write possible on fd %d, outlen %d", 381 writefd, outlen ); 382 m = write( writefd, outbuffer, outlen); 383 DEBUGF(DLOG2)("Logger: last write %d", m ); 384 if( m < 0 ){ 385 /* we have EOF on the file descriptor */ 386 LOGERR(LOG_INFO) "Logger: error writing on writefd fd %d", writefd ); 387 close( writefd ); 388 writefd = -2; 389 } else if( m > 0 ){ 390 memmove(outbuffer, outbuffer+m, outlen-m+1 ); 391 outlen -= m; 392 } 393 } 394 } 395 } 396 cleanup(0); 397} 398