Następna strona Poprzednia strona Spis treści

9. Udostępnianie drukarki spod Windows komputerom z Linux-em.

Aby udostępnić drukarkę spod Windows-ów musisz zrobić następujące rzeczy:

  1. Musisz mieć poprawne pola w /etc/printcap i muszą one odpowiadać lokalnej strukturze katalogów (katalog dla drukarki itp.)
  2. Musisz mieć skrypt /usr/bin/smbprint. Skrypt ten znajduje się w źródłach Samby, ale nie w każdym pakiecie binarnym. Poniżej znajduje się trochę zmodyfikowana wersja tego skryptu.
  3. Jeśli chcesz zamieniać pliki ASCII na PostScript, musisz mieć nenscript albo jego ekwiwalent. nenscript jest konwerterem PostScript-owym i jest z reguły instalowany w /usr/bin.
  4. Możesz ułatwić drukowanie poprzez Sambę pisząc skrypt. Poniżej podany jest prosty skrypt w Perl-u obsługujący pliki ASCII, PostScript i stworzony PostScript.
  5. Mógłbys też użyć MagicFilter do powyższych zadań. Szczegóły na temat konfiguracji tego filtru są podane za skryptem w perlu. Zaletą tego filtru jest znajomość wielu formatów plików i umiejętność ich konwersji.

Poniższe pola w /etc/printcap są dla drukarki HP 5MP dołączonej do komputera z Windows NT.


     cm - komentarz; lp - urządzenie, na które ma być wysłany wydruk;
     sd - katalog zadań dla drukarki (na lokalnym komputerze); af -
   katalog accounting; mx - maksymalny rozmiar pliku (0 - bez
   ograniczenia); if - nazwa filtru wejściowego (skryptu).

Więcej informacji znajdziesz w Printing-HOWTO lub w podręczniku systemowym dla "printcap".


 etc/printcap
   #
   # //zimmerman/oreilly przez smbprint
   #
   lp:\ cm=HP 5MP Postscript OReilly na zimmerman:\ lp=/dev/lp1:\
           :sd=/var/spool/lpd/lp:\ af=/var/spool/lpd/lp/acct:\ mx#0:\
           :if=/usr/bin/smbprint:

Upewnij się, że katalogi zadań i zliczania (accounting) istnieją i są zapisywalne oraz że if ma poprawną ścieżkę do scryptu smbprint (patrz poniżej) i że lp wskazuje poprawne urządzenie (plik specjalny w katalogu /dev)

Następnym krokiem jest skrypt smbprint. Zwykle znajduje się on w /usr/bin i jest przypisywany Andrew Tridgellowi - osobie, która stworzyła Sambę o ile wiem. Przychodzi on wraz z dystrybucją źródeł Samby, ale nie ma go w dystrybucji binariów, więc go tutaj stworzyłem.

Możesz przejrzeć go dokładniej. Przerobiłem go trochę, ponieważ przeróbki wydawały mi się użyteczne.


   #!/bin/sh
   # Skrypt ten jest filtrem wejściowym do drukowania na drukarce
   # dołączonej do Unix-a. Używa programu smbclient do drukowania
   # pliku. Na przykład twój printcap mógłby wyglądać nastepująco:
   #
   #
   # smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
   #
   #
   # Stworzyłby on drukarkę o nazwie smb, która drukowałaby poprzez
   # ten skrypt. Musiałbyś stworzyć katalog zadań /usr/spool/smb z
   # odpowiednimi dla twojego systemu prawami dostępu i właścicielem.
   # 
   # Ustaw następujące rzeczy na serwer i serwis przez, który chcesz
   # drukować. W tym przykładzie mam PC-ta z WfWg o nazwie "lapland",
   # który ma drukarkę o nazwie printer bez hasła.
   #
   #
   # W dalszej części skrypt został przerobiony przez hamilton@ecnz.co.nz
   # (Michael Hamilton, tak aby serwer, serwis i hasło mogły być
   # przeczytane z pliku /usr/var/spool/lpd/PRINTNAME/.config
   #
   # Aby to działało /etc/printcap musi mieć pole 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:
   #
   # Plik /usr/var/spool/lpd/PRINTNAME/.config powinien zawierać:
   #   server=PC_SERVER service=PR_SHARENAME password="password"
   #
   # Np. server=PAULS_PC service=CJET_371 password=""

   #
   # Plik, do którego mają byc zapisywane wiadomości ze śledzenia;
   # możesz zmienić na /dev/null jeśli chcesz:
   #
   logfile=/tmp/smb-print.log logfile=/dev/null


   #
   # Ostatnim parametrem do filtra jest nazwa pliku accounting.
   #
   spool_dir=/var/spool/lpd/lp config_file=$spool_dir/.config

   # Powinien czytać te zmienne z pliku konfiguracyjnego: serwer
   # serwis hasło użytkownik
   eval `cat $config_file`

   # Trcohę pomocy, zmień >> na > jeśli chcesz zachować trochę
   # miejsca na dysku.
   #
   echo "server $server, service $service" >> $logfile

   (UWAGA Możesz dodać linię `echo translate' jesli chcesz
   # automatycznego tłumaczenia CR/LF podczas drukowania.   
        echo translate echo "print -" cat
   ) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $user
   -N -P >>
   $logfile

Większość dystrybucji Linux-owych posiada nenscript do zamiany dokumentów ASCII na PostScript. Następujący skrypt w Perl-u ułatwia życie stwarzając prosty interfejs dla drukowania w Linux-ie przez smbprint.


     Stosowanie: print [-a|c|p] <nazwa_pliku>
     -a drukuje <nazwa_pliku> jako ASCII; c drukuje <nazwa_pliku>
     sformatowane jako źródło; -code p drukuje <nazwa_pliku> jako
     PostScript.
     Jeśli nie ma żadnej opcji, print próbuje odgadnąć typ pliku i
    odpowiednio go wydrukować.

Użycie smbprint do drukowania plików ASCII powoduje obcinanie długich linii. Ten skrypt dzieli długie linie w miejscu spacji (zamiast w środku słowa) jeśli jest to możliwe.

Formatowanie źródła odbywa sie przy pomocy programu nenscript. Bierze on plik ASCII i formatuje go w dwie kolumny z dodatkowym nagłówkiem (data, nazwa pliku, itp.) Zlicza także ilość linii. Wzorując się na tym przykładzie możesz zrobić inne typy formatowania.

Dokumenty PostScript-owe są już sformatowane więc przechodzą bezpośrednio do drukarki.


 usr/bin/perl

# Skrypt:   print Autorzy: Brad Marshall, David Wood
#           Plugged In Communications Date: 960808
#
# Skrypt do drukowania na drukarce oreilly, która jest dołączona do
# komputera zimmerman. Opis działania: Jako argumenty przyjmuje pliki
# różnych typów i wysyła je odpowiednio do skryptu drukujacego Samby
#
# Obecnie obsługiwane typy plików:
#
# ASCII         - Upewnij się, że linie dłuższe niż $line_length zostały
#               podzielone w miejscu spacji.
# PostScript    - Nie robi nic.
# Code          - Formatuje na PostScript używając "nenscript", aby wszystko
#               było odpowiednio wyświetlone (ułożenie, czcionki, itd.)
#
#
# Ustaw maksymalną ilość znaków w linii dla plików ASCII. line_length
$= 76;

# Ustaw ścieżkę i nazwę skryptu drukującego Samby print_prog = 
$"/usr/bin/smbprint";

# Ustaw ścieżkę i nazwę "nenscript-u" (zamiana 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") { ero;wrap($line_length); elsif ($filetype eq
        &"code") {
} ero;codeformat; elsif ($filetype eq "ps") {
        &createarray; else {
} print "Sorry..no known
        &file type.\n"; exit
} 0;
}
# Wyślij tablcę do smbprint open(PRINTER, "|$print_prog") || die "Can't
open $print_prog: $!\n"; foreach
$line (@newlines) {
        print PRINTER $line;
}
# Wyślij dodatkowy znak LF jeśli plik ma niekompletną ostatnią linię. print
PRINTER "\n"; close(PRINTER); print "Completed\n"; exit 0;

# --------------------------------------------------- #
#        Wszystko poniżej jest procedurą              #
# --------------------------------------------------- #

sub ParseCmdLine { Interpretuje wiersz poleceń, szukając jakiego typu jest
        # plik

        # Gets $arg and $file to be the arguments (if they exists) and the
        # filename
        if ($#_ < 0) { ero;usage;
        }
        # DBG foreach $element (@_) { print "*$element* \n";
#       }

        $arg = shift(@_); if ($arg =~ /\-./) { cmd = $arg; DBG print "\$cmd
        found.\n";

                $file = shift(@_); else { file = $arg;
        }
        
        # Definiowanie typu pliku dopóki ($cmd) { Nie mamy argumentów

                if ($file =~ /\.ps$/) { filetype = "ps"; elsif ($file =~
                        $/\.java$|\.c$|\.h$|\.pl$|\.sh$|\.csh$|\.m4$|\.inc$|\.html$|\.htm$/)
                        ${ filetype = "code"; else { filetype = "ASCII";
                }

                # Przerób $file odpowiednio do jego typu i zwróć $filetype
        } else { Mamy typ pliku w $arg if ($cmd =~ /^-p$/) {
                filetype = "ps"; elsif ($cmd =~
                        $/^-c$/) { filetype
                } = "code"; elsif ($cmd =~
                        $/^-a$/) {
                } filetype = "ASCII"
                }
        }
}

sub usage { print " Stosowanie: print [-a|c|p] <plik>
       -a drukuje <plik> jako ASCII c drukuje <plik> sformatowany jako
         źródło
       -code p drukuje <plik> jako PostScript
        Jeśli nie ma żadnej opcji, print próbuje odgadnąć typ pliku i
        odpowiednio go wydrukować.\n
";
        exit(0);
}

sub wrap { Stwórz tablicę linii w pliku, gdzie każda linia jest krótsza od
        # podanej ilości znaków i jest podzielona tylko w miejscach spacji

        # Pobierz ilość znaków jaka może być w linii.  limit =
        $pop(@_);

        # DBG print "Entering subroutine wrap\n"; print "The line length
        #limit is $limit\n";

        # Wczytaj plik, sformatuj i umieść w tablicy.  open(FILE,
        "<$file") || die "Can't open $file: $!\n"; while(<FILE>) {
                $line = $_;
                
                # DBG print "The line is:\n$line\n";

                # Podziel linię jeśli jest dłuższa niż podana ilość znaków.  while (
                length($line) > $limit ) {
                        
                        # DBG print "Wrapping...";

                        # Pobierz pierwsze $limit+1 znaków.  part =
                        $substr($line,0,$limit +1);

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

                        # Sprawdź czy ostatni znak jest spacją. 
                        $last_char = substr($part,-1, 1);
                        if ( " " eq $last_char ) { Jeśli tak, wydrukuj resztę.

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

                            substr($line,0,$limit + 1) = "";
                            substr($part,-1,1) = "";
                            push(@newlines,"$part\n");
                        } else { Jeśli nie, znajdź ostatnią spację w
                                # pod-linii i drukuj do niej

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

                             # Usuń znaki dalsze niż $limit
                             substr($part,-1,1) = ""; Odwróć linię
                             # aby ułatwić odnajdywanie ostatniej spacji
                             $revpart = reverse($part);
                             $index = index($revpart," ");
                             if ( $index > 0 ) {
                               substr($line,0,$limit-$index) = "";
                               push(@newlines,substr($part,0,$limit-$index)
                                   . "\n"); else { Nie było spacji w linii
                             } więc
                               # wydrukuj do $limit.
                               substr($line,0,$limit) = "";
                               push(@newlines,substr($part,0,$limit)
                                   . "\n");
                             }
                        }
                }
                push(@newlines,$line);
        }
        close(FILE);
}

sub codeformat { Wywołaj procedurę wrap i przefiltruj przez nenscript
        &wrap($line_length);
        
        # Przepuść wynik przez nenscript, aby utworzyć plik PostScript,
        # który pasuje do jakiegoś przyzwoitego formatu źródeł do drukowania
        # (ułożenie, czcionki Courier, ilość linii). Najpierw wydrukuj to do
        # pliku tymczasowego.
        $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);
        
        # Wczytaj plik tymczasowy spowrotem do tablicy, tak aby mógł być
        # wysłany do skryptu print Samby.
        @newlines = ("");
        open(FILE, "<$tmpfile") || die "Can't open $file: $!\n";
        while(<FILE>) {
                push(@newlines,$_);
        }
        close(FILE); system("rm $tmpfile");
}

sub createarray { Stwórz tablicę dla PostScript-u open(FILE, "<$file") ||
        # die "Can't
        open $file: $!\n"; while(<FILE>) {
                push(@newlines,$_);
        }
        close(FILE);
}

Teraz sposób z MagicFilter. Dziękuję za tę informację Alberto Menegazzi ( flash.egon@iol.it).

Alberto pisze:

--------------------------%<----------------------------------

1) Zainstaluj MagicFilter dla odpowiednich drukarek w /usr/bin/local/, ale nie umieszczaj w /etc/printcap tego co sugeruje dokumentacja do tego filtru.

2) Utwórz plik /etc/printcap na podobieństwo tego poniżej (to jest konfiguracja dla mojej drukarki 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:

Powinieneś wiedzieć, że lp=/dev/... otwierane jest z lokowaniem, tak więc powinny być używane virtualne urządzenia; jedno dla każdej odległej drukarki.

Np. stworzone przez 'touch /dev/ljet4l'.

3) Stwórz filtr /usr/local/bin/main-filter jak poniżej:


#! /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. Oto cytat z mini-HOWTO Print2Win na temat lokowania i po co tworzyć wirtaulne drukarki.

---Początek cytatu

Wskazówka od Ricka Bresslera:

Dobra rada. Ja używam czegoś bardzo podobnego. Jedna pomocna wskazówka, to poniżej nie jest dobrym pomysłem:


        :lp=/dev/null:\

lpr otwiera plik podany w ustawieniu lp= na wyłączność. Robi tak, żeby zapobiec zapisywaniu przez wiele procesów do tej samej drukarki w tym samym czasie.

Ubocznym efektem tego jest, że w twoim przypadku 'eng' i 'colour' nie mogą drukować w tym samym czasie (zwykle mniej lub bardziej przezroczyste, ponieważ będą raczej drukowały szybko no i jest też kolejka. Tak że nie powinieneś niczego zauważyć). Ale każdy inny proces, który spróbuje zapisać do /dev/null przerwie działanie.

W systemie jednoużytkownikowym nie jest to problem. Ja mam system z 50. drukarkami - i tam byłby to problem.

Rozwiązaniem jest stworzenie fałszywej drukarki dla każdej. Np. 'touch /dev/eng'.

Zmodyfikowałem pola w pliku /etc/printcap powyżej i wziąłem pod uwagę sugestie Ricka. Wykonałem te dwa polecenia:


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

---Koniec cytatu

--------------------------%<----------------------------------


Następna strona Poprzednia strona Spis treści