1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<title>Print Job Filters</title>
<meta name="GENERATOR" content=
"Modular DocBook HTML Stylesheet Version 1.71 ">
<link rel="HOME" title=" LPRng-HOWTO" href="index.htm">
<link rel="UP" title="Print Spooling Tutorial " href=
"tutorial.htm">
<link rel="PREVIOUS" title="Job Removal" href="jobremoval.htm">
<link rel="NEXT" title=
"Job File Format Conversion with Filters" href=
"jobfileformatconversion.htm">
</head>
<body class="SECT1" bgcolor="#FFFFFF" text="#000000" link=
"#0000FF" vlink="#840084" alink="#0000FF">
<div class="NAVHEADER">
<table summary="Header navigation table" width="100%" border=
"0" cellpadding="0" cellspacing="0">
<tr>
<th colspan="3" align="center">LPRng-HOWTO: 1 Apr 2002
(For LPRng-3.8.10)</th>
</tr>
<tr>
<td width="10%" align="left" valign="bottom"><a href=
"jobremoval.htm" accesskey="P">Prev</a></td>
<td width="80%" align="center" valign="bottom">Chapter 4.
Print Spooling Tutorial</td>
<td width="10%" align="right" valign="bottom"><a href=
"jobfileformatconversion.htm" accesskey="N">Next</a></td>
</tr>
</table>
<hr align="LEFT" width="100%">
</div>
<div class="SECT1">
<h1 class="SECT1"><a name="PRINTJOBFILTERS">4.9. Print Job
Filters</a></h1>
<p>A printer usually understands one or more <i class=
"EMPHASIS">Print Job Languages</i>. Files sent to this
printer must be in one of these languages and have the
appropriate <i class="EMPHASIS">job format</i>. The most
common Print Job Languages are <a href=
"x290.htm#POSTSCRIPT">PostScript</a> and <a href=
"x290.htm#PCL">PCL</a>. Text files are PCL with no special
PCL control sequences.</p>
<p>In order for a printer to reliably print a job it needs to
be reset to a known configuration and then at the end of job
having it flush all of the output to the printing device.
This is done by sending it <i class="EMPHASIS">start of
job</i> and <i class="EMPHASIS">end of job</i> commands.
These commands differ from printer to printer and depend on
the print job language as well. Some <i class=
"EMPHASIS">vintage</i> line printers also have a set of
proprietary <i class="EMPHASIS">escape sequences</i> that are
used to set up margins, form size, and other printing
characteristics. Usually a <i class="EMPHASIS">setup
string</i> with these escape sequences must be sent to the
printer before a file can be printed.</p>
<p>When sending a job to the printer the print spooler will
first process the job using a <i class="EMPHASIS">print job
filter</i> or <i class="EMPHASIS">filter</i> program. This
program reads the job file and then produces output in the
format required for the printer.</p>
<p>When a print job is created the files in the print job are
assigned a <i class="EMPHASIS">format</i>. This format was
meant as a guide to the print spooler and was to be used to
select the filter program for the files in the job. The
format was a lower case letter; the <tt class=
"LITERAL">f</tt> is the de<tt class="LITERAL">f</tt>ault
format and indicates normal processing and the <tt class=
"LITERAL">l</tt> format indicates a literal or binary file.
Job files that are flagged as having literal or binary format
are usually passed directly to the printer or have at the
most a minimal amount of processing. See <a href=
"printjobformats.htm">Print Job Formats</a> for more
information about formats and their use with filters.</p>
<p>There are two ways to specify filters: the default <tt
class="LITERAL">:filter=...</tt> option and the more specific
<tt class="LITERAL">Xf=...</tt> option. The <tt class=
"LITERAL">X</tt> is a lower case letter corresponding to a
format. Here is a sample printcap entry with a filter
specification:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2147"></a>
<pre class="SCREEN">
lp:sd=/var/spool/lpd/%P
:filter=/usr/local/lib/filters/ifhp
:rf=/usr/local/lib/filters/rfilter
</pre>
</div>
All jobs with formats other than <tt class="LITERAL">r</tt>
will be processed using the <tt class="LITERAL">ifhp</tt>
program while the jobs with the <tt class="LITERAL">r</tt>
format will be processed using the <tt class=
"LITERAL">rfilter</tt> program.<br>
<br>
<p>We will set up a very simple filter and use it to
demonstrate how filtering is done by the <b class=
"APPLICATION">lpd</b> print spooler. First, set up the <tt
class="FILENAME">/tmp/testf</tt> file as shown below.</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2156"></a>
<pre class="SCREEN">
#!/bin/sh
# /tmp/testf - test filter for LPRng
PATH=/bin:/usr/bin; export PATH
echo TESTF $0 "$@" >&2
echo TESTF $0 "$@"
echo ENV
set
echo LEADER
/bin/cat
echo TRAILER
exit 0
</pre>
</div>
<br>
<br>
<p>Let us carefully examine the script line by line. The
first couple of lines are <i class=
"EMPHASIS">boilerplate</i>. You should <i class=
"EMPHASIS">always</i> set the <tt class="ENVAR">PATH</tt>
value in a filter script or use full pathnames for executable
programs. This is a good practice as it ensures that only the
specified directories will be searched for commands.</p>
<p>The next lines echo the command line arguments to file
descriptor 2 (<span class="ACRONYM">STDERR</span>) and to
<span class="ACRONYM">STDOUT</span>. We will soon see how
this information is displayed by the <b class=
"APPLICATION">LPRng</b> software. We then use the <tt class=
"COMMAND">set</tt> command to list the shell variables to
<span class="ACRONYM">STDOUT</span>, print <span class=
"ACRONYM">LEADER</span> to <span class=
"ACRONYM">STDOUT</span>, copy <span class=
"ACRONYM">STDIN</span> to <span class=
"ACRONYM">STDOUT</span>, and print <span class=
"ACRONYM">TRAILER</span> to <span class=
"ACRONYM">STDOUT</span>. We exit with a zero result code.</p>
<p>We can test our script, with the results shown below:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2175"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {163} %</tt> <tt class=
"USERINPUT"><b>chmod 755 /tmp/testf</b></tt>
<tt class="PROMPT">h4: {164} %</tt> <tt class=
"USERINPUT"><b>echo hi |/tmp/testf -a1</b></tt>
TESTF /tmp/testf -a1
TESTF /tmp/testf -a1
ENV
USER=papowell
HOSTNAME=h4
...
PATH=/bin:/usr/bin
LEADER
hi
TRAILER
</pre>
</div>
<br>
<br>
<p>Let's now use this filter. Edit the <tt class=
"LITERAL">lp</tt> printcap entry so it has contents indicated
below, use <tt class="COMMAND">checkpc -f</tt> to check the
printcap, and then use <tt class="COMMAND">lpc reread</tt> to
restart the <b class="APPLICATION">lpd</b> server.</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2186"></a>
<pre class="SCREEN">
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter=/tmp/testf
</pre>
</div>
<br>
<br>
<p>Execute the following commands to print the <tt class=
"FILENAME">/tmp/hi</tt> file and observe the results:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2190"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {165} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {166} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {167} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
Queue: no printable jobs in queue
Status: lp@h4.private: job 'papowell@h4+26593' printed at 21:37:21.312
Status: job 'papowell@h4+26593' removed at 21:37:21.323
Status: subserver pid 26683 starting at 21:39:21.908
Status: accounting at start at 21:39:21.908
Status: opening device '/tmp/lp' at 21:39:21.909
Status: printing job 'papowell@h4+26681' at 21:39:21.909
Status: no banner at 21:39:21.909
Status: printing data file 'dfA026681h4.private', size 3, \
IF filter 'testf' at 21:39:21.909
Status: IF filter msg - 'TESTF /tmp/testf -Apapowell@h4+26681 \
-CA -D2000-04 -11-21:39:21.877 -Ff -Hh4.private -J/tmp/hi \
-Lpapowell -Plp -Qlp -aacct -b3 -d/var/tmp/LPD/lp \
-edfA026681h4.private -f/tmp/hi -hh4.private -j026681 \
-kcfA026681h4.private -l66 -npapowell -sstatus \
-t2000-04-11-21:39:21.000 -w80 -x0 -y0 acct' \
at 21:39:21.914
Status: IF filter finished at 21:39:22.070
Status: printing done 'papowell@h4+26681' at 21:39:22.070
Status: accounting at end at 21:39:22.070
Status: finished 'papowell@h4+26681', status 'JSUCC' at 21:39:22.070
Status: subserver pid 26683 exit status 'JSUCC' at 21:39:22.072
Status: lp@h4.private: job 'papowell@h4+26681' printed at 21:39:22.072
Status: job 'papowell@h4+26681' removed at 21:39:22.085
<tt class="PROMPT">h4: {168} %</tt> <tt class=
"USERINPUT"><b>more /tmp/lp</b></tt>
TESTF /tmp/testf -Apapowell@h4+26681 -CA -D2000-04-11-21:39:21.877 \
-Ff -Hh4.private -J/tmp/hi -Lpapowell -Plp -Qlp -aacct -b3 \
-d/var/tmp/LPD/lp -edfA026681h4.private -f/tmp/hi -hh4.private \
-j026681 -kcfA026681h4.private -l66 -npapowell -sstatus \
-t2000-04-11-21:39:21.000 -w80 -x0 -y0 acct
ENV
USER=papowell
LD_LIBRARY_PATH=/lib:/usr/lib:/usr/5lib:/usr/ucblib
HOME=/home/papowell
PRINTCAP_ENTRY=lp
:force_localhost
:filter=/tmp/testf
:lp=/var/tmp/lp
:sd=/var/tmp/LPD/lp
PS1=$
OPTIND=1
PS2=>
SPOOL_DIR=/var/tmp/LPD/lp
LOGNAME=papowell
CONTROL=Hh4.private
Ppapowell
J/tmp/hi
CA
Lpapowell
Apapowell@h4+15850
D2000-04-26-18:13:55.505
Qlp
N/tmp/hi
fdfA015850h4.private
UdfA015850h4.private
PATH=/bin:/usr/bin
SHELL=/bin/sh
LOGDIR=/home/papowell
IFS=
PRINTER=lp
LEADER
test Test
TRAILER
</pre>
</div>
<br>
<br>
<p>The <tt class="COMMAND">cp</tt> command clears out the <tt
class="FILENAME">/tmp/lp</tt> file we are using as a dummy
output device. The <tt class="COMMAND">lpr</tt> command
prints the <tt class="FILENAME">/tmp/hi</tt> file and the <tt
class="COMMAND">lpq -llll</tt> command shows the status
information. The status information now contains the line
that the <tt class="COMMAND">testf</tt> script wrote to <span
class="ACRONYM">STDERR</span>. The <b class=
"APPLICATION">lpd</b> server captures filter <span class=
"ACRONYM">STDERR</span> messages and puts it them in the
spool queue status file.</p>
<p>As we see from the lpq status, <b class=
"APPLICATION">lpd</b> passes a large number of command line
options to our filter. These options and their meanings are
discussed in detail in <a href="filteroptions.htm">Filter
Command Line Options and Environment Variables</a>. We will
discuss these in more detail in the next section.</p>
<p>If we look at the <tt class="FILENAME">/tmp/lp</tt> file,
we see the command line options and values of the shell
variables. For a full discussion of the environment variables
passed to a filter see <a href="filteroptions.htm">Filter
Command Line Options and Environment Variables</a>. The more
interesting environment variables include the <tt class=
"ENVAR">PRINTCAP_ENTRY</tt> variable, which is a copy of the
printcap entry for this printer, and the <tt class=
"ENVAR">CONTROL</tt> variable, which is a copy of the control
file for the the print job.</p>
<div class="SECT2">
<h2 class="SECT2"><a name="CONTROLFILES">4.9.1. Control
Files and Filter Options</a></h2>
<p>When you submit a print job the <b class=
"APPLICATION">lpd</b> print spooler stores it in the spool
queue as two or more files: a <i class=
"EMPHASIS">control</i> file that contains information about
the job and the <i class="EMPHASIS">data</i> files that
contain the information to be printed. Here is sample
control file:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2224"></a>
<pre class="SCREEN">
Hh4.private
Ppapowell
J/tmp/hi
CA
Lpapowell
Apapowell@h4+15850
D2000-04-26-18:13:55.505
Qlp
N/tmp/hi
fdfA015850h4.private
UdfA015850h4.private
</pre>
</div>
<br>
<br>
<p>Lines starting with upper case letters contain job
information such as the user who submitted the job. Lines
starting with lower case letters indicate the data file to
be printed and the corresponding format. For full details
about the exact format of the control file see <a href=
"jobfiles.htm">Job Files</a>.</p>
<p><a href="printjobfilters.htm#FILTEROPTIONSTABLE">Table
4-1</a> shows the correspondence between lines in the
control file and <b class="APPLICATION">lpr</b> command
line options. The <tt class="LITERAL">N</tt> values are the
names of the files that are printed. The <tt class=
"LITERAL">U</tt> indicates a data file is in a job and is
present to meet RCF1179 and <i class="EMPHASIS">vintage</i>
print spooler requirements.</p>
<div class="TABLE">
<a name="FILTEROPTIONSTABLE"></a>
<p><b>Table 4-1. Filter Options</b></p>
<table border="1" class="CALSTABLE">
<thead>
<tr>
<th align="LEFT" valign="TOP">Control File</th>
<th align="LEFT" valign="TOP">Filter Option</th>
<th align="LEFT" valign="TOP">Purpose or Value</th>
</tr>
</thead>
<tbody>
<tr>
<td align="LEFT" valign="TOP"> </td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-P</tt><i class=
"EMPHASIS">Printer</i></td>
<td align="LEFT" valign="TOP">Print queue name -
printcap information</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><i class=
"EMPHASIS">H</i></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-H</tt><i class="EMPHASIS">Host</i></td>
<td align="LEFT" valign="TOP">Host Name</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">P</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-n</tt><i class="EMPHASIS">User</i></td>
<td align="LEFT" valign="TOP">User Login Name of
job originator</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">J</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-J</tt><i class="EMPHASIS">Job
name</i></td>
<td align="LEFT" valign="TOP">lpr -J option or file
name</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">C</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-C</tt><i class="EMPHASIS">Class</i></td>
<td align="LEFT" valign="TOP">Print class (lpr -C
option)</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">L</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-L</tt><i class=
"EMPHASIS">Banner</i></td>
<td align="LEFT" valign="TOP">Banner page
request</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">A</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-A</tt><i class="EMPHASIS">Jobid</i></td>
<td align="LEFT" valign="TOP">Job Id</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">D</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-D</tt><i class="EMPHASIS">Date</i></td>
<td align="LEFT" valign="TOP">Date or time
information</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">Q</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-Q</tt><i class="EMPHASIS">Queue</i></td>
<td align="LEFT" valign="TOP">Original Print queue
job was sent to</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">N</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-N</tt><i class=
"EMPHASIS">Filename</i></td>
<td align="LEFT" valign="TOP">Filename</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">f,l,p,...</tt></td>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">-F</tt><i class="EMPHASIS">f</i></td>
<td align="LEFT" valign="TOP">Datafile format</td>
</tr>
<tr>
<td align="LEFT" valign="TOP"><tt class=
"LITERAL">U</tt></td>
<td align="LEFT" valign="TOP"> </td>
<td align="LEFT" valign="TOP">Datafile
(historical)</td>
</tr>
</tbody>
</table>
</div>
<p>When a print filter processes these jobs the values in
the control file are passed on the command line as options
starting with upper case letters:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2325"></a>
<pre class="SCREEN">
/tmp/testf -Apapowell@h4+26681 -CA \
-D2000-04-11-21:39:21.877 -Ff -Hh4.private ....
</pre>
</div>
Sometimes we want to pass only a small subset of these
command line options to a filter or provide them in a
specific order in order to be compatible with <i class=
"EMPHASIS">legacy</i> print filters. <b class=
"APPLICATION">LPRng</b> provides several different ways to
do this and we will explore how to control command line
options.<br>
<br>
<p>If the filter entry starts with <tt class=
"LITERAL">-$</tt>, this suppresses the automatic addition
of command line options; we can then add our own options to
the command line. Modify the printcap entry to have the
following form:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2331"></a>
<pre class="SCREEN">
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter= -$ /tmp/testf '$P' $0P -X$-P ${lp} G\072 or \:
</pre>
</div>
<br>
<br>
<p>Lets print our <tt class="FILENAME">/tmp/hi</tt> test
file and then look at the <b class="APPLICATION">lpq</b>
status:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2336"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {169} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {170} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {171} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
....
Status: IF filter msg - 'TESTF /tmp/testf -Plp -P lp -Xlp \
-Ylp /tmp/lp G: or :' at 01:20:21.560
</pre>
</div>
<br>
<br>
<p>The <tt class="LITERAL">-$</tt> suppresses the adding
the default literals to the filter command line. You can
pass specific options using <tt class="LITERAL">$X</tt>; if
the option has a non-null value then it will be expanded in
the following format:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2347"></a>
<pre class="SCREEN">
Option Value Expansion
$X -X<value>
$0X -X <value>
$-X <value>
${name} printcap option value if value nonzero length
\nnn single printable character
$* all options expanded using $X
</pre>
</div>
<br>
<br>
<p>Command line options can be grouped and passed as a
single argument by enclosing them in single or double
quotes. You should be aware that <b class=
"APPLICATION">LPRng</b> has an <i class=
"EMPHASIS">extremely</i> primitive way of handling quotes.
When the <tt class="COMMAND">/bin/sh -c</tt> parameter is
not used, the the command line is broken on spaces and each
unit is passed as an individual argument. If the first
character after a space is a quote (single or double), the
next quote is found, and then entire element is then used
as a single parameter. Substitution of <tt class=
"LITERAL">$X</tt> parameters is then done. As a special
case, when you have a <tt class="LITERAL">$0X</tt>, this
causes a split and all of the string previous and including
the <tt class="LITERAL">-X</tt> flag is passed as a single
option and all of the option value and following are passed
as another option. If the result of the expansion is a zero
length parameter then it is removed from the parameter
list. When the <tt class="COMMAND">/bin/sh -c</tt> is used
the command line is not broken, and all non-empty option
values are enclosed in single quotes.</p>
<p>The <tt class="LITERAL">${name}</tt> option is used to
pass a printcap option value. For example, you can pass the
value of the printcap option <tt class="LITERAL">form</tt>
as shown below. You can experiment with this by using the
<tt class="FILENAME">/tmp/testf</tt> filter and printcap
shown below.</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2361"></a>
<pre class="SCREEN">
printcap:
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter=/tmp/testf -F ${form}
:form=payroll
<tt class="PROMPT">h4: {172} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {173} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {174} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
...
Status: IF filter msg - 'TESTF /tmp/testf -F payroll' at 09:55:31.276
...
</pre>
</div>
<br>
<br>
<p>If we have a <i class="EMPHASIS">legacy</i> print filter
that was originally written for the <span class=
"ACRONYM">BSD</span> print spooler, then we may find that
it requires a small number of command line options in a
very specific order. We can use the <tt class=
"LITERAL">:bkf</tt> (BSD Kompatible Filter or BacKwards
compatible Filter) flag to pass suitable options. Modify
the printcap entry to have the following form:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2373"></a>
<pre class="SCREEN">
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter=/tmp/testf
:bk
</pre>
</div>
<br>
<br>
<p>Lets print our <tt class="FILENAME">/tmp/hi</tt> test
file and then look at the <b class="APPLICATION">lpq</b>
status:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2378"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {175} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {176} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {177} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
....
Status: IF filter msg - 'TESTF /tmp/testf -Plp -w80 -l66 \
-x0 -y0 -Ff -Lpapowell -J/tmp/hi -CA -n papowell \
-h h4.private acct' at 08:07:46.583
</pre>
</div>
<br>
<br>
<p>Finally, there are times when we would like the print
filter to be a simple shell command or to chain several
programs together in a simple pipeline. While this is
possible using a print filter, you can also do this in the
filter specification. If your filter specification starts
with a parenthesis (<tt class="LITERAL">(</tt>) or contains
the IO redirection for pipeto (<tt class="LITERAL">|</tt>),
input redirection (<tt class="LITERAL"><</tt>), or
output redirection (<tt class="LITERAL">></tt>) then the
<b class="APPLICATION">lpd</b> server will use the <tt
class="LITERAL">:shell</tt> configuration option value
(default <tt class="FILENAME">/bin/sh</tt>) and execute it
using:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2394"></a>
<pre class="SCREEN">
${shell} -c "( ${if} )"
</pre>
</div>
<br>
<br>
<p>If this is done, then no command line options are added
to the command. However, expansion of <tt class=
"LITERAL">$X</tt> parameters are still done. Modify the
printcap entry to have the following form:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2398"></a>
<pre class="SCREEN">
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter=(echo "PREAMBLE"; /tmp/testf; echo "APPENDIX")
</pre>
</div>
<br>
<br>
<p>Lets print our <tt class="FILENAME">/tmp/hi</tt> test
file and then look at the <b class="APPLICATION">lpq</b>
status:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2403"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {178} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {179} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {180} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
....
Status: printing data file 'dfA018881h4.private', size 3, \
IF filter 'echo' at 09:22:11.476
Status: IF filter msg - 'TESTF /tmp/testf' at 09:22:11.510
Status: IF filter finished at 09:22:11.514
</pre>
</div>
<br>
<br>
<p>If we examine the <tt class="FILENAME">/tmp/lp</tt> file
we find:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2413"></a>
<pre class="SCREEN">
PREAMBLE
TESTF /tmp/testf
ENV
USER=papowell
LD_LIBRARY_PATH=/lib:/usr/lib:/usr/5lib:/usr/ucblib
...
PRINTER=lp
LEADER
hi
TRAILER
APPENDIX
</pre>
</div>
<br>
<br>
<p>As we expected, no options were passed on the command
line. If the printcap is modified to have the following
contents, then you will see:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2416"></a>
<pre class="SCREEN">
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter=(echo "PREAMBLE"; /tmp/testf $*; echo "APPENDIX")
<tt class="PROMPT">h4: {181} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {182} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
....
Status: IF filter msg - 'TESTF /tmp/testf -Apapowell@h4+18941 \
-CA -D2000-04-29-09:27:30.700 -Ff -Hh4.private -J/tmp/hi \
-Lpapowell -Plp -Qlp -aacct -b3 -d/var/tmp/LPD/lp \
-edfA018941h4.private -f/tmp/hi -hh4.private -j018941 \
-kcfA018941h4.private -l66 -npapowell -sstatus \
-t2000-04-29-09:27:30.864 -w80 -x0 -y0 acct' at 09:27:30.879
</pre>
</div>
<br>
<br>
<p>Using the shell invocation is especially useful when you
may have a parameter that has an empty string value, and
need to pass this as a command line parameter. Modify the
<tt class="FILENAME">/tmp/testf</tt> filter, the printcap,
and execute the following commands:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2424"></a>
<pre class="SCREEN">
printcap:
lp:sd=/var/spool/lpd/%P
:force_localhost
:lp=/tmp/lp
:filter=( /tmp/testf -F '${form}' )
:form=
#!/bin/sh
# /tmp/testf - test filter for LPRng
PATH=/bin:/usr/bin; export PATH
echo TESTF $0 "$@" >&2
echo TESTF $0 "$@"
while test $# -gt 0 ; do
echo "PARM '$1'";
shift;
done
echo LEADER
/bin/cat
echo TRAILER
exit 0
<tt class="PROMPT">h4: {183} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {184} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {185} %</tt> <tt class=
"USERINPUT"><b>lpq -llll</b></tt>
Printer: lp@h4
...
Status: IF filter msg - 'TESTF /tmp/testf -F' at 09:59:27.365
<tt class="PROMPT">h4: {186} %</tt> <tt class=
"USERINPUT"><b>more /tmp/lp</b></tt>
TESTF /tmp/testf -F
PARM '-F'
PARM ''
LEADER
hi
TRAILER
</pre>
</div>
<br>
<br>
<p>As you can see, there are <i class="EMPHASIS">empty</i>
parameters passed to the filter. This is due to the
combination of the <tt class="LITERAL">$'{form}</tt> and
using the <tt class="LITERAL">:filter=(...)</tt> form.</p>
</div>
<div class="SECT2">
<h2 class="SECT2"><a name="FILTERENVIRONMENTVARS">4.9.2.
Filter Environment Variables</a></h2>
<p>In this section we will look further at the environment
variables passed to the filter. We printed the shell
variable values for the filter at the start of the
file:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2441"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {187} %</tt> <tt class=
"USERINPUT"><b>cat /tmp/lp</b></tt>
/tmp/testf -Plp -P lp -Xlp -Ylp /tmp/lp G:' at 01:20:21.560
ENV
CONTROL=Hh4.private
Ppapowell
J/tmp/hi
CA
Lpapowell
Apapowell@h4+105
D2000-04-12-15:27:26.662
Qlp
N/tmp/hi
fdfA105h4.private
UdfA105h4.private
HOME=/home/daemon
LD_LIBRARY_PATH=/lib:/usr/lib:/usr/5lib:/usr/ucblib
LOGDIR=/home/daemon
LOGNAME=daemon
OPTIND=1
PATH=/bin:/usr/bin:/usr/local/bin
PRINTCAP_ENTRY=lp
:force_localhost
:filter=/tmp/testf
:lp=/tmp/lp
:sd=/tmp/LPD/lp
PRINTER=lp
PS1=$
PS2=>
SHELL=/bin/sh
SPOOL_DIR=/tmp/LPD/lp
USER=daemon
LEADER
hi
TRAILER
</pre>
</div>
<br>
<br>
<p>The <tt class="ENVAR">HOME</tt>, <tt class=
"ENVAR">USER</tt>, <tt class="ENVAR">SHELL</tt>, <tt class=
"ENVAR">PS1</tt>, and <tt class="ENVAR">PS2</tt> variables
are usually set by the shell, and are reflect the
information for the <span class="ACRONYM">UID</span> of the
user running the shell.</p>
<p>The <tt class="ENVAR">PATH</tt> and <tt class=
"LITERAL">LP_LIBRARY_PATH</tt> are set by the <b class=
"APPLICATION">lpd</b> server to values specified in the
printcap or configuration information. It is recommended
that users set these to site specific values if the
defaults are not suitable for their sites.</p>
<p>The <b class="APPLICATION">lpd</b> server sets the <tt
class="LITERAL">PRINTER</tt>, <tt class=
"LITERAL">PRINTCAP_ENTRY</tt>, and <tt class=
"LITERAL">CONTROL</tt> environment variables to the printer
name, printcap entry, and control file for the print job.
This information is very useful to filters that must make
decisions based on values passed to the print server in the
control file and which use parameters in the printcap entry
to control their actions.</p>
</div>
<div class="SECT2">
<h2 class="SECT2"><a name=
"USINGCOMMANDLINEANDPRINTCAP">4.9.3. Using Command Line and
Printcap Options In Filters</a></h2>
<p>One of the problems commonly encountered problem in
writing a filter is getting the command line values. The
UNIX POSIX Standard provides a C Language <tt class=
"FUNCTION">getopt</tt> function that can be used for
command line options, and some, but not all shell
implementations have a corresponding shell <tt class=
"FUNCTION">getopt</tt> function. Also, many times it would
be useful to get the values of the printcap options. These
could be used to specify options or operations that are not
easily done by passing command lines.</p>
<ul>
<li>
<p>Observe that all the command line options are single
letters. If we set the shell variables to the
corresponding option value, then we could access them
by using <tt class="LITERAL">$x</tt>, where <tt class=
"LITERAL">x</tt> is the option letter. There is an
exception to this rule, which is the <tt class=
"LITERAL">-c</tt> command line literal, which for
various historical and compatibility reasons does not
take a value. But if it is present, we might as well
assign it the value <tt class="LITERAL">1</tt>.</p>
</li>
<li>
<p>Observe that by convention all printcap options have
lowercase names of two or more letters, and that all
environment variables have all upper case letters. If
we set shell variables with the corresponding printcap
entry values, then we can access them using <tt class=
"LITERAL">$literal</tt>. If we need to create a local
shell variable for use, we can use <tt class=
"LITERAL">mIxEd</tt> case and not have a conflict.</p>
</li>
</ul>
<br>
<br>
<p>The <tt class="LITERAL">decode_args_with_sh</tt> script
which is in the <span class="ACRONYM">UTILS</span>
directory of the <b class="APPLICATION">LPRng</b>
distribution follows these conventions and sets the
appropriate shell variables. We have also include a bit of
code that will extract the control file control line values
and put them into variables as well.</p>
<p>Save the current <tt class="FILENAME">/tmp/testf</tt>
filter file in <tt class="FILENAME">/tmp/testf.old</tt> and
replace it with the following:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2484"></a>
<pre class="SCREEN">
#!/bin/sh
# this is an example of how to use /bin/sh and LPRng
# to get the command line and printcap option values
# and set shell variables from them
# Note that we use a couple of variables
#PATH=/bin:/usr/bin
Args=""
vAr=""
vAlue=""
vAls=""
iI=""
Tf=""
Debug=1
if -n $Debug ; then
set >/tmp/before
fi
Args="$@"
if -n $Debug ; then
echo "$@" >>/tmp/before
fi
while expr "$1" : '-.*' >/dev/null ; do
vAr=`expr "$1" : '-\(.\).*'`;
vAlue=`expr "$1" : '-.\(.*\)`;
case "$vAr" in
- ) break;;
c ) c=1;;
[a-zA-Z] )
if test "X$vAlue" = "X" ; then shift; vAlue=$1; fi;
eval $vAr='$vAlue';
#setvar $vAr "$vAlue"
;;
esac;
shift;
done
# set shell variables to the printcap options
# flag -> flag=1
# flag@ -> flag=0
# option=value -> option='value'
#
setpcvals () {
while test "$#" -gt 0 ; do
iI=$1
if expr "$iI" : " *\:" >/dev/null ; then
vAr=`expr "$iI" : " *\:\([^=][^=]*\)=.*"`;
vAlue=`expr "$iI" : " *\:[^=][^=]*=\(.*\)"`;
if test "X$vAr" = "X" ; then
vAr=`expr "$iI" : " *:\(.*\)@"`;
vAlue=0;
fi
if test "X$vAr" = "X" ; then
vAr=`expr "$iI" : " *:\(.*\)"`;
vAlue=1;
fi
if test "X$vAr" != "X" ; then
eval $vAr='$vAlue';
#setvar $vAr "$vAlue"
fi
else
vAr=`expr "$iI" : " *\([^|][^|]*\).*"`;
if test "X$vAr" != "X" ; then
eval Printer="$vAr"
fi
fi;
shift
done
}
# set shell variables to the printcap options
# flag -> flag=1
# flag@ -> flag=0
# option=value -> option='value'
#
setcontrolvals () {
while test "$#" -gt 0 ; do
iI=$1
vAr=`expr "$iI" : " *\([A-Z]\).*"`;
vAlue=`expr "$iI" : " *[A-Z]\(.*\)"`;
if test "X$vAr" != "X" ; then
eval $vAr='$vAlue';
#setvar $vAr "$vAlue";
fi;
shift
done
}
Tf=$IFS
IFS="
"
setpcvals $PRINTCAP_ENTRY
setcontrolvals $CONTROL
IFS=$Tf
#
# restore argument list
set -- $Args
Args=""
vAr=""
vAlue=""
vAls=""
iI=""
Tf=""
if test -n "$Debug" ; then
set >/tmp/after
echo "$@" >>/tmp/after
diff /tmp/before /tmp/after
fi
/bin/cat
exit 0
</pre>
</div>
<br>
<br>
<p>Lets print our <tt class="FILENAME">/tmp/hi</tt> test
file and then look at the results in <tt class=
"FILENAME">/tmp/lp</tt>:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2489"></a>
<pre class="SCREEN">
<tt class="PROMPT">h4: {188} %</tt> <tt class=
"USERINPUT"><b>cp /dev/null /tmp/lp</b></tt>
<tt class="PROMPT">h4: {189} %</tt> <tt class=
"USERINPUT"><b>lpr /tmp/hi</b></tt>
<tt class="PROMPT">h4: {190} %</tt> <tt class=
"USERINPUT"><b>more /tmp/lp</b></tt>
0a1
> e=dfA021771h4.private
2a4,6
> l=66
> s=status
> L=papowell
10a15,17
> j=021771
> C=A
> J=/tmp/hi
12a20
> a=acct
...
33a58
> Printer=lp
...
hi
</pre>
</div>
<br>
<br>
<p>As we see from the output, shell variables have the
values of our command line and printcap options. It is left
as an exercise for the reader to add the necessary <tt
class="LITERAL">export</tt> statements to cause these
values to be exported to subshells. It is <i class=
"EMPHASIS">not</i> recommended that a wholesale export of
the shell variables be done, but only selected ones.</p>
<p>The paranoid and security minded reader will see some
possible security problem with this script. The <tt class=
"LITERAL">eval $vAr='$vAlue'</tt> command sets the value of
the shell variable <tt class="LITERAL">$vAr</tt> to the
value <tt class="LITERAL">$vAlue</tt>. The <tt class=
"LITERAL">$vAr</tt> variable is always taken from either a
single letter or is the name of an option in the printcap
file. Clearly the printcap file must not be modifiable by
users, and should have the same security considerations as
any other system configuration file. The values of the <tt
class="LITERAL">$vAlue</tt> are taken directly from the
control file, whose contents are under the control of the
originator of the print job request.</p>
<p>For this reason <b class="APPLICATION">LPRng</b> takes
the rather brutal step of <i class=
"EMPHASIS">sanitizing</i> the control file. Only
alphanumerics or a character in the list <tt class=
"LITERAL">@/:()=,+-%_</tt> are used in the control file;
all others replaced by the underscore (<tt class=
"LITERAL">_</tt>) character. In addition, all filters are
run as the <b class="APPLICATION">lpd</b> user specified in
the <tt class="FILENAME">lpd.conf</tt> configuration
file.</p>
<p>The following is an example of how to extract the same
information in Perl:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2514"></a>
<pre class="SCREEN">
#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if $running_under_some_shell;
# this emulates #! processing on NIH machines.
# (remove #! line above if indigestible)
use Getopt::Std;
my(%args,%options);
# get the arguments
getopt(
"a:b:cd:e:f:g:h:i:j:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z:" .
"A:B:C:D:E:F:G:H:I:J:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z:",
\%args );
# set :key=value -> $option{$key}=$value
# set :key@ -> $option{$key}="0"
# set :key -> $option{$key}="1"
map {
if( m/^\s*:([^=]+)=(.*)/ ){
$options{$1}=$2;
} elsif( m/^\s*:([^=]+)\@$/ ){
$options{$1}="0";
} elsif( m/^\s*:([^=]+)/ ){
$options{$1}="1";
} elsif( m/^\s*([^|]+)/ ){
$options{"Printer"}=$1;
}
} split( "\n", $ENV{'PRINTCAP_ENTRY'});
# get the control file entries
map {
if( m/^\s*([A-Z])(.*)/ ){
$options{$1}=$2;
} elsif( m/^\s*([a-z])/ ){
$options{'Format'}=$1;
}
} split( "\n", $ENV{'CONTROL'});
</pre>
</div>
<br>
<br>
<p>The Perl <tt class="LITERAL">Getopt::Std</tt> routine
parses the command line options and puts their values in
the <tt class="LITERAL">%args</tt> hash variable where they
can be accessed using <tt class="LITERAL">$args{'x'}</tt>.
Similarly, the <tt class="LITERAL">map</tt> and <tt class=
"LITERAL">split</tt> functions process the PRINTCAP_ENTRY
and CONTROL environment variable and set <tt class=
"LITERAL">%options</tt> with the printcap entry options and
the values from the control file. The <tt class=
"FUNCTION">map</tt> function could be replaced by a <tt
class="FUNCTION">foreach</tt> loop, but this is Perl: <i
class="EMPHASIS">There is more than one way to do it</i>
and no tutorial would be complete without at least one mind
stretching example that has the reader reaching for the
reference manual.</p>
</div>
<div class="SECT2">
<h2 class="SECT2"><a name="FILTEREXITCODES">4.9.4. Filter
Exit Codes</a></h2>
<p>The <b class="APPLICATION">lpd</b> server uses the exit
code of the filter to determine if the filter was
successful or unsuccessful. The <a href=
"exitcodes.htm">Filter Exit Codes</a> section discusses
these values in detail, but here are the most
important:</p>
<div class="VARIABLELIST">
<dl>
<dt>0 - JSUCC</dt>
<dd>
<p>A JSUCC exit code indicates that the filter was
successful in doing its work.</p>
</dd>
<dt>1 - JFAIL</dt>
<dd>
<p>A JFAIL exit code indicates that the filter was
unsuccessful in doing its work, possibly due to a
transient condition such as out of paper, printer
jam, etc., but an additional attempt might be
successful. Usually the <b class=
"APPLICATION">lpd</b> server will try at most <a
href="abnormalterm.htm">send_try</a> attempts before
giving up.</p>
</dd>
<dt>2 - JABORT</dt>
<dd>
<p>A JABORT exit code indicates that the filter was
unsuccessful in doing its work and has detected a
condition that would make it impossible to print the
job. In addition, the printer may require
administrative attention, and the print queue
operation may need to be suspended until the problem
is rectified.</p>
</dd>
<dt>3 - JREMOVE</dt>
<dd>
<p>The JREMOVE exit code will cause the job to be
removed from the print queue.</p>
</dd>
<dt>6 - JHOLD</dt>
<dd>
<p>The JHOLD exit code will cause the job to be
temporarily prevented from printing until release by
the <tt class="COMMAND">lpc release</tt> command.</p>
</dd>
<dt>Other Values</dt>
<dd>
<p>Usually any other value, including exit due to a
signal, is treated as a JABORT exit, and the same
action is taken.</p>
</dd>
</dl>
</div>
<br>
<br>
<p>It should be obvious that the filter exit code is very
important, and that care needs to be taken to return the
correct value.</p>
</div>
<div class="SECT2">
<h2 class="SECT2"><a name=
"JOBFORMATSANDFILTERSELECTION">4.9.5. Job Formats and
Filter Selection</a></h2>
<p>In the previous sections we discussed how a print filter
was executed and how it could be used. Now we will look at
how the <b class="APPLICATION">lpd</b> spooler chooses a
print filter program. Let us re-examine our example print
job control file:</p>
<div class="INFORMALEXAMPLE">
<a name="AEN2564"></a>
<pre class="SCREEN">
Hh4.private
Ppapowell
J/tmp/hi
CA
Lpapowell
Apapowell@h4+105
D2000-04-12-15:27:26.662
Qlp
N/tmp/hi
fdfA105h4.private
UdfA105h4.private
</pre>
</div>
<br>
<br>
<p>Each data file for a print job has a name with the
format <tt class="LITERAL">df</tt><i class=
"EMPHASIS">X</i>nnn<tt class="FILENAME">h4.private</tt>.
The <tt class="LITERAL">df</tt> is used to indicate that
the file is a <i class="EMPHASIS">data file</i>, and the
remainder is a unique name for the file in the job. The <tt
class="LITERAL">X</tt> part of the name must be an upper or
lower case letter, setting a limit of 52 different files in
a single print job.</p>
<p>The <tt class="FILENAME">fdfA105h4.private</tt> line in
the control file specifies that we are to print the job
using the filter for the <tt class="LITERAL">f</tt> format;
the file printing information consists of the format
assigned to the file and the name of the file. In the
legacy BSD print spoolers, this format was used to select
the print filter to be used. <b class=
"APPLICATION">LPRng</b> has expanded this by providing a <i
class="EMPHASIS">default</i> filter specification.</p>
<div class="TABLE">
<a name="JOBFORMAT"></a>
<p><b>Table 4-2. Job Formats and Filter Selection</b></p>
<table border="1" class="CALSTABLE">
<thead>
<tr>
<th align="LEFT" valign="TOP"><b class=
"APPLICATION">lpr</b> command line option</th>
<th align="LEFT" valign="TOP">Control File
Line</th>
<th align="LEFT" valign="TOP">Printcap Option For
Filter</th>
<th align="LEFT" valign="TOP">Filter Command
Line</th>
</tr>
</thead>
<tbody>
<tr>
<td align="LEFT" valign="TOP">(default)</td>
<td align="LEFT" valign="TOP">fdfAnnn</td>
<td align="LEFT" valign="TOP">:if=/path</td>
<td align="LEFT" valign="TOP">/path -Ff ...</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">-b or -l</td>
<td align="LEFT" valign="TOP">ldfAnnn</td>
<td align="LEFT" valign="TOP">:if=/path</td>
<td align="LEFT" valign="TOP">/path ... -Ff -c</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">-p</td>
<td align="LEFT" valign="TOP">pdfAnnn</td>
<td align="LEFT" valign="TOP">:if=/path</td>
<td align="LEFT" valign="TOP">pr | format f
filter</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">-c, -d, -n, -r, -t,
-v, -FX</td>
<td align="LEFT" valign="TOP">XdfAnnn</td>
<td align="LEFT" valign="TOP">:Xf=/path ...</td>
<td align="LEFT" valign="TOP">/path -FX</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">any format</td>
<td align="LEFT" valign="TOP">XdfAnnn</td>
<td align="LEFT" valign="TOP">:filter=/path
...</td>
<td align="LEFT" valign="TOP">/path -FX</td>
</tr>
</tbody>
</table>
</div>
<p><a href="printjobfilters.htm#JOBFORMAT">Table 4-2</a>
shows the rather baroque relationship between the format
options specified by the <b class="APPLICATION">lpr</b>
command and the way that <b class="APPLICATION">lpd</b>
uses them. The reason for this complexity lies in the
various implementations and variations that occurred during
the development and deployment of the original BSD print
spooling software.</p>
<p>Here is the complete, arcane, and baroque set of rules
that are used to select and print filters. The de<tt class=
"LITERAL">f</tt>ault format used by <b class=
"APPLICATION">lpr</b> is <tt class="LITERAL">f</tt>; unless
some other format is specified this is used. The <tt class=
"COMMAND">lpr -b</tt> and <tt class="COMMAND">lpr -l</tt>
(<tt class="LITERAL">b</tt>inary and <tt class=
"LITERAL">l</tt>iteral literals) are a request to <b class=
"APPLICATION">lpd</b> to do as little processing as
possible of this file before printing it. <b class=
"APPLICATION">Lpd</b> use the <tt class="LITERAL">:if</tt>
filter for formats <tt class="LITERAL">f</tt> and <tt
class="LITERAL">l</tt>; the <tt class="LITERAL">l</tt>
literal causes the the <tt class="LITERAL">-c</tt> filter
command line flag to be used as well. The <tt class=
"COMMAND">lpr</tt> <tt class="LITERAL">-c</tt>, <tt class=
"LITERAL">-d</tt>, <tt class="LITERAL">-n</tt>, <tt class=
"LITERAL">-r</tt>, <tt class="LITERAL">-t</tt>, and <tt
class="LITERAL">-v</tt> options cause the corresponding
format to be used, and for <b class="APPLICATION">lpd</b>
to use the filter specified by the printcap option <tt
class="LITERAL">:Xf</tt>, where <tt class="LITERAL">X</tt>
is the specified format.</p>
<p>The <tt class="COMMAND">lpr -p</tt> (<tt class=
"LITERAL">p</tt>retty-print literal) selects <tt class=
"LITERAL">p</tt> format, and <b class="APPLICATION">lpd</b>
is supposed to use the program specified by the <tt class=
"LITERAL">:pr</tt> printcap option to format the file and
then process the output of this program according to format
<tt class="LITERAL">f</tt>. Unpredictable results may occur
using this facility.</p>
<p>the <tt class="COMMAND">lpr -FX</tt> allows you to
explicitly specify format <tt class="LITERAL">X</tt> where
<tt class="LITERAL">X</tt> is a lower case letter, and <b
class="APPLICATION">lpd</b> will use the filter specified
by printcap option <tt class="LITERAL">:Xf</tt>, where <tt
class="LITERAL">X</tt> is the specified format. If there is
no <tt class="LITERAL">:Xf</tt> printcap literal value then
the printcap <tt class="LITERAL">:filter</tt> literal value
will be used as the filter, and if this is undefined then
the file will be passed without processing through to the
printing device.</p>
<p>If a filter is not specified for the format then the
default filter specified by <tt class=
"LITERAL">:filter=/path</tt> filter is used, and if there
is no default, then the output is sent directly to the
output device.</p>
<p>If the <tt class="LITERAL">:fx=</tt><i class=
"EMPHASIS">formats</i> is present in a printcap entry, it
specifies the formats that are allowed. For example, <tt
class="LITERAL">:fx=lfv</tt> would allow only formats <tt
class="LITERAL">l</tt>, <tt class="LITERAL">f</tt>, and <tt
class="LITERAL">v</tt> to be used on a particular spool
queue.</p>
<p>Some <tt class="LITERAL">Xf</tt> options have
pre-assigned meanings and cannot be used for filter
selection.</p>
<div class="INFORMALTABLE">
<a name="AEN2670"></a>
<table border="1" class="CALSTABLE">
<thead>
<tr>
<th align="LEFT" valign="TOP">Printcap Option</th>
<th align="LEFT" valign="TOP">Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td align="LEFT" valign="TOP">Printcap Option</td>
<td align="LEFT" valign="TOP">Purpose</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:af=/path</td>
<td align="LEFT" valign="TOP">Accounting File</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:ff=formfeed</td>
<td align="LEFT" valign="TOP">Form Feed String</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:if=/path</td>
<td align="LEFT" valign="TOP">filter (l,b,p,f
formats)</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:filter=/path</td>
<td align="LEFT" valign="TOP">Default filter</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:lf=/path</td>
<td align="LEFT" valign="TOP">Log file</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:of=/path</td>
<td align="LEFT" valign="TOP">OF filter</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">:sf</td>
<td align="LEFT" valign="TOP">suppress form feed
between job files</td>
</tr>
</tbody>
</table>
</div>
<p>The <tt class="LITERAL">:of</tt> filter is a special
case and is used for banner printing and accounting
purposes. See <a href="ofdetails.htm">OF Filter</a> for
details.</p>
</div>
</div>
<div class="NAVFOOTER">
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border=
"0" cellpadding="0" cellspacing="0">
<tr>
<td width="33%" align="left" valign="top"><a href=
"jobremoval.htm" accesskey="P">Prev</a></td>
<td width="34%" align="center" valign="top"><a href=
"index.htm" accesskey="H">Home</a></td>
<td width="33%" align="right" valign="top"><a href=
"jobfileformatconversion.htm" accesskey="N">Next</a></td>
</tr>
<tr>
<td width="33%" align="left" valign="top">Job
Removal</td>
<td width="34%" align="center" valign="top"><a href=
"tutorial.htm" accesskey="U">Up</a></td>
<td width="33%" align="right" valign="top">Job File
Format Conversion with Filters</td>
</tr>
</table>
</div>
</body>
</html>
|