Tag Archives: nc

Print on FreeBSD

Nothing compares more to the sense of power UNIX sysadmin experiences when being able to print from a command line on its UNIX system :p

I kinda omitted this topic (printing) for quite a lot of time – when I was using FreeBSD in the corporate environment I still printed from Windows VM on a network printers. Then they forced me to use Windows anyway. At home my wife always had a printer configured (as she uses it more) and the other printer also had USB port – so you could just copy the PDF or JPG file to a USB pendrive – attach it the printer and hit print button for the selected files. No configuration needed.

I was also disappointed when I tried several years ago to configure USB printer on FreeBSD … and failed.

Recently I though that its about fucking time to dig into that topic and have at least one working printer on FreeBSD.

This guide will focus on using two printers with CUPS on FreeBSD:

  • HP Color LaserJet 200 M251nw Printer (attached over TCP/IP network)
  • Samsung Black/White ML-1915 Printer (local USB attached)

There will be two different prompt types used for the commands:

  • starting with % for commands that can be executed as regular user or root
  • starting with # for commands that must be executed as root user

The Table of Contents for this article is shown below.

  • CUPS Packages and Service Configuration
  • Network Printer – HP M251nw
  • Try to Print Some Document
  • USB Printer – Samsung ML-1915
  • Choose Default Printer
  • CUPS Printers Config
  • Command Line Printing
  • Last Chance Fancy Pants
  • Summary

CUPS Packages and Service Configuration

There are only three pkg(8) packages needed for my printers – these are:

# pkg install cups cups-filters splix

We will also need to add some lines to the /etc/devfs.rules file.

These lines are important for printing with CUPS:

add path 'lpt*'      mode 0660 group cups
add path 'ulpt*'     mode 0660 group cups
add path 'unlpt*'    mode 0660 group cups

The rest of the config is just the rest of my desktop config and can be omitted for printing.

The entire /etc/devfs.rules file looks as follows.

% cat /etc/devfs.rules
add path 'lpt*'      mode 0660 group cups
add path 'ulpt*'     mode 0660 group cups
add path 'unlpt*'    mode 0660 group cups
add path 'acd*'      mode 0660 group operator
add path 'cd*'       mode 0660 group operator
add path 'da*'       mode 0660 group operator
add path 'pass*'     mode 0660 group operator
add path 'xpt*'      mode 0660 group operator
add path 'fd*'       mode 0660 group operator
add path 'md*'       mode 0660 group operator
add path 'uscanner*' mode 0660 group operator
add path 'ugen*'     mode 0660 group operator
add path 'usb/*'     mode 0660 group operator
add path 'video*'    mode 0660 group operator
add path 'cuse*'     mode 0660 group operator

We will also need to add devfs_system_ruleset=desktop to the /etc/rc.conf file.

% grep desktop /etc/rc.conf

Now we need to restart the devfs daemon to read new config.

# service devfs restart

We can also make sure that devfs(8) know our ruleset config.

# devfs rule -s 10 show | column -t
100   path  acd*       group  operator  mode  660
200   path  cd*        group  operator  mode  660
300   path  da*        group  operator  mode  660
400   path  pass*      group  operator  mode  660
500   path  xpt*       group  operator  mode  660
600   path  fd*        group  operator  mode  660
700   path  md*        group  operator  mode  660
800   path  uscanner*  group  operator  mode  660
900   path  lpt*       group  cups      mode  660
1000  path  ulpt*      group  cups      mode  660
1100  path  unlpt*     group  cups      mode  660
1200  path  ugen*      group  operator  mode  660
1300  path  usb/*      group  operator  mode  660
1400  path  video*     group  operator  mode  660
1500  path  cuse*      group  operator  mode  660

The column(1) is not needed here – I used it only to format the output.

What amaze me to this day that column(1) command is still not available on such enterprise (and overpriced also) IBM AIX system πŸ™‚

Here are the contents of fresh CUPS installation at /usr/local/etc/cups dir.

# tree -F --dirsfirst /usr/local/etc/cups
β”œβ”€β”€ ppd/
β”œβ”€β”€ ssl/
β”œβ”€β”€ cups-files.conf
β”œβ”€β”€ cups-files.conf.sample
β”œβ”€β”€ cupsd.conf
β”œβ”€β”€ cupsd.conf.sample
β”œβ”€β”€ snmp.conf
└── snmp.conf.sample

3 directories, 6 files

You will need to add cupsd_enable=YES to the /etc/rc.conf file.

% grep cups /etc/rc.conf

Make sure that cupsd service is started and running.

# service cupsd start
Starting cupsd.

# service cupsd status
cupsd is running as pid 44515.

# sockstat -l4 | grep -e ADDRESS -e 631
root     cupsd      44515 6  tcp4         *:*

Just in case – here are the groups in which my vermaden user is:

% id | tr ',' '\n'
uid=1000(vermaden) gid=1000(vermaden) groups=1000(vermaden)

It was not needed to add my vermaden user to the cups group to print – but feel free to also test that if you face any problems.

Network Printer – HP M251nw

First I will go with the TCP/IP attached network printer – HP M251nw.

Before doing any steps or configuration on FreeBSD part we first need to connect that printer to the TCP/IP network. As the HP M251nw printer has WiFi – I decided to connect it to my wireless WiFi router instead of using RJ45 cable. I will not document that part as HP already provides decent guide on how to achieve that – https://youtu.be/jLDzQBAtKyQ – on YouTube service.

In my case I used the IP address and I configured my WiFi router to always attach that MAC address to that IP address.


Next step is to open http://localhost:631/ page in your browser. You will see default CUPS web interface.


Hit the Administration tab on the top. Then click the Add Printer button in the middle of the page – you will be asked for username and password – use your username and your password here.


The HP M251nw network attached browser has already been detected by CUPS. Select it and click Continue button.


CUPS will suggest some long names and description as showed below.


… but we will use simpler and shorter name instead.


Next we need to choose which driver to use.

We will not find a HP M251nw driver on the CUPS list but there are two drivers that will work here:

  • HP LaserJet Series PCL 6 CUPS (en)
  • HP Color LaserJet Series PCL 6 CUPS (en)

As HP M251nw is color printer we will choose HP Color LaserJet Series PCL 6 CUPS here.


After a moment we will see a message that HP M251nw printer has been successfully added to CUPS.


You can notice that new PPD file appeared at CUPS dir named exactly like the printer name.

% ls -l /usr/local/etc/cups/ppd
total 9K
-rw-r----- 1 root cups 9721 2023-02-06 11:24 HP-M251nw.ppd
-rw-r----- 1 root cups 9736 2023-02-06 11:23 HP-M251nw.ppd.O

This is how our HP M251nw printer status page looks like.


We should now setup the default printing options. From the Administration drop down menu select Set Default Options option. The only things I selected/set that are different from the CUPS defaults are A4 paper size and 1200 DPI resolution.


Try to Print Some Document

I will now use Atril PDF viewer to test how the printing on the HP M251nw works – I used a small one page PDF file with one of my old guides – the ZFS Madness one from 2014. From the File menu select Print… option – or just hit [CTRL]+[P] shortcut.


Then select HP-M251nw printer from the list and hit the Print button below.


After some noises and time (not much later) the printer dropped a printed page. Seems to work properly.


Looks good.

Lets now add USB printer.

USB Printer – Samsung ML-1915

To get needed PPD driver for the Samsung ML-1915 printer we installed the print/splix package.


Here is the exact driver we will use.

% pkg info -l splix | grep 1915

Before attaching the Samsung ML-1915 printer to your computer you may check what devices devd(8) will create.

First power on the Samsung ML-1915 printer.

Then attach the USB cable from the printer to your FreeBSD box (assuming that printer has AC power and is powered on).

You should see something similar from devd(8) daemon.

# nc -U /var/run/devd.pipe
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.3.0
!system=DEVFS subsystem=CDEV type=CREATE cdev=ugen0.3
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.3.2
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.3.3
!system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.3 cdev=ugen0.3 vendor=0x04e8 product=0x3297 devclass=0x00 devsubclass=0x00 sernum="Z2L9BACSC00641K." release=0x0100 mode=host port=2 parent=ugen0.2
!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.3 cdev=ugen0.3 vendor=0x04e8 product=0x3297 devclass=0x00 devsubclass=0x00 sernum="Z2L9BACSC00641K." release=0x0100 mode=host interface=0 endpoints=2 intclass=0x07 intsubclass=0x01 intprotocol=0x02
!system=DEVFS subsystem=CDEV type=CREATE cdev=ulpt0
!system=DEVFS subsystem=CDEV type=CREATE cdev=unlpt0
+ulpt0 at bus=0 hubaddr=2 port=2 devaddr=3 interface=0 ugen=ugen0.3 vendor=0x04e8 product=0x3297 devclass=0x00 devsubclass=0x00 devproto=0x00 sernum="Z2L9BACSC00641K." release=0x0100 mode=host intclass=0x07 intsubclass=0x01 intprotocol=0x02 on uhub4

These are the created devices.

% ls -ltra /dev | tail -3
lrw-rw----  1 root     operator      9 2023-02-06 11:38 ugen0.3 -> usb/0.3.0
crw-rw----  1 root     cups     2, 113 2023-02-06 11:38 ulpt0
crw-rw----  1 root     cups     2, 114 2023-02-06 11:38 unlpt0

They are created with proper cups group.

Now we will go to the CUPS web page at http://localhost:631/ again to add the Samsung ML-1915 printer.

Go again to the Administration tab and click Add Printer button.


The Samsung ML-1915 should be already detected as local printer as shown below.


Select it and hit Continue button.

As earlier we will use shorter more reasonable name.


We will then select Samsung ML-1915, 2.0.0 (en, en) driver for this printer.


… and Samsung ML-1915 black/white printer has been added.


Same as earlier the PPD file is copied to the /usr/local/etc/cups/ppd CUPS dir.

% ls -l /usr/local/etc/cups/ppd
total 14K
-rw-r----- 1 root cups  9721 2023-02-06 11:24 HP-M251nw.ppd
-rw-r----- 1 root cups  9736 2023-02-06 11:23 HP-M251nw.ppd.O
-rw-r----- 1 root cups 12391 2023-02-06 11:58 Samsung-ML-1915.ppd

You now have two printers configured in CUPS.


Choose Default Printer

I will now choose the HP M251nw printer as the default for two reasons. First – its always available as its attached over WiFi. Second – its more powerful and provides color at the same time.

To do that I went to the Printers and clicked the HP M251nw printer.


Next from the Administration drop down menu I have chosen Set As Server Default option.


From now on – if not explicitly specified – all the print jobs will land on the HP M251nw printer.


CUPS Printers Config

After our actions CUPS stored two printers configuration in its /usr/local/etc/cups/printers.conf config file.

# cat /usr/local/etc/cups/printers.conf
# Printer configuration file for CUPS v2.4.2
# Written by cupsd
NextPrinterId 3
<DefaultPrinter HP-M251nw>
PrinterId 1
UUID urn:uuid:b760d323-5f46-36cd-4ca0-d9015c9fb7ca
MakeModel HP Color LaserJet Series PCL 6 CUPS
DeviceURI socket://
State Idle
StateTime 1675683146
ConfigTime 1675679066
Type 8400972
Accepting Yes
Shared No
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy stop-printer
Attribute marker-colors \#000000,#00FFFF,#FF00FF,#FFFF00
Attribute marker-levels 99,98,98,99
Attribute marker-names Black Cartridge HP CF210X,Cyan Cartridge HP CF211A,Magenta Cartridge HP CF213A,Yellow Cartridge HP CF212A
Attribute marker-types toner,toner,toner,toner
Attribute marker-change-time 1675683146
<Printer Samsung-ML-1915>
PrinterId 2
UUID urn:uuid:4434851b-5516-3b73-702a-286dabf630b0
MakeModel Samsung ML-1915, 2.0.0
DeviceURI usb://Samsung/ML-191x%20252x%20Series?serial=Z2L9BACSC00641K.
State Idle
StateTime 1675681099
ConfigTime 1675681099
Type 12372
Accepting Yes
Shared No
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy stop-printer

Command Line Printing

Besides being able to print from graphical applications that support CUPS we can also print directly from the command line if needed.

Use lpstat(1) command to see all available printers – including the default one.

% lpstat -p -d
printer HP-M251nw is idle.  enabled since Mon Feb  6 12:02:39 2023
printer Samsung-ML-1915 is idle.  enabled since Mon Feb  6 11:58:19 2023
system default destination: HP-M251nw

You can check more information about the default printer with lpoptions(1) command.

% lpoptions -l
PageSize/Media Size: Letter Legal Executive Tabloid A3 *A4 A5 B5 EnvISOB5 Env10 EnvC5 EnvDL EnvMonarch
InputSlot/Media Source: *Default Auto MultiPurpose Upper Lower LargeCapacity Manual Envelope
ColorModel/Output Mode: *RGB Gray
Resolution/Output Resolution: 150dpi 300dpi 600dpi *1200dpi
Duplex/Double-Sided Printing: *None DuplexNoTumble DuplexTumble
OptionDuplex/Duplexer: True *False

… or even more details and information when executed without arguments.

I have used tr(1) tool to make the output more readable as by default all this information is separated only by spaces.

% lpoptions | tr ' ' '\n'

We will now print the same PDF document using command line with lp(1) command.

% lp ZFS-Madness-2014.pdf
request id is HP-M251nw-02 (1 file(s))

Believe me or not – that PDF document got printed exactly the same as when invoked from Atril PDF browser.

Last Chance Fancy Pants

There is of course a chance that your printer will not be detected – or it will not print – or the driver will not attach to it properly … life happens.

What then? Fuck it. There is even more fun way to print … even without any drivers or configuration … directly with nc(1) command πŸ™‚

First lets check of your printer listens on 9100 port – this is called HP JetDirect.

% grep 9100 /etc/services
jetdirect       9100/tcp   #HP JetDirect card
pdl-datastream  9100/tcp   #Printer PDL Data Stream
pdl-datastream  9100/udp   #Printer PDL Data Stream

% nmap -A
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-06 23:41 CET
Nmap scan report for
Host is up (0.0072s latency).
Not shown: 988 closed tcp ports (conn-refused)
21/tcp   open  ftp            oftpd
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_ftp-bounce: bounce working!
| ftp-syst:
|_  SYST: .
23/tcp   open  telnet         HP LaserJet printer telnetd (busy)
80/tcp   open  soap           gSOAP 2.7
| http-server-header:
|   Virata-EmWeb/R6_2_1
|_  gSOAP/2.7
81/tcp   open  tcpwrapped
82/tcp   open  tcpwrapped
83/tcp   open  tcpwrapped
443/tcp  open  ssl/tcpwrapped
| ssl-cert: Subject: commonName=NPI04344D/organizationName=Hewlett-Packard Co.
| Not valid before: 2012-09-01T00:00:00
|_Not valid after:  2022-09-01T00:00:00
|_http-server-header: gSOAP/2.7
|_ssl-date: TLS randomness does not represent time
515/tcp  open  printer
631/tcp  open  soap           gSOAP 2.7
| http-server-header:
|   Virata-EmWeb/R6_2_1
|_  gSOAP/2.7
5222/tcp open  tcpwrapped
| xmpp-info:
|   STARTTLS Failed
|   info:
|     features:
|     auth_mechanisms:
|     xmpp:
|     unknown:
|     compression_methods:
|     errors:
|       (timeout)
|_    capabilities:
8080/tcp open  soap           gSOAP 2.7
| http-server-header:
|   Virata-EmWeb/R6_2_1
|_  gSOAP/2.7
9100/tcp open  jetdirect?
Service Info: OS: Unix; Device: printer

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.37 seconds

Lets try to connect to it with nc(1) tool.

% nc -v 10.9 9100
Connection to 10.9 9100 port [tcp/jetdirect] succeeded!

… and yes you do not have to always type that whole address as the middle zeroes can be omitted and 10.9 will be interpretted as address.

Something basic for a start – a plain text print.

% lsblk | nc 10.9 9100

In a moment you should have the output of lsblk(8) command printed on a page.

Lets try something more fancy like a PDF file then.

% nc 10.9 9100 < ZFS-Madness-2014.pdf

Yep. Printed. No CUPS configuration needed here.

Maybe I should start the article with that instead πŸ™‚


Not sure what I can add here as I am definitely not printing expert.

Hope these instructions will help you to setup your printer on FreeBSD (or any other CUPS supported) system.