Changeset 1185

Show
Ignore:
Timestamp:
11/14/03 23:05:12 (20 years ago)
Author:
jalet
Message:

New CUPS backend fully functionnal.
Old CUPS configuration method is now officially deprecated.

Location:
pykota/trunk
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/cupspykota

    r1184 r1185  
    2424# 
    2525# $Log$ 
     26# Revision 1.7  2003/11/14 22:05:12  jalet 
     27# New CUPS backend fully functionnal. 
     28# Old CUPS configuration method is now officially deprecated. 
     29# 
    2630# Revision 1.6  2003/11/14 20:13:11  jalet 
    2731# We exit the loop too soon. 
     
    147151    return "%s >/dev/null" % (cmdline % locals()) 
    148152 
    149 def sigterm_handler(signum, frame) : 
    150     """Handler for SIGTERM.""" 
    151     sys.stderr.write("INFO: PyKota backend aborted.") 
    152     sys.exit(1) 
    153      
    154153def main(thebackend) :     
    155154    """Do it, and do it right !""" 
     
    157156    # CUPS backends ignore SIGPIPE and exit(1) on SIGTERM 
    158157    # Fortunately SIGPIPE is already ignored by Python 
    159     # It's there just in case this changes in the future 
     158    # It's there just in case this changes in the future. 
     159    # But here we will IGNORE SIGTERM for now, and see 
     160    # if we shouldn't pass it to the original backend 
     161    # instead. 
    160162    signal.signal(signal.SIGPIPE, signal.SIG_IGN) 
    161     signal.signal(signal.SIGTERM, sigterm_handler) 
     163    signal.signal(signal.SIGTERM, signal.SIG_IGN) 
    162164     
    163165    # 
     
    226228        thebackend.accounter.beginJob(printer, user) 
    227229         
    228         # executes original backend 
     230        # Now it becomes tricky... 
     231         
     232        # First ensure that we have a file object as input 
    229233        mustclose = 0     
    230234        if thebackend.inputfile is not None :     
     
    236240        else :     
    237241            infile = sys.stdin 
     242             
     243        # Find the real backend pathname     
    238244        realbackend = os.path.join(os.path.split(sys.argv[0])[0], thebackend.originalbackend) 
    239         subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, arg0=os.environ["DEVICE_URI"]) 
    240         pollster = select.poll() 
     245         
     246        # And launch it 
     247        subprocess = PyKotaPopen3([realbackend] + sys.argv[1:], capturestderr=1, bufsize=0, arg0=os.environ["DEVICE_URI"]) 
     248         
     249        # Save file descriptors, we will need them later. 
    241250        infno = infile.fileno() 
    242251        stdoutfno = sys.stdout.fileno() 
     
    245254        tocfno = subprocess.tochild.fileno() 
    246255        cerrfno = subprocess.childerr.fileno() 
     256         
     257        # We will have to be careful when dealing with I/O  
     258        # So we use a poll object to know when to read or write 
     259        pollster = select.poll() 
    247260        pollster.register(infno, select.POLLIN | select.POLLPRI) 
    248261        pollster.register(fromcfno, select.POLLIN | select.POLLPRI) 
     
    251264        pollster.register(stderrfno, select.POLLOUT) 
    252265        pollster.register(tocfno, select.POLLOUT) 
     266         
     267        # Initialize our buffers 
    253268        indata = "" 
    254269        outdata = "" 
    255270        errdata = "" 
    256         end = 0 
    257         while not end : 
    258             availablefds = pollster.poll(500) 
    259             if not availablefds : 
    260                 end = 1 
    261             else :     
    262                 for (fd, mask) in availablefds : 
    263                     thebackend.logdebug("Stream: %02i  Mask: %02x" % (fd, mask)) 
    264                     if mask & select.POLLHUP : 
    265                         if fd == infno : 
    266                             end = 1 # this happens with real stdin 
    267                     if mask & select.POLLOUT : 
    268                         if fd == tocfno : 
    269                             if indata : 
    270                                 os.write(fd, indata)     
    271                                 indata = "" 
    272                         elif fd == stdoutfno : 
    273                             if outdata : 
    274                                 os.write(fd, outdata) 
     271        endinput = 0 
     272        status = -1 
     273        while status == -1 : 
     274            # First check if original backend is still alive 
     275            status = subprocess.poll() 
     276             
     277            # In any case, deal with any remaining I/O 
     278            availablefds = pollster.poll() 
     279            for (fd, mask) in availablefds : 
     280                if mask & select.POLLOUT : 
     281                    # We can write 
     282                    if fd == tocfno : 
     283                        if indata : 
     284                            os.write(fd, indata)     
     285                            indata = "" 
     286                    elif fd == stdoutfno : 
     287                        if outdata : 
     288                            os.write(fd, outdata) 
     289                            outdata = "" 
     290                    elif fd == stderrfno : 
     291                        if errdata : 
     292                            os.write(fd, errdata) 
     293                            errdata = "" 
     294                if (mask & select.POLLIN) or (mask & select.POLLPRI) :      
     295                    # We have something to read 
     296                    data = os.read(fd, 256 * 1024) 
     297                    if fd == infno : 
     298                        indata += data 
     299                        if not data :    # If yes, then no more input data 
     300                            endinput = 1 # this happens with real files. 
     301                    elif fd == fromcfno : 
     302                        outdata += data 
     303                    elif fd == cerrfno :     
     304                        errdata += data 
     305                if mask & select.POLLHUP : 
     306                    # Some standard I/O stream has no more datas 
     307                    if fd == infno : 
     308                        # Here we are in the case where the input file is stdin. 
     309                        # which has no more data to be read. 
     310                        endinput = 1 
     311                    elif fd == fromcfno :     
     312                        # This should never happen, since 
     313                        # CUPS backends don't send anything on their 
     314                        # standard output 
     315                        if outdata :                 
     316                            try : 
     317                                os.write(stdoutfno, outdata) 
    275318                                outdata = "" 
    276                         elif fd == stderrfno : 
    277                             if errdata : 
    278                                 os.write(fd, errdata) 
     319                            except :     
     320                                pass 
     321                        try :         
     322                            pollster.unregister(fromcfno)         
     323                        except KeyError :     
     324                            pass 
     325                        else :     
     326                            os.close(fromcfno) 
     327                    elif fd == cerrfno :     
     328                        # Original CUPS backend has finished  
     329                        # to write informations on its standard error 
     330                        if errdata :                 
     331                            # Try to write remaining info (normally "Ready to print.") 
     332                            try : 
     333                                os.write(stderrfno, errdata) 
    279334                                errdata = "" 
    280                     if (mask & select.POLLIN) or (mask & select.POLLPRI) :      
    281                         data = os.read(fd, 256 * 1024) 
    282                         if fd == infno : 
    283                             indata += data 
    284                             if not data : 
    285                                 end = 1 # this happens with real files 
    286                         elif fd == fromcfno : 
    287                             outdata += data 
    288                         elif fd == cerrfno :     
    289                             errdata += data 
    290         if indata :                 
    291             try : 
    292                 os.write(tocfno, indata) 
    293             except :     
    294                 pass 
    295         sys.stdout.flush()                 
    296         sys.stderr.flush() 
    297         subprocess.fromchild.close() 
    298         subprocess.childerr.close() 
    299         subprocess.tochild.close() 
     335                            except :     
     336                                pass 
     337                        # We are no more interested in this file descriptor         
     338                        try :         
     339                            pollster.unregister(cerrfno)         
     340                        except KeyError :     
     341                            pass 
     342                        else :     
     343                            os.close(cerrfno) 
     344                         
     345            if endinput :             
     346                # We deal with remaining input datas here 
     347                # because EOF can happen in two different 
     348                # situations and I don't want to duplicate 
     349                # code, nor making functions. 
     350                if indata :                 
     351                    try : 
     352                        os.write(tocfno, indata) 
     353                        indata = "" 
     354                    except :     
     355                        pass 
     356                # Again, we're not interested in this file descriptor         
     357                # anymore. 
     358                try :         
     359                    pollster.unregister(tocfno)         
     360                except KeyError :     
     361                    pass 
     362                else :     
     363                    os.close(tocfno) 
     364             
     365        # Input file was a real file, we have to close it.     
    300366        if mustclose : 
    301367            infile.close() 
    302         status = subprocess.wait() 
     368             
     369        # Check exit code of original CUPS backend.     
    303370        if os.WIFEXITED(status) : 
    304371            retcode = os.WEXITSTATUS(status) 
  • pykota/trunk/NEWS

    r1179 r1185  
    2222PyKota NEWS : 
    2323 
     24    - 1.16alpha7 : 
     25     
     26        - The CUPS backend is now fully functionnal (it seems). 
     27         
     28        - From now on, the use of the pykota filter with CUPS  
     29          is deprecated. The pykota filter still has to be 
     30          used with LPRng though. 
     31         
    2432    - 1.16alpha6 : 
    2533     
  • pykota/trunk/pykota/version.py

    r1179 r1185  
    2222# 
    2323 
    24 __version__ = "1.16alpha6_unofficial" 
     24__version__ = "1.16alpha7_unofficial" 
    2525 
    2626__doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng.""" 
  • pykota/trunk/README

    r1181 r1185  
    280280printers, and change the administrator's email address. 
    281281 
    282   - CUPS Print Backend : 
    283    
    284     Modify the PPD files for each printer on which you want to manage 
    285     print quotas, for example /etc/cups/ppd/lp.ppd : 
    286      
    287     --- Add the line below exactly as-is somewhere near the top --- 
    288     *cupsFilter:  "application/vnd.cups-postscript 0 /usr/bin/pykota" 
    289     --- Add the line above exactly as-is somewhere near the top  --- 
    290      
    291     Modify the path to the pykota executable if needed, unfortunately  
    292     you have to supply the correct absolute path here due to CUPS  
    293     internals, or put the pykota executable into /usr/lib/cups/filter  
    294     instead of into /usr/bin.  
    295      
    296     Do this for each ppd file present in this directory if you want 
    297     to enable quota on every printer. 
    298                
    299     WARNING : In the case you've got a non-postscript printer, chances 
    300               are that the *cupsFilter is already filled-in and points 
    301               to cupsomatic or such a print filter. In this case please 
    302               check if you can switch your printer to PostScript mode 
    303               or if there's a way to make it accept PostScript jobs. 
    304               If yes then ensure that your workstations uses a PostScript 
    305               printer driver, and replace the *cupsFilter line with the 
    306               one pointing to the pykota filter. This should work, but 
    307               is currently untested. 
    308               If your printer really needs the original *cupsFilter line 
    309               then you may not be able to use PyKota easily for now. 
    310  
    311   - LPRng Print Backend : 
     282  - CUPS Printing System : 
     283   
     284    Once and for all : 
     285     
     286        Create a symbolic link to the cupspykota backend  
     287        in CUPS's backend directory : 
     288         
     289          $ cd /usr/lib/cups/backend 
     290          $ ln -s /usr/bin/cupspykota cupspykota 
     291           
     292        Restart CUPS so that the new backend can be detected. 
     293         
     294          $ /etc/init.d/cupsys restart 
     295           
     296    For new printers : 
     297     
     298        Go to CUPS management interface (http://localhost:631)  
     299        and choose the appropriate PyKota managed device depending 
     300        on the type of printer you use. For example, if your 
     301        printer is waiting on : 
     302         
     303            socket://myprinter.domain.com:9100 
     304             
     305        Then choose :     
     306         
     307            cupspykota:socket://myprinter.domain.com:9100 
     308             
     309        Configure your printer as usual.     
     310         
     311        That's all. 
     312     
     313    For existing printers : 
     314     
     315        If you had already installed PyKota, then remove 
     316        the *cupsFilter lines in your PPD files for each 
     317        printer already managed printers. Each line to 
     318        remove is of the form : 
     319         
     320          *cupsFilter: "application/vnd.cups-postscript 0 /usr/bin/pykota" 
     321         
     322        Don't touch anything else, especially any other *cupsFilter line. 
     323        Then save each of these files and restart CUPS. 
     324         
     325        Then, the easiest is to directly modify the DeviceURI lines  
     326        in /etc/cups/printers.conf, you just have to put  
     327        'cupspykota:' in front of what is already on these lines.  
     328        For example, replace : 
     329     
     330            DeviceURI socket://myprinter.domain.com:9100 
     331         
     332        with :     
     333     
     334            DeviceURI cupspykota:socket://myprinter.domain.com:9100 
     335         
     336        Save the file and restart CUPS. 
     337 
     338  - LPRng Printing System : 
    312339   
    313340    Modify the /etc/printcap file to add two lines identical to these ones :