Доступ к принтеру Windows с машин работающих под Linux
Для доступа к принтеру на Windows машине, вы должны сделать следующее:
Запись в файле /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
---Конец -----
--------------------------------------------------------------