HOW TO CONFIGURE PRINTER SUPPORTED BY GHOSTSCRIPT AS A POSTSCRIPT PRINTER UNDER SOLARIS

by Alexander Panasyuk ().

Version 6.0.0

(FYI, analogous problem for SunOS 4.x.x can be solved using APSfilter package).

Table of contents

  • Introduction
  • Instructions for locally connected printer.
  • Instructions for networked printer (Solaris 2.6+).
  • Q & A
  • How to disable banner page?
  • How to enable remote print requests under Solaris 2.5?
  • Why is my postscript document still being printed as a text?
  • I am getting error diagnostics from printer daemon which looks like following: "ld.so.1: /opt/bin/gs: fatal: libXext.so.0: can't open file: errno=2". What's up?
  • Can I pass command line options to my filter?
  • Why does not "stcolor" work with my Epson Stylus? Where is this "stcolor" anyway?
  • What about ULTRAstation?
  • Filtering does not work for remote printer, what can I do (Solaris 2.6 to Windows NT Printing) ?
  • There are no error messages, but no printer output either...
  • I am having trouble printing plain text files.
  • Notes on Solaris 8.
  • Important changes in this document from earlier versions.

  •  

    Introduction

        Following is a relatively simple procedure which allowed me to configure an inkjet Epson Stylus Color II and non-Postscript HP LaserJet III as postscript printers under Solaris 2.5.1-2.6 (SPARC) on SPARCstation 20 and ULTRA 10 using Ghostscript (versions 3.53-5.10). I believe that similar procedure can be used for other printers supported by Ghostscript. Information presented here should be valid for users of Solaris (x86) as well.

    This HOW-TO primarily concerns locally connected and networked printers. Stephen Thamel has sent me a workaround to extend this solution on remote printers as well. I have put his information here.

    These instructions are still being occasionally updated and corrected (see "Important changes in this document from previous versions" below), you can find latest revision at http://cfauvcs5.cfa.harvard.edu/SetGSprinter4Solaris.html.

    I am not taking any responsibility for what may happen to your printer, system, state of mind or wallet if you follow these instructions. They worked for me, though.

    Instructions for locally connected printer.

    Most of the following instructions require superuser access. You will need Ghostscript package installed with support for your printer compiled in (a binary distributions may not include some of the drivers available so you have to check . Command "gs -h" lists all device types your Ghostscript installation can generate output for). Information about Ghostscript can be found here.

    1) Write filter description file and put it into /etc/lp/fd directory. Name it whatever you want, e.g. "stylus.fd". Content may be like this:

    # Beginning of the file - this is just a comment 
    Input types: postscript 
    Output types: ESC 
    Printer types: any 
    Printers: any 
    Filter type: fast
    Command: /opt/bin/gs -q -dSAFER -dNOPAUSE -dMicroweave -sDEVICE=stcolor -r360x360 -sOutputFile=/dev/bpp0 stcolor.ps - 
    # End of the file
    Instead of "ESC" for "Output types" you can use any word which you believe describes the language your printer understands. Example above was used by me for Epson Stylus which understands Epson ESC-codes language. I guess "PCL" would be proper for HP's. What particular word does not really matter as long as you use it consistently. Don't use types already defined in the system, like "PS","postscript","simple" or "postdown". As a "Command:" you specify whatever is required to convert postscript to this language. For LaserJets it may look like following:
    Command: /opt/bin/gs -q -dSAFER -dNOPAUSE -sDEVICE=laserjet -r300 -sOutputFile=/dev/bpp0 -
    See Ghostscript documentation for options suitable for your printer. You should use real name of the device your printer is connected to  instead of "/dev/bpp0" if different.

    You should use full path names for executables.

    1a) Set file ownership and permissions similar to the "standard" filters in the directory, for my system it was "chown lp:lp stylus.fd; chmod 664 stylus.fd"

    2) Register filter with printing system.

    /usr/sbin/lpfilter -f stylus -F /etc/lp/fd/stylus.fd

    Here "stylus.fd" is the name of the file you have created in 1), "stylus" is the name of the filter which can be whatever you like (just watch for names already defined - "lpfilter -f all -l" should print them).

    3) Register printer

    /usr/sbin/lpadmin -p your_printer_name -v /dev/null -I ESC

    "your_printer_name" here is your choice - you will be using it with "lp" command. Use "Output type" from filter description file (see 1) instead of "ESC" if different.  Users of Solaris (x86) may want to add -o stty="-opost" to the  list of options to avoid CR/LF to CR translation in the STREAM module.

    4) I had to reset my printer port device to be owned by "lp" with permission "666", you may have to as well. Now run

    enable your_printer_name
    accept your_printer_name

    and you are in business ( hopefully ).

    NOTE: Alternative approach

    It was mentioned to me that sending data to printer port directly from the filter was not how Solaris print system assumed to use printer filters. Filter is supposed to send data to standard output and print system should get them to printer port later. Well, the main advantage of the approach above is that there is no risk of printing subsystem filtering this output in some way and converting it to a garbage. It is not easy to avoid  this using "correct" approach. I've applied latter successfully on SPARCstation 20 under Solaris 2.5.1, but when I tried to use it with Solaris (x86), SPARCprinters or ULTRAs I had to get over many complications. I was not able to apply it to ULTRA 10 running Solaris 2.6 at all.

    Nevertheless you may be more lucky, or modern versions of Solaris may make it easier. To use correct approach in the list of instructions above change following:
    1) In filter "Command:" line change "-sOutputFile=/dev/bpp0" to "-sOutputFile=-". Change "Filter type:" from "fast" to "slow".
    3) In lpadmin command line change "-v /dev/null" to "-v /dev/bpp0" or whatever port your printer is connected to.

    Instructions for networked printer (Solaris 2.6+).

    Following instructions are relevant for non-postscript printer connected directly to TCP/IP network, i.e. one that has its own IP address (One can find even networked inkjets lately - wow!). If you have a printer connected to remote system you should go here instead.

    Install Ghostscript and find proper options to run your printer. Install printer with

    lpadmin -p <printer name> -i /usr/lib/lp/model/netstandard -v /dev/null \
        -o dest=<printer network address> -I postscript

    Then edit /etc/lp/interfaces/<printer name> file and replace whole if-statement

    if [ -z "${FILTER}" ]
    then
            #####
            #
            # If no filter is being used, we use netpr to push the
            # file to the printer.
            # (QUOTES ARE IMPORTANT!)
            #####
    ....
    fi

    with

    FILTER="/path_to_gs/gs -q -dSAFER -dNOPAUSE <options to run your printer> -sOutputFile=- -"

    Then run

    enable your_printer_name
    accept your_printer_name

    That's it.
     

    Q&A (some of them are taken from Solaris 2.5 AnswerBook, System Administration Guide, Volume II and put here only because there are relevant and not easy to find).

    How to disable banner page?

    If you want printer to stop printing banner page (header) by default you have to:

    a) run "lpadmin -p your_printer_name -o nobanner". This would allow users to suppress banner by running "lp" with "-o nobanner" option, but it will still be printed by default.

    b) Edit "/etc/lp/interfaces/your_printer_name" file (it is created by "lpadmin" command in 3). Find line which says

    nobanner="no"

    and change it to ... guess what ...

    nobanner="yes".

    How to enable remote print requests under Solaris 2.5?

    Because you have not used "admintool" to set up your printer there is a chance that port monitor for print server is not yet configured and remote print requests are not processed. If command "pmadm -l" returns no lines having "lp" or "lpd" in SVCTAG column this is probably the case. To remedy the situation you can employ following incantation using Bourne shell ("sh"):

    (!!!WARNING!!! Following sequence of commands is retyped from Answerbook for Solaris version 2.5. It worked for me with Solaris 2.5.1. There is no guaranty that it would work with any other version of Solaris. Casper Dik has informed me that all this stuff is not necessary for Solaris 2.6 where remote printing is done through inetd.)

    sacadm -a -p tcp -t listen -c "/usr/lib/saf/listen tcp" \ 
    -v `nlsadmin -V` -n 999 

    pmadm -a -p tcp -s lp -i root -m `nlsadmin -o /var/spool/lp/fifos/listenS5` \
    -v `nlsadmin -V`

    u_addr=`lpsystem -A`

    pmadm -a -p tcp -s lpd -i root \
    -m `nlsadmin -o /var/spool/lp/fifos/listenBSD -A "\\x${u_addr}"` \ 
    -v `nlsadmin -V` 

    new_addr=`lpsystem -A | cut -b1-4`

    tail=`lpsystem -A | awk '{pos = index($0, "0203")+4 
    print substr($0, pos, length($0)-pos+1)}'`

    new_addr=`echo ${new_addr}0ACE${tail}`

    pmadm -a -p tcp -s 0 -i root \ -m `nlsadmin -c /usr/lib/saf/nlps_server -A \ 
    "\\x${new_addr}"` -v `nlsadmin -V`
    After magic had worked "pmadm -l" should return something closely resembling following (there may be more lines, but these should be present):
    PMTAG          PMTYPE         SVCTAG         FLGS ID       <PMSPECIFIC>
    tcp            listen         lp             -    root     - - p - /var/spool/lp/fifos/listenS5 #
    tcp            listen         lpd            -    root     \x00020203000000000000000000000000 - p - /var/spool/lp/fifos/listenBSD #
    tcp            listen         0              -    root     \x00020ACE000000000000000000000000 - c - /usr/lib/saf/nlps_server #
    "sacadm -l" should return in particular something like this:
    PMTAG          PMTYPE         FLGS RCNT STATUS     COMMAND
    tcp            listen         -    999  ENABLED    /usr/lib/saf/listen tcp #
    Now there is a question about permissions for remote requests. If you don't care about restricting access to your printer edit "/etc/lp/Systems" file and uncomment "+:x:-:s5:-:n:10:-:-:Allow all connections" line if it is commented out ; you may want to read relevant information in the same file.

    If your luck has hold you should be all set by now.
     

    Why is my postscript document still being printed as a text?

    Run "file name-of-the-file-you-are-trying-to-print". If output is "Postscript document" then something is wrong with your printer configuration. If not - something is wrong with your document. You should make sure that a) its content is really postscript and b) first two characters in the file are "%!". For example, postscript documents generated under DOS/Windows often have "Ctrl-D" character as a first byte preceding "%!". This character prevents Solaris from recognizing the document as postscript and should be deleted.
     

    I am getting error diagnostics from printer daemon which looks like following: "ld.so.1: /opt/bin/gs: fatal: libXext.so.0: can't open file: errno=2". What's up?

    Well, it is about shared libraries. It looks like Ghostscript can not find shared library it needs to run without help of LD_LIBRARY_PATH environment variable which is not set when filter is called. You have to:

    1) Locate necessary libraries  (libXext.so.0 in the example above). If Ghostscript works fine from your shell prompt then enter command "ldd full-path-to-gs-file" (e.g. "ldd /opt/bin/gs") and it will print out locations of all shared libraries "gs" uses (usually libXext.so.0 is located in /usr/openwin/lib) . Then unset environment variable LD_LIBRARY_PATH (e.g. "unsetenv LD_LIBRARY_PATH" for C-shell) and run "ldd full-path-to-gs-file" again. For all "not found" libraries note the directories where they are located comparing output with previous "ldd" run.

    2) What you do next depends on how many directories should be included in the path. If it is only one prepend program call in filter description file "Command:" line with LD_LIBRARY_PATH=directory-not-found-libraries-are-located-in statement. In our case the line in the filter description file may look like this:

    Command: LD_LIBRARY_PATH=/usr/openwin/lib /opt/bin/gs -q -dSAFER ...

    You can not specify several directories this way because the format of LD_LIBRARY_PATH variable (directories are separated with colons) conflicts with format of some internal printing subsystem database files. You have to write a shell script in this case.

    NOTE: if you are compiling Ghostscript yourself you may use -R compiler option to record necessary directory information into executable, so it does not have to rely on LD_LIBRARY_PATH at all.

    Can I pass command line options to my filter?

    Following is the quote from e-mail message from Casper Dik:

    "Perhaps it's interesting to also supply information on how to pass parameters to the filter script. This can be done using modes in the filter definition:

    Options: MODES fast = -f

    This example passes the "-f" option to your interface script if you invoke lp like this:

    lp -y fast

    You can use this to have one queue for several types of output; I use it for fast (360x360 dpi; @st600pl.up), normal (720x720dpi) and photo (1440x720 @st600ih.upp) on my Stylus Color 600."

    NOTE: As Dr. David Kirkby found out it was not so straightforward to use this approach without writing a special interface script. Problem here is that option gets attached to the END of command line, so in case of ghostscript command it would appear after input file specification ("-" in case of standard input). Ghostscript does not like this and would not process such an option. One solution is to write interface script which would put option in correct place on command line.

    Why does not "stcolor" work with my Epson Stylus? Where is this "stcolor" anyway?

    You may try to use "uniprint" device with new versions of Ghostscript (5.0x-...). Read Ghostscript documentation about using "uniprint" -  the syntax is quite different from "stcolor".

    What about ULTRA?

    You should install patch 104605-0n (n > 3) for Solaris 2.5.1 or  105741-0n  (n>3) for 2.6. Name of on-board parallel port device is "/dev/ecpp0" (at least on my ULTRA 10).

    Filtering does not work for remote printer, what can I do?

    Solaris does not call any filters for  a stream sent to remote printer. By now I have two approaches suggested by readers to overcome this problem:
    Solution by Stephen W. Thamel:
    "  The workaround is to make a local queue that also sends the output of gs  to a remove queue.  If NT is involved (like here) there is a slight mod that has to be performed on that system as well.

    Solaris 2.6 to Window NT Printing

    The following problems and solutions encountered are described generally:
    1.  The standard Windows NT service LPDSVC wants to surround all lp jobs with headers resulting in textual output of Postscript or code output of PCL.  This can be corrected by a registry modification call "SimulatePassThrough".  See Q168457 (Microsoft Technical Support) for details.  This modification should be applied even if lpr/lpd (BSD) is to be used. ( NOTE from Alexander: quoted Microsoft Technical Support note did not work for Michael Deiss. What did work was note Q150930.)
    2.  The IBM4019 printer attached to the NT server is a PCL emulator and does not speak Postscript.  Yet, Solaris as installed only supports Postscript output.  Fortunately, Ghostscript can parse and process Postscript commands and output hplaserjet (PCL) format.
    3. Filters on Solaris 2.6 (ATT) are only applied to local printers and not remote ones.  Several sites mention this drawback regarding BSD but none on ATT.  The same holds true for ATT printing (at least on Solaris 2.6) - as tested by myself.  Creating a local queue (to /dev/null) and a remote queue (to the NT server) can serve as a workaround.  The command that performs the filter on the local queue will dump the stdout to the remote queue.
    Steps

     1.Install LPDSVC on Windows NT and apply the "SimlatePassThrough" mod as described in Q168457

    2.Install in standard locations GhostScript 5.10 or later for  Solaris. Binaries are probably available.

     3.On Solaris, create the following filter as (/etc/lp/fd/PStoPCL.fd):

    Input types: postscript
    Output types: PCL
    Printer types: any
    Printers: any
    Filter type: slow
    Command: /usr/local/bin/gs -q -dSAFER -dNOPAUSE -sDEVICE -sDEVICE=laserjet -r300 -sOutputFile=\|'lp -d ibm4019remote -' -

    4. Assign ownership and permissions to this filters, otherwise the daemon might not be able to access it.

    chown lp:lp /etc/lp/fd/PStoPCL.fd; chmod 664 /etc/lp/fd/PStoPCL.fd

    5. Register this filter with the printing system.

    /usr/sbin/lpfilter -f PStoPCL -F /etc/lp/fd/PStoPCL.fd

    6. Verify the full filter has been parsed.  It should end up at the bottom of the following output:

    /usr/sbin/lpfilter -f all -l

    7. Register the remote printer.  The -s option is where the server ip and
    queue name are supplied.  Also, the remote printer can process ascii text
    without filtering, so set its content-type to simple.

    lpadmin -p ibm4019remote -s  100.100.100.5!IBM4019Unix -I simple

    8. Register the local printer and assign the local printer as the system default.  Make sure the local printer is assigned a content-type of PCL so the filter will be applied.

    lpadmin -p ibm4019local -v /dev/null -I PCL
    lpadmin -d ibm4019local

    9. Allow the local queue to accept jobs and enable the local queue to output.  Solaris may have already performed these actions in the step above.

    enable ibm4019local
    accept ibm4019local
    "
    NOTE (by Andy Robertson): "One minor suggestion for Stephen W. Thamel's solution in your "Solaris 2.6 to Windows NT Printing" section. In Step 3 the filter definition hardwires the remote printer name, but uses a filter name and "Output type" which reflects the actual type e.g. PStoPCL.fd and PCL. This is okay if there's only one remote printer of this type, but there could be more than one PCL printer on your network. A clearer approach might be to derive each filter name and its output type from the unique printer name. Just a thought."

    Another NOTE (by Sumit Shah):
    Problem:  When a user  submits a job to the queue the job will print as expected, but  will remain in the queue.  When I run lpq -P<printer> it will list the jobs with the following warning:
    Warning: hpofficelocal is down: new printer
    The printer itself is connected to an NT box.
    Solution:I managed to fix the problem by enabling the printer, but not with the enable listed in /usr/bin,
    but the one in: /usr/lib/lp/local.

    Solution by Casper Dik:

    "There's an easy trick in Solaris 2.6 to make a remote (BSD) printer appear as a local printer and have local filtering.

    Simply define the printer as a local printer, but use the "netstandard" script.  The queue will act as a local printer, but the output phase will write to the networked printer instead.  But make sure you define the input types correctly.

    There are two ways to have a remote printer: one is defining it as a remote printer in /etc/printers.conf, but the other is defining a local printer and sending output through netstandard.  With the latter method, a netstandard printer can be used for local filtering."
     

    There are no error messages, but no printer output either.

    According to Brian Grayson the filter can fail without producing any error messages - it depends on your system configuration. In this case he recommends to check LD_LIBRARY_PATH and/or use "truss -o /dev/console " in the beginning of the filter command to determine whether gs is being invoked and why it is dying. Adam Stein also suggests adding "1>/dev/console 2>&1" to the end of the command line to see ghostscript error messages.
     

    I am having trouble printing plain text files.

    If your printer can print plain text you can try to register it under different name for plain text files only:

    /usr/sbin/lpadmin -p different_name -v device_your_printer_is_connected_to \
        -I simple

    It may work or may not, because printing system will filter your file, possibly removing CRs etc. and producing ugly printout. Another approach is to activate "plain text (simple) to postscript" filter provided with Solaris. Just run as a root:

     /usr/sbin/lpfilter -f postprint -F /etc/lp/fd/postprint.fd

    Conversion to and from postscript will suck up some CPU, but you don't have to specify second printer name this way.

    Notes on Solaris 8.

    Following are the notes I've received from John Rosander. I've edited them somewhat and apologize in advance if I got something wrong. He was trying to connect HP Officejet 520 printer to Solaris 8 system using Ghostscript loaded from the "Software companion" CD that came with Solaris 8.
    1) He found out that mentioned Ghostscript installation can not find its own fonts without using -I"/opt/sfw/share/ghostscript/6.52:/opt/sfw/share/ghostscript/fonts" option in the command line.
    2) He had to use  Alternative approach  because gs appeared to be running under user ID that did not allow to access printer port.

    Important changes in this document from earlier versions.

    1) Major modification. Former version with relevant changes list is still available here.
    2) -sOutputFile='lp -d ibm4019remote -' in Q&A about remote printing is changed to correct -sOutputFile=\|'lp -d ibm4019remote -'.
    3) By recommendation of Kai O'Yang -o 'stty="-opost"' is added to lpadmin options for Solaris (x86).
    4) Recommendations from Brian Grayson about troubleshooting.
    5) Added instructions for networked printer.
    6) Michael Deiss has provided some additional info  about Windows NT printing.
    7) Added Casper Dik's solution for remote printing.
    8) Added Dr. David Kirkby note about filter option specification.
    9) Added Andy Robertson's suggestion for remote printing.
    10) Ernst-Georg Schmid corrected wrong "-post" stty option.
    11) Hint for Windows NT printing from Sumit Shah.
    12) My own advice about plain text file printing.
    13) Notes from John Rosander on Solaris 8 printing.