Доступ к принтеру Windows с машин работающих под Linux


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

  • ВЫ должны иметь правильные записи в файле /etc/printcap и они должны соответствовать локальной структуре директорий (для буферной директории, и т.п.)
  • У вас должен быть скрипт /usr/bin/smbprint. Он поставляется вместе с исходными текстами Samba, но не со всеми двоичными дистрибутивами Samba. Его немного модифицированная копия обсуждается ниже.
  • Если вы хотите преобразовывать ASCII файлы в Postscript, вы должны иметь программу nenscript, или ее эквивалент. nenscript-- это конвертер Postscript, он обычно устанавливается в директорию /usr/bin.
  • Вы можете захотеть сделать печать через Samba более легкой, используя программы-надстройки. Простой скрипт на perl, который обрабатывает ASCII, Postscript или преобразованный Postscript приведен ниже.
  • Вы также можете использовать MagicFilter для того, чтобы выполнить, описанное выше. Подробности о настройке MagicFilter приводятся ниже. MagicFilter имеет преимущества, потому, что он знает как автоматически преобразовывать достаточно большое количество форматов файлов.
  • Запись в файле /etc/printcap, приведенном ниже, сделана для принтера HP 5MP на сервере Windows NT. Используются следующие поля файла /etc/printcap:

    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 делает жизнь пользователя легче, обеспечивая простой интерфейс для печати используя 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); }

    Теперь о применении MagicFilter. Спасибо Alberto Menegazzi ( ) за его информацию.

    Alberto сообщил: -------------------------------------------------------------- 1) Установите MagicFilter в /usr/bin/local с фильтрами для необходимых принтеров, но НЕ заполняйте записи в /etc/printcap, как предполагается в документации на MagicFilter.

    2) Запишите в /etc/printcap примерно вот такую запись (Это сделано для моего принтера LaserJet 4L):

    lp|ljet4l:\ :cm=HP LaserJet 4L:\ :lp=/dev/null:\ # or /dev/lp1 :sd=/var/spool/lpd/ljet4l:\ :af=/var/spool/lpd/ljet4l/acct:\ :sh:mx#0:\ :if=/usr/local/bin/main-filter:

    Вы должны, объяснить, что устройство lp=/dev/... открывается для блокирования, так что для каждого удаленного принтера используется одно "виртуальное устройство".

    Пример создания : touch /dev/ljet4l

    3) Напишите фильтр /usr/local/bin/main-filter, с таким же образом предполагая использование ljet4l-filter вместо cat.

    Вот так для меня.

    #! /bin/sh logfile=/var/log/smb-print.log spool_dir=/var/spool/lpd/ljet4l ( echo "print -" /usr/local/bin/ljet4l-filter ) | /usr/bin/smbclient "\\\\SHIR\\HPLJ4" -N -P >> $logfile

    P.S. : Это цитата из Print2Win mini-Howto о блокировании, а также о том, зачем создавать виртуальные принтера

    ---Начало здесь --------- Совет от Rick Bressler :

    Хороший совет. Я использую нечто подобное. Вот один полезный совет, хотя он не является хорошей идеей:

    :lp=/dev/null:\

    lpr делает 'монопольное (exclusive)' открытие файла, который вы укажете в поле lp=. Он делает это для предотвращения попыток множества процессов печатать одновременно на одном и том же принтере.

    Побочным эффектом этого, в вашем случае является то, что eng и colour не могут печатать одновременно, (обычно более или менее прозрачно, поскольку они вероятно печатают быстро и поскольку вы не замечаете, что они ставят задания в очередь), но любые другие процессы, которые пытаются записать в /dev/null не будут работать!

    На однопользовательской системе, это вероятно не является большой проблемой. У меня имеется система с 50 принтерами. В этом случае это может быть проблемой.

    Решение этой проблемы заключалось в создании устройства для каждого их принтеров. Например: touch /dev/eng.

    Я модифицировал записи lp в файле printcap, приведенном выше, приняв во внимание пожелания Rick. Я сделал следующее:

    #touch /dev/eng #touch /dev/colour

    ---Конец -----

    --------------------------------------------------------------


    Содержание раздела