SMB HOWTO: Доступ к принтеру Windows с машин под Linux

Next Previous Contents

## 59. Доступ к принтеру Windows с машин под Linux

Для доступа к принтеру на Windows машине, вы должны сделать следующее:

a) ВЫ должны иметь правильные записи в файле /etc/printcap и они должны соответствовать локальной структуре директорий (для директории спула, и т.п.)

b) У вас должен быть скрипт /usr/bin/smbprint. Он идет вместе с исходными текстами Samba, но не со всеми двоичными дистрибутивами Samba. Его немного модифицированная копия обсуждается ниже.

c) Если вы хотите преобразовывать ASCII файлы в Postscript, вы должны иметь nenscript, или его эквивалент. nenscript -- это конвертор Postscript, он обычно устанавливается в директорию /usr/bin.

d) Вы можете хотеть сделать печать через Samba более легкой с помощью программы-надстройки. Простой скрипт на perl, который обрабатывает ASCII, Postscript или преобразованный Postscript дан ниже.

Запись в /etc/printcap ниже приведена для принтера HP 5MP на сервере Windows NT. Записи следующие:

            cm - комментарий

            lp - имя устройства, открываемого для вывода

            sd - директория спула принтера (на локальной машине)

            af - файл учета пользования принтером

            mx - максимальный размер файла (ноль -- без ограничений)

            if - имя входного фильтра (скрипта)

Для более детальной информации смотрите Printing HOWTO или справочные страницы по printcap.

> `

>     # /etc/printcap

>     #

>     # //zimmerman/oreilly via smbprint

>     #

>     lp:\

>             :cm=HP 5MP Postscript OReilly on zimmerman:\

>             :lp=/dev/lp1:\

>             :sd=/var/spool/lpd/lp:\

>             :af=/var/spool/lpd/lp/acct:\

>             :mx#0:\

>             :if=/usr/bin/smbprint:

> `

Убедитесь, что директории спула и учета пользования существуют и имеют право на запись. Убедитесь, что строка 'if' содержит правильный путь к скрипту `smbprint` (дан ниже) и будьте уверены, что указывается на правильное устройство (специальный файл /dev).

Далее идет сам скрипт `smbprint`. Он обычно находится в директории /usr/bin и относящийся к Andrew Tridgell, человеку кто создал Samba, насколько я знаю. Этот скрипт идет с дистрибутивом исходного кода Samba, но отсутствует в некоторых бинарных дистрибутивах, так что я воссоздал его здесь.

Вы можете захотеть взглянуть на него внимательно. Есть некоторые мелкие изменения, которые показали себя полезными.

> `

>     #!/bin/sh -x

>     # Этот скрипт является входным фильтром для основанной на printcap

>     # печати на unix-машинах. Он использует программу smbclient для

>     # печати файла на указанный smb-сервер и сервис.

>     # Например вы можете иметь запись в printcap подобную этой

>     #

>     # smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint

>     #

>     # которая создает unix-принтер названный "smb", который будет

>     # печатать с помощью этого скрипта. Вам необходимо создать директорию

>     # спула /usr/spool/smb с соответствующими правами и владельцем

>     # Установите здесь сервер и сервис на который вы хотите печатать. В

>     # этом примере я имею PC с WfWg PC, названную "lapland", которая

>     # имеет экспортируемый принтер, называемый "printer" без пароля

>     #

>     # Далее скрипт был изменен hamiltom@ecnz.co.nz (Michael Hamilton)

>     # так что сервер, сервис и пароль могут быть считаны из файла

>     # /usr/var/spool/lpd/PRINTNAME/.config

>     #

>     # Для того чтобы это работало запись в /etc/printcap должна

>     # включать файл учета использования (af=...):

>     #

>     #   cdcolour:\

>     #       :cm=CD IBM Colorjet on 6th:\

>     #       :sd=/var/spool/lpd/cdcolour:\

>     #       :af=/var/spool/lpd/cdcolour/acct:\

>     #       :if=/usr/local/etc/smbprint:\

>     #       :mx=0:\

>     #       :lp=/dev/null:

>     #

>     # Файл /usr/var/spool/lpd/PRINTNAME/.config должен содержать

>     #   server=PC_SERVER

>     #   service=PR_SHARENAME

>     #   password="password"

>     #

>     # Например,

>     #   server=PAULS_PC

>     #   service=CJET_371

>     #   password=""

>     #

>     # Debugging log file, change to /dev/null if you like.

>     #

>     logfile=/tmp/smb-print.log

>     # logfile=/dev/null

>     #

>     # The last parameter to the filter is the accounting file name.

>     #

>     spool_dir=/var/spool/lpd/lp

>     config_file=$spool_dir/.config

>     # Should read the following variables set in the config file:

>     #   server

>     #   service

>     #   password

>     #   user

>     eval `cat $config_file`

>     #

>     # Some debugging help, change the >> to > if you want to same space.

>     #

>     echo "server $server, service $service" >> $logfile

>     (

>     # NOTE You may wish to add the line `echo translate' if you want automatic

>     # CR/LF translation when printing.

>             echo translate

>             echo "print -"

>             cat

>     ) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $user -N -P >> $logfile

> `

Большинство дистрибутивов linux идет с программой `nenscript` для преобразования ASCII документов в Postscript. Следующий скрипт на perl делает жизнь легче, обеспечивая простой интерфейс для печати в liinux через smbprint.

    Использование: print [-a|c|p] <filename>

           -a печатает <filename> как ASCII

           -c печатает <filename> отформатированный как исходный код

           -p печатает <filename> как Postscript

            Если опции не заданы, программа попробует определить

            тип файла и печатать соответственно

Используя smbprint для печати ASCII файлов, скрипт следит за длинными строками. Если возможно этот скрипт разрывает длинную строку на пробеле (вместо разрыва в середине слова).

Форматирование исходного кода выполняется с помощью `nenscript`. Он берет ASCII-файл и форматирует его в 2 колонки с с заголовком (дата, имя файла и т.п.). Он также нумерует строки. Используя этот скрипт как пример другие типы форматирования могут быть сделаны.

Postscript-документы уже правильно отформатированы, так что они печатаются сразу.

> `

>     #!/usr/bin/perl

>     # Скрипт:   print

>     # Авторы:   Brad Marshall, David Wood

>     #           Plugged In Communications

>     # Дата:   960808

>     #

>     # Используется для печати на сервис oreilly, который расположен на

>     # сервере zimmerman

>     # Назначение: Берет файлы разных типов как аргумент и обрабатывает

>     # их соответственно для передачи на скрипт печать Samba.

>     #

>     # В настоящее время поддерживаются типы файлов:

>     #

>     # ASCII      - Если длина строки длинее чем $line_length символов, то

>     #              переносит строку на пробеле

>     # Postscript - Берет без обработки

>     # Code        - Форматирует в Postscript (используя nenscript), чтобы

>     #               отображать правильно (альбомный формат, фонт и т.п.)

>     #

>     # Установить максимальную длину строки ASCII текста

>     $line_length = 76;

>     # Установить путь к скрипту печати Samba

>     $print_prog = "/usr/bin/smbprint";

>     # Установить путь и имя nenscript (конвертера ASCII-->Postscript)

>     $nenscript = "/usr/bin/nenscript";

>     unless ( -f $print_prog ) {

>             die "Can't find $print_prog!";

>     }

>     unless ( -f $nenscript ) {

>             die "Can't find $nenscript!";

>     }

>     &ParseCmdLine(@ARGV);

>     # DBG

>     print "filetype is $filetype\n";

>     if ($filetype eq "ASCII") {

>             &wrap($line_length);

>     } elsif ($filetype eq "code") {

>             &codeformat;

>     } elsif ($filetype eq "ps") {

>             &createarray;

>     } else {

>             print "Sorry..no known file type.\n";

>             exit 0;

>     }

>     # Pipe the array to smbprint

>     open(PRINTER, "|$print_prog") || die "Can't open $print_prog: $!\n";

>     foreach $line (@newlines) {

>             print PRINTER $line;

>     }

>     # Send an extra linefeed in case a file has an incomplete last line.

>     print PRINTER "\n";

>     close(PRINTER);

>     print "Completed\n";

>     exit 0;

>     # --------------------------------------------------- #

>     #        Everything below here is a subroutine        #

>     # --------------------------------------------------- #

>     sub ParseCmdLine {

>             # Parses the command line, finding out what file type the file is

>             # Gets $arg and $file to be the arguments (if the exists)

>             # and the filename

>             if ($#_ < 0) {

>                     &usage;

>             }

>             # DBG

>     #       foreach $element (@_) {

>     #               print "*$element* \n";

>     #       }

>             $arg = shift(@_);

>             if ($arg =~ /\-./) {

>                     $cmd = $arg;

>             # DBG

>     #       print "\$cmd found.\n";

>                     $file = shift(@_);

>             } else {

>                     $file = $arg;

>             }

>             # Defining the file type

>             unless ($cmd) {

>                     # We have no arguments

>                     if ($file =~ /\.ps$/) {

>                             $filetype = "ps";

>                     } elsif ($file =~ /\.java$|\.c$|\.h$|\.pl$|\.sh$|\.csh$|\.m4$|\.inc$|\.html$|\.htm$/) {

>                             $filetype = "code";

>                     } else {

>                             $filetype = "ASCII";

>                     }

>                     # Process $file for what type is it and return $filetype

>             } else {

>                     # We have what type it is in $arg

>                     if ($cmd =~ /^-p$/) {

>                             $filetype = "ps";

>                     } elsif ($cmd =~ /^-c$/) {

>                             $filetype = "code";

>                     } elsif ($cmd =~ /^-a$/) {

>                             $filetype = "ASCII"

>                     }

>             }

>     }

>     sub usage {

>             print "

>     Использование: print [-a|c|p] <filename>

>            -a печатает <filename> как ASCII

>            -c печатает <filename> отформатированный как исходный код

>            -p печатает <filename> как Postscript

>             Если опции не заданы, программа попробует определить

>             тип файла и печатать соответственно\n

>     ";

>             exit(0);

>     }

>     sub wrap {

>             # Create an array of file lines, where each line is < the

>             # number of characters specified, and wrapped only on whitespace

>             # Get the number of characters to limit the line to.

>             $limit = pop(@_);

>             # DBG

>             #print "Entering subroutine wrap\n";

>             #print "The line length limit is $limit\n";

>             # Read in the file, parse and put into an array.

>             open(FILE, "<$file") || die "Can't open $file: $!\n";

>             while(<FILE>) {

>                     $line = $_;

>                     # DBG

>                     #print "The line is:\n$line\n";

>                     # Wrap the line if it is over the limit.

>                     while ( length($line) > $limit ) {

>                             # DBG

>                             #print "Wrapping...";

>                             # Get the first $limit +1 characters.

>                             $part = substr($line,0,$limit +1);

>                             # DBG

>                             #print "The partial line is:\n$part\n";

>                             # Check to see if the last character is a space.

>                             $last_char = substr($part,-1, 1);

>                             if ( " " eq $last_char ) {

>                                 # If it is, print the rest.

>                                 # DBG

>                                 #print "The last character was a space\n";

>                                 substr($line,0,$limit + 1) = "";

>                                 substr($part,-1,1) = "";

>                                 push(@newlines,"$part\n");

>                             } else {

>                                  # If it is not, find the last space in the

>                                  # sub-line and print up to there.

>                                 # DBG

>                                 #print "The last character was not a space\n";

>                                  # Remove the character past $limit

>                                  substr($part,-1,1) = "";

>                                  # Reverse the line to make it easy to find

>                                  # the last space.

>                                  $revpart = reverse($part);

>                                  $index = index($revpart," ");

>                                  if ( $index > 0 ) {

>                                    substr($line,0,$limit-$index) = "";

>                                    push(@newlines,substr($part,0,$limit-$index)

>                                        . "\n");

>                                  } else {

>                                    # There was no space in the line, so

>                                    # print it up to $limit.

>                                    substr($line,0,$limit) = "";

>                                    push(@newlines,substr($part,0,$limit)

>                                        . "\n");

>                                  }

>                             }

>                     }

>                     push(@newlines,$line);

>             }

>             close(FILE);

>     }

>     sub codeformat {

>             # Call subroutine wrap then filter through nenscript

>             &wrap($line_length);

>             # Pipe the results through nenscript to create a Postscript

>             # file that adheres to some decent format for printing

>             # source code (landscape, Courier font, line numbers).

>             # Print this to a temporary file first.

>             $tmpfile = "/tmp/nenscript$$";

>             open(FILE, "|$nenscript -2G -i$file -N -p$tmpfile -r") ||

>                     die "Can't open nenscript: $!\n";

>             foreach $line (@newlines) {

>                     print FILE $line;

>             }

>             close(FILE);

>             # Read the temporary file back into an array so it can be

>             # passed to the Samba print script.

>             @newlines = ("");

>             open(FILE, "<$tmpfile") || die "Can't open $file: $!\n";

>             while(<FILE>) {

>                     push(@newlines,$_);

>             }

>             close(FILE);

>             system("rm $tmpfile");

>     }

>     sub createarray {

>             # Create the array for postscript

>             open(FILE, "<$file") || die "Can't open $file: $!\n";

>             while(<FILE>) {

>                     push(@newlines,$_);

>             }

>             close(FILE);

>     }

> `

Next Previous Contents