Show
Ignore:
Timestamp:
11/26/03 21:43:29 (20 years ago)
Author:
jalet
Message:

Inadvertantly introduced a bug, which is fixed.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r1221 r1222  
    2424# 
    2525# $Log$ 
     26# Revision 1.16  2003/11/26 20:43:29  jalet 
     27# Inadvertantly introduced a bug, which is fixed. 
     28# 
    2629# Revision 1.15  2003/11/26 19:17:35  jalet 
    2730# Printing on a printer not present in the Quota Storage now results 
     
    192195            return 0 
    193196         
    194         if action not in ["ALLOW", "WARN"] :     
    195             # if not allowed to print then die, else proceed. 
    196             # we die without error, so that the job doesn't  
    197             # stop the print queue. 
    198             retcode = 0 
    199         else : 
    200             # pass the job untouched to the underlying layer 
    201             # and starts accounting at the same time 
    202             thebackend.accounter.beginJob(printer, user) 
     197    if action not in ["ALLOW", "WARN"] :     
     198        # if not allowed to print then die, else proceed. 
     199        # we die without error, so that the job doesn't  
     200        # stop the print queue. 
     201        retcode = 0 
     202    else : 
     203        # pass the job untouched to the underlying layer 
     204        # and starts accounting at the same time 
     205        thebackend.accounter.beginJob(printer, user) 
     206         
     207        # Now it becomes tricky... 
     208         
     209        # First ensure that we have a file object as input 
     210        mustclose = 0     
     211        if thebackend.inputfile is not None :     
     212            if hasattr(thebackend.inputfile, "read") : 
     213                infile = thebackend.inputfile 
     214            else :     
     215                infile = open(thebackend.inputfile, "rb") 
     216            mustclose = 1 
     217        else :     
     218            infile = sys.stdin 
    203219             
    204             # Now it becomes tricky... 
     220        # Find the real backend pathname     
     221        realbackend = os.path.join(os.path.split(sys.argv[0])[0], thebackend.originalbackend) 
     222         
     223        # And launch it 
     224        subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, bufsize=0, arg0=os.environ["DEVICE_URI"]) 
     225         
     226        # Save file descriptors, we will need them later. 
     227        infno = infile.fileno() 
     228        stdoutfno = sys.stdout.fileno() 
     229        stderrfno = sys.stderr.fileno() 
     230        fromcfno = subprocess.fromchild.fileno() 
     231        tocfno = subprocess.tochild.fileno() 
     232        cerrfno = subprocess.childerr.fileno() 
     233         
     234        # We will have to be careful when dealing with I/O  
     235        # So we use a poll object to know when to read or write 
     236        pollster = select.poll() 
     237        pollster.register(infno, select.POLLIN | select.POLLPRI) 
     238        pollster.register(fromcfno, select.POLLIN | select.POLLPRI) 
     239        pollster.register(cerrfno, select.POLLIN | select.POLLPRI) 
     240        pollster.register(stdoutfno, select.POLLOUT) 
     241        pollster.register(stderrfno, select.POLLOUT) 
     242        pollster.register(tocfno, select.POLLOUT) 
     243         
     244        # Initialize our buffers 
     245        indata = "" 
     246        outdata = "" 
     247        errdata = "" 
     248        endinput = 0 
     249        status = -1 
     250        while status == -1 : 
     251            # First check if original backend is still alive 
     252            status = subprocess.poll() 
    205253             
    206             # First ensure that we have a file object as input 
    207             mustclose = 0     
    208             if thebackend.inputfile is not None :     
    209                 if hasattr(thebackend.inputfile, "read") : 
    210                     infile = thebackend.inputfile 
     254            # Now if we got SIGTERM, we have  
     255            # to kill -TERM the original backend 
     256            if gotSigTerm : 
     257                try : 
     258                    os.kill(subprocess.pid, signal.SIGTERM) 
     259                except : # ignore if process was already killed. 
     260                    pass 
     261             
     262            # In any case, deal with any remaining I/O 
     263            availablefds = pollster.poll() 
     264            for (fd, mask) in availablefds : 
     265                if mask & select.POLLOUT : 
     266                    # We can write 
     267                    if fd == tocfno : 
     268                        if indata : 
     269                            os.write(fd, indata)     
     270                            indata = "" 
     271                    elif fd == stdoutfno : 
     272                        if outdata : 
     273                            os.write(fd, outdata) 
     274                            outdata = "" 
     275                    elif fd == stderrfno : 
     276                        if errdata : 
     277                            os.write(fd, errdata) 
     278                            errdata = "" 
     279                if (mask & select.POLLIN) or (mask & select.POLLPRI) :      
     280                    # We have something to read 
     281                    data = os.read(fd, 256 * 1024) 
     282                    if fd == infno : 
     283                        indata += data 
     284                        if not data :    # If yes, then no more input data 
     285                            endinput = 1 # this happens with real files. 
     286                    elif fd == fromcfno : 
     287                        outdata += data 
     288                    elif fd == cerrfno :     
     289                        errdata += data 
     290                if (mask & select.POLLHUP) or (mask & select.POLLERR) : 
     291                    # I've never seen POLLERR myself, but this probably 
     292                    # can't hurt to treat an error condition just like  
     293                    # an EOF. 
     294                    #  
     295                    # Some standard I/O stream has no more datas 
     296                    if fd == infno : 
     297                        # Here we are in the case where the input file is stdin. 
     298                        # which has no more data to be read. 
     299                        endinput = 1 
     300                    elif fd == fromcfno :     
     301                        # This should never happen, since 
     302                        # CUPS backends don't send anything on their 
     303                        # standard output 
     304                        if outdata :                 
     305                            try : 
     306                                os.write(stdoutfno, outdata) 
     307                                outdata = "" 
     308                            except :     
     309                                pass 
     310                        try :         
     311                            pollster.unregister(fromcfno)         
     312                        except KeyError :     
     313                            pass 
     314                        else :     
     315                            os.close(fromcfno) 
     316                    elif fd == cerrfno :     
     317                        # Original CUPS backend has finished  
     318                        # to write informations on its standard error 
     319                        if errdata :                 
     320                            # Try to write remaining info (normally "Ready to print.") 
     321                            try : 
     322                                os.write(stderrfno, errdata) 
     323                                errdata = "" 
     324                            except :     
     325                                pass 
     326                        # We are no more interested in this file descriptor         
     327                        try :         
     328                            pollster.unregister(cerrfno)         
     329                        except KeyError :     
     330                            pass 
     331                        else :     
     332                            os.close(cerrfno) 
     333                         
     334            if endinput :             
     335                # We deal with remaining input datas here 
     336                # because EOF can happen in two different 
     337                # situations and I don't want to duplicate 
     338                # code, nor making functions. 
     339                if indata :                 
     340                    try : 
     341                        os.write(tocfno, indata) 
     342                        indata = "" 
     343                    except :     
     344                        pass 
     345                # Again, we're not interested in this file descriptor         
     346                # anymore. 
     347                try :         
     348                    pollster.unregister(tocfno)         
     349                except KeyError :     
     350                    pass 
    211351                else :     
    212                     infile = open(thebackend.inputfile, "rb") 
    213                 mustclose = 1 
    214             else :     
    215                 infile = sys.stdin 
     352                    os.close(tocfno) 
    216353                 
    217             # Find the real backend pathname     
    218             realbackend = os.path.join(os.path.split(sys.argv[0])[0], thebackend.originalbackend) 
     354        # Input file was a real file, we have to close it.     
     355        if mustclose : 
     356            infile.close() 
    219357             
    220             # And launch it 
    221             subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, bufsize=0, arg0=os.environ["DEVICE_URI"]) 
    222              
    223             # Save file descriptors, we will need them later. 
    224             infno = infile.fileno() 
    225             stdoutfno = sys.stdout.fileno() 
    226             stderrfno = sys.stderr.fileno() 
    227             fromcfno = subprocess.fromchild.fileno() 
    228             tocfno = subprocess.tochild.fileno() 
    229             cerrfno = subprocess.childerr.fileno() 
    230              
    231             # We will have to be careful when dealing with I/O  
    232             # So we use a poll object to know when to read or write 
    233             pollster = select.poll() 
    234             pollster.register(infno, select.POLLIN | select.POLLPRI) 
    235             pollster.register(fromcfno, select.POLLIN | select.POLLPRI) 
    236             pollster.register(cerrfno, select.POLLIN | select.POLLPRI) 
    237             pollster.register(stdoutfno, select.POLLOUT) 
    238             pollster.register(stderrfno, select.POLLOUT) 
    239             pollster.register(tocfno, select.POLLOUT) 
    240              
    241             # Initialize our buffers 
    242             indata = "" 
    243             outdata = "" 
    244             errdata = "" 
    245             endinput = 0 
    246             status = -1 
    247             while status == -1 : 
    248                 # First check if original backend is still alive 
    249                 status = subprocess.poll() 
    250                  
    251                 # Now if we got SIGTERM, we have  
    252                 # to kill -TERM the original backend 
    253                 if gotSigTerm : 
    254                     try : 
    255                         os.kill(subprocess.pid, signal.SIGTERM) 
    256                     except : # ignore if process was already killed. 
    257                         pass 
    258                  
    259                 # In any case, deal with any remaining I/O 
    260                 availablefds = pollster.poll() 
    261                 for (fd, mask) in availablefds : 
    262                     if mask & select.POLLOUT : 
    263                         # We can write 
    264                         if fd == tocfno : 
    265                             if indata : 
    266                                 os.write(fd, indata)     
    267                                 indata = "" 
    268                         elif fd == stdoutfno : 
    269                             if outdata : 
    270                                 os.write(fd, outdata) 
    271                                 outdata = "" 
    272                         elif fd == stderrfno : 
    273                             if errdata : 
    274                                 os.write(fd, errdata) 
    275                                 errdata = "" 
    276                     if (mask & select.POLLIN) or (mask & select.POLLPRI) :      
    277                         # We have something to read 
    278                         data = os.read(fd, 256 * 1024) 
    279                         if fd == infno : 
    280                             indata += data 
    281                             if not data :    # If yes, then no more input data 
    282                                 endinput = 1 # this happens with real files. 
    283                         elif fd == fromcfno : 
    284                             outdata += data 
    285                         elif fd == cerrfno :     
    286                             errdata += data 
    287                     if (mask & select.POLLHUP) or (mask & select.POLLERR) : 
    288                         # I've never seen POLLERR myself, but this probably 
    289                         # can't hurt to treat an error condition just like  
    290                         # an EOF. 
    291                         #  
    292                         # Some standard I/O stream has no more datas 
    293                         if fd == infno : 
    294                             # Here we are in the case where the input file is stdin. 
    295                             # which has no more data to be read. 
    296                             endinput = 1 
    297                         elif fd == fromcfno :     
    298                             # This should never happen, since 
    299                             # CUPS backends don't send anything on their 
    300                             # standard output 
    301                             if outdata :                 
    302                                 try : 
    303                                     os.write(stdoutfno, outdata) 
    304                                     outdata = "" 
    305                                 except :     
    306                                     pass 
    307                             try :         
    308                                 pollster.unregister(fromcfno)         
    309                             except KeyError :     
    310                                 pass 
    311                             else :     
    312                                 os.close(fromcfno) 
    313                         elif fd == cerrfno :     
    314                             # Original CUPS backend has finished  
    315                             # to write informations on its standard error 
    316                             if errdata :                 
    317                                 # Try to write remaining info (normally "Ready to print.") 
    318                                 try : 
    319                                     os.write(stderrfno, errdata) 
    320                                     errdata = "" 
    321                                 except :     
    322                                     pass 
    323                             # We are no more interested in this file descriptor         
    324                             try :         
    325                                 pollster.unregister(cerrfno)         
    326                             except KeyError :     
    327                                 pass 
    328                             else :     
    329                                 os.close(cerrfno) 
    330                              
    331                 if endinput :             
    332                     # We deal with remaining input datas here 
    333                     # because EOF can happen in two different 
    334                     # situations and I don't want to duplicate 
    335                     # code, nor making functions. 
    336                     if indata :                 
    337                         try : 
    338                             os.write(tocfno, indata) 
    339                             indata = "" 
    340                         except :     
    341                             pass 
    342                     # Again, we're not interested in this file descriptor         
    343                     # anymore. 
    344                     try :         
    345                         pollster.unregister(tocfno)         
    346                     except KeyError :     
    347                         pass 
    348                     else :     
    349                         os.close(tocfno) 
    350                      
    351             # Input file was a real file, we have to close it.     
    352             if mustclose : 
    353                 infile.close() 
    354                  
    355             # Check exit code of original CUPS backend.     
    356             if os.WIFEXITED(status) : 
    357                 retcode = os.WEXITSTATUS(status) 
    358             else :     
    359                 thebackend.logger.log_message(_("CUPS backend %s died abnormally.") % realbackend, "error") 
    360                 retcode = -1 
    361          
    362         # stops accounting.  
    363         thebackend.accounter.endJob(printer, user) 
    364              
    365         # retrieve the job size     
    366         jobsize = thebackend.accounter.getJobSize() 
    367          
    368         # update the quota for the current user on this printer  
    369         if printer.Exists : 
    370             jobprice = (float(printer.PricePerPage or 0.0) * jobsize) + float(printer.PricePerJob or 0.0) 
    371             if jobsize : 
    372                 userquota = thebackend.storage.getUserPQuota(user, printer) 
    373                 if userquota.Exists : 
    374                     userquota.increasePagesUsage(jobsize) 
    375              
    376             # adds the current job to history     
    377             printer.addJobToHistory(thebackend.jobid, user, thebackend.accounter.getLastPageCounter(), action, jobsize, jobprice, thebackend.preserveinputfile, thebackend.title, thebackend.copies, thebackend.options) 
    378          
    379         return retcode # return (retcode or gotSigTerm) shouldn't be needed 
     358        # Check exit code of original CUPS backend.     
     359        if os.WIFEXITED(status) : 
     360            retcode = os.WEXITSTATUS(status) 
     361        else :     
     362            thebackend.logger.log_message(_("CUPS backend %s died abnormally.") % realbackend, "error") 
     363            retcode = -1 
     364     
     365    # stops accounting.  
     366    thebackend.accounter.endJob(printer, user) 
     367         
     368    # retrieve the job size     
     369    jobsize = thebackend.accounter.getJobSize() 
     370     
     371    # update the quota for the current user on this printer  
     372    jobprice = (float(printer.PricePerPage or 0.0) * jobsize) + float(printer.PricePerJob or 0.0) 
     373    if jobsize : 
     374        userquota = thebackend.storage.getUserPQuota(user, printer) 
     375        if userquota.Exists : 
     376            userquota.increasePagesUsage(jobsize) 
     377     
     378    # adds the current job to history     
     379    printer.addJobToHistory(thebackend.jobid, user, thebackend.accounter.getLastPageCounter(), action, jobsize, jobprice, thebackend.preserveinputfile, thebackend.title, thebackend.copies, thebackend.options) 
     380     
     381    return retcode # return (retcode or gotSigTerm) shouldn't be needed 
    380382 
    381383if __name__ == "__main__" :