全部博文(1144)
分类: LINUX
2006-04-24 09:30:50
为了共享 Linux 打印机给 Windows 机器, 你必须确定你的打印机已经装设好. 如果你能从 linux 上打印,设定 SMB 的打印机共享将会很直接.
请见 Printing HOWTO 来设定当地的打印.
因为作者使用被连接到 Windows NT 机器的打印机, 这小节不应该被视为很完整的,而只是建议.加入打印设定到你的 smb.conf:
[global]
printing = bsd
printcap name = /etc/printcap
load printers = yes
log file = /var/log/samba-log.%m
lock directory = /var/lock/samba
[printers]
comment = All Printers
security = server
path = /var/spool/lpd/lp
browseable = no
printable = yes
public = yes
writable = no
create mode = 0700
[ljet]
security = server
path = /var/spool/lpd/lp
printer name = lp
writable = yes
public = yes
printable = yes
print command = lpr -r -h -P %p %s
确认打印机的路径(本例子中是在[ljet]下)要与 /etc/printcap中的 spool 目录相符合!
注意: 使用 Samba 来共享 UNIX boxes 上的打印机给 Windows NT 机器有一些问题. 其中一个问题是使用 NT 适当地看到共享的打印机. 想要修正这个问题, 请看 Samba 发行套件上的说明, 即 docs/WinNT.txt 文件.其它是处理密码的问题. 对于这扰人问题的了解与不能成功的修正,请看相同文件上的说明.
为了共享 Windows 机器上的打印机, 你必须做以下步骤:
a) 你必须在 /etc/printcap 内有适当的记录,而且他们必须与当地目录结构 (像 spool 目录等) 相符合.
b) 你必须有 script 档 /usr/bin/smbprint. 这会随附在 Samba source, 但不是随附於所有 Samba binary 发行套件. 一个稍微修改版本在以下讨论.
c) 如果你想要转换 ASCII 档到 Postscript,你必须有netscript,或与其等效的. netscipt 是一种 Postscript 转换器而且一般是安装在 /usr/bin.
d) 你可以希望藉由有易於使用的 frond end 来使 Samba 打印更容易. 一种置于处理 ASCII, Postscript 或建立 Postscript 的简单 perl script 在下面给定.
以下 /etc/printcap 项目用在 Windows NT 主机上 HP 5MP 打印机. 这些项目如下:
cm - comment
{ 说明 }
lp - device name to open for output
{ 为了输出,而要开启的设备域名 }
sd - the printer's spool directory (on the local machine)
{ 打印机的 spool 目录 (在当地的机器上) }
af - the accounting file
{ 帐号文件 }
mx - the maximum file size (zero is unlimited)
{ 最大文件大小 (零表示没限制) }
if - name of the input filter (script)
{ 输入过滤之域名 (script) }
要取得更多信息,请看 Printing HOWTO 或者关于 printcap 的 man page.
# /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:
请确定 spool 和 accounting{ 帐号 } 的目录存在且可写入. 请确信某行有适当的路径指到 smbprint script (在下面会给) 而且确定适当的设备被指到 ( /dev 下某个档).
下个是 smbprint script 本身. 它通常被摆在 /usr/bin 而且是因为 Andrew Tridgell 的缘故,而据我所知是他创造了 Samba. 它随附在 Samba source 发行套件, 但在某些 binary 发行套件并没有, 所以在这我再造一个.
你可以希望仔细地看这个. 有某些较小的修改已经证明它们是很有用的.
#!/bin/sh -x
# This script is an input filter for printcap printing on a unix machine. It
# uses the smbclient program to print the file to the specified smb-based
# server and service.
# For example you could have a printcap entry like this
#
# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
#
# which would create a unix printer called "smb" that will print via this
# script. You will need to create the spool directory /usr/spool/smb with
# appropriate permissions and ownerships for your system.
# Set these to the server and service you wish to print to
# In this example I have a WfWg PC called "lapland" that has a printer
# exported called "printer" with no password.
#
# Script further altered by hamiltom at ecnz dot co.nz (Michael Hamilton)
# so that the server, service, and password can be read from
# a /usr/var/spool/lpd/PRINTNAME/.config file.
#
# In order for this to work the /etc/printcap entry must include an
# accounting file (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:
#
# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
# server=PC_SERVER
# service=PR_SHARENAME
# password="password"
#
# E.g.
# 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 script 经由 smbprint 使更容易提供一种简单界面给 linux 的打印.
Usage: print [-a|c|p]
-a printsas ASCII
-c printsformatted as source code
-p printsas Postscript
If no switch is given, print attempts to
guess the file type and print appropriately.
使用 smbprint 来打印 ASCII 文件便於截断过长的行. 如果可能的话,这个 script 截断长行於空白键处(取代在字的中间).
格式化过的源代码是被 nenscript 处理过. 它处理 ASCII 档而且用个特选的标头(像 date,filename等)格式化成两栏. 它也可计算行数. 使用这当作例子, 其它格式格式可以达成的.
Postscript 文件已经适当地格式化了,所以它们直接通过.
#!/usr/bin/perl
# Script: print
# Authors: Brad Marshall, David Wood
# Plugged In Communications
# Date: 960808
#
# Script to print to oreilly which is currently on zimmerman
# Purpose: Takes files of various types as arguments and
# processes them appropriately for piping to a Samba print script.
#
# Currently supported file types:
#
# ASCII - ensures that lines longer than $line_length characters wrap on
# whitespace.
# Postscript - Takes no action.
# Code - Formats in Postscript (using nenscript) to display
# properly (landscape, font, etc).
#
# Set the maximum allowable length for each line of ASCII text.
$line_length = 76;
# Set the path and name of the Samba print script
$print_prog = "/usr/bin/smbprint";
# Set the path and name to nenscript (the ASCII-->Postscript converter)
$nenscript = "/usr/bin/nenscript";
unless ( -f $print_prog ) {
die "Can't find $print_prog!";
}
unless ( -f $nenscript ) {
die "Can't find $nenscript!";
}
&ParseCmdLine( at 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 dot .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 ( at newlines) {
print PRINTER $line;
}
# Send an extra linefeed in case a file has an incomplete last line dot
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 ( at _) {
# print "*$element* \n";
# }
$arg = shift(@_);
if ($arg =~ /\- dot /) {
$cmd = $arg;
# DBG
# print "\$cmd found.\n";
$file = shift( at _);
} else {
$file = $arg;
}
# Defining the file type
unless ($cmd) {
# We have no arguments
if ($file =~ /\ dot 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 "
Usage: print [-a|c|p]
-a prints as ASCII
-c prints formatted as source code
-p prints as Postscript
If no switch is given, print attempts to
guess the file type and print appropriately.\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( at _);
# DBG
#print "Entering subroutine wrap\n";
#print "The line length limit is $limit\n";
# Read in the file, parse and put into an array dot
open(FILE, "<$file") || die "Can't open $file: $!\n";
while() {
$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( at newlines,"$part\n");
} else {
# If it is not, find the last space in the
# sub-line and print up to there dot
# 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( at newlines,substr($part,0,$limit-$index)
dot "\n");
} else {
# There was no space in the line, so
# print it up to $limit.
substr($line,0,$limit) = "";
push( at newlines,substr($part,0,$limit)
dot "\n");
}
}
}
push( at 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) dot
# 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 ( at newlines) {
print FILE $line;
}
close(FILE);
# Read the temporary file back into an array so it can be
# passed to the Samba print script dot
@newlines = ("");
open(FILE, "<$tmpfile") || die "Can't open $file: $!\n";
while() {
push(@newlines,$_);
}
close(FILE);
system("rm $tmpfile");
}
sub createarray {
# Create the array for postscript
open(FILE, "<$file") || die "Can't open $file: $!\n";
while() {
push(@newlines,$_);
}
close(FILE);
}