Changeset 1291
- Timestamp:
- 01/14/04 16:52:01 (21 years ago)
- Location:
- pykota/trunk
- Files:
-
- 3 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/bin/cupspykota
r1289 r1291 24 24 # 25 25 # $Log$ 26 # Revision 1.24 2004/01/14 15:52:01 jalet 27 # Small fix for job cancelling code. 28 # 26 29 # Revision 1.23 2004/01/13 10:48:28 jalet 27 30 # Small streams polling loop modification. … … 114 117 import select 115 118 import signal 119 import time 116 120 117 121 from pykota.tool import PyKotaFilterOrBackend, PyKotaToolError … … 120 124 from pykota.accounter import PyKotaAccounterError 121 125 from pykota.requester import PyKotaRequesterError 122 123 gotSigTerm = 0124 def sigterm_handler(signum, frame) :125 """Sets a global variable whenever SIGTERM is received."""126 # SIGTERM will be ignore most of the time, but during127 # the call to the real backend, we have to pass it through.128 global gotSigTerm129 gotSigTerm = 1130 126 131 127 class PyKotaPopen3(popen2.Popen3) : … … 152 148 class PyKotaBackend(PyKotaFilterOrBackend) : 153 149 """A class for the pykota backend.""" 150 def __init__(self) : 151 """Does normal initialization then installs signal handler.""" 152 # Normal init 153 PyKotaFilterOrBackend.__init__(self) 154 155 # then deal with signals 156 # CUPS backends ignore SIGPIPE and exit(1) on SIGTERM 157 # Fortunately SIGPIPE is already ignored by Python 158 # It's there just in case this changes in the future. 159 # Here we have to handle SIGTERM correctly, and pass 160 # it to the original backend if needed. 161 self.gotSigTerm = 0 162 signal.signal(signal.SIGPIPE, signal.SIG_IGN) 163 signal.signal(signal.SIGTERM, self.sigterm_handler) 164 165 def sigterm_handler(self, signum, frame) : 166 """Sets a global variable whenever SIGTERM is received.""" 167 # SIGTERM will be ignore most of the time, but during 168 # the call to the real backend, we have to pass it through. 169 self.gotSigTerm = 1 170 self.logger.log_message(_("SIGTERM received, job %s cancelled.") % self.jobid, "info") 171 154 172 def acceptJob(self) : 155 173 """Returns the appropriate exit code to tell CUPS all is OK.""" … … 165 183 def doWork(self, policy, printer, user, userpquota) : 166 184 """Most of the work is done here.""" 167 global gotSigTerm168 185 # Two different values possible for policy here : 169 186 # ALLOW means : Either printer, user or user print quota doesn't exist, … … 181 198 # pass the job's data to the real backend 182 199 if action in ["ALLOW", "WARN"] : 183 if gotSigTerm :200 if self.gotSigTerm : 184 201 retcode = self.removeJob() 185 202 else : … … 211 228 # Now it becomes tricky... 212 229 # We must pass the unmodified job to the original backend 213 214 global gotSigTerm215 216 230 # First ensure that we have a file object as input 217 231 mustclose = 0 … … 256 270 endinput = endoutput = enderr = 0 257 271 inputclosed = outclosed = errclosed = 0 272 killed = 0 258 273 self.logdebug("Entering streams polling loop...") 259 274 status = -1 … … 264 279 # Now if we got SIGTERM, we have 265 280 # to kill -TERM the original backend 266 if gotSigTerm:281 if self.gotSigTerm and not killed : 267 282 try : 268 283 os.kill(subprocess.pid, signal.SIGTERM) 284 self.logger.log_message(_("SIGTERM was sent to real backend %s (pid: %s)") % (realbackend, subprocess.pid), "info") 285 killed = 1 269 286 except : # ignore if process was already killed. 270 287 pass … … 272 289 # In any case, deal with any remaining I/O 273 290 availablefds = pollster.poll(5000) 274 if (not availablefds) and inputclosed and outputclosed and errclosed :275 break276 291 for (fd, mask) in availablefds : 277 292 # self.logdebug("file: %i mask: %04x" % (fd, mask)) … … 284 299 if endinput : 285 300 pollster.unregister(tocfno) 301 self.logdebug("Closing real backend's stdin.") 286 302 os.close(tocfno) 287 self.logdebug("Closing real backend's stdin.")288 303 inputclosed = 1 289 304 elif fd == stdoutfno : … … 331 346 # standard output. 332 347 # We are no more interested in this file descriptor 348 self.logdebug("Closing real backend's stdout.") 333 349 os.close(fromcfno) 334 self.logdebug("Real backend's stdout ends.")335 350 endoutput = 1 336 351 elif fd == cerrfno : … … 338 353 # to write informations on its standard error. 339 354 # We are no more interested in this file descriptor . 355 self.logdebug("Closing real backend's stderr.") 340 356 os.close(cerrfno) 341 self.logdebug("Real backend's stderr ends.")342 357 enderr = 1 358 if killed or (inputclosed and outputclosed and errclosed) : 359 break 343 360 361 # We must close the real backend's input stream 362 if killed and not inputclosed : 363 self.logdebug("Forcing close of real backend's stdin.") 364 os.close(tocfno) 365 344 366 # Input file was a real file, we have to close it. 345 367 if mustclose : … … 351 373 if os.WIFEXITED(status) : 352 374 retcode = os.WEXITSTATUS(status) 353 el se:375 elif not killed : 354 376 self.logger.log_message(_("CUPS backend %s died abnormally.") % realbackend, "error") 355 377 retcode = -1 378 else : 379 retcode = self.removeJob() 356 380 return retcode 357 381 358 382 if __name__ == "__main__" : 359 383 # This is a CUPS backend, we should act and die like a CUPS backend 360 361 # first deal with signals362 # CUPS backends ignore SIGPIPE and exit(1) on SIGTERM363 # Fortunately SIGPIPE is already ignored by Python364 # It's there just in case this changes in the future.365 # Here we have to handle SIGTERM correctly, and pass366 # it to the original backend if needed.367 global gotSigTerm368 gotSigTerm = 0369 signal.signal(signal.SIGPIPE, signal.SIG_IGN)370 signal.signal(signal.SIGTERM, sigterm_handler)371 372 384 if len(sys.argv) == 1 : 373 385 # we will execute each existing backend in device enumeration mode -
pykota/trunk/NEWS
r1287 r1291 22 22 PyKota NEWS : 23 23 24 - 1.16beta2 : 25 26 - Small fix for job cancelling code while job already 27 printing in CUPS backend. 28 24 29 - 1.16beta1 : 25 30 -
pykota/trunk/pykota/version.py
r1287 r1291 22 22 # 23 23 24 __version__ = "1.16beta 1_unofficial"24 __version__ = "1.16beta2_unofficial" 25 25 26 26 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng."""