Archive for October, 2014

Oct 29

KVM virsh console on CentOS 7

Several articles on using the console feature of KVM guests exists already. This is just a quick note on a test I did using specifically Centos 7 which is using systemd now.

Console allows you to A) see bootup messages and B) login on the console of the guest without SSH.

As far as I can tell you only need to do two things. Add console=ttyS0 to the kernel being booted and in the guest XML switch virtio to serial for the console. Keep in mind this is if you are using the RHEL 7 type when creating the VM. If you were using a RHEL 6 type when creating the guest the console probably still were configured to use serial.

This KVM hypervisor is on Fedora 20 and using libvirt version

To send messages from the kernel to the serial console add console=ttyS0:

# grep console=ttyS0 /boot/grub2/grub.cfg
        linux16 /vmlinuz-3.10.0-123.el7.x86_64 root=UUID=ba0f2424-e66e-4862-90ff-7dccb63339c2 ro vconsole.font=latarcyrheb-sun16 crashkernel=auto  vconsole.keymap=us LANG=en_US.UTF-8 console=ttyS0

# grep ttyS0 /etc/securetty

Change guest console type to serial:

<console type='pty' tty='/dev/pts/6'>
      <source path='/dev/pts/6'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>

# virsh console centos7
Connected to domain centos7
CentOS Linux 7 (Core)
Kernel 3.10.0-123.el7.x86_64 on an x86_64

localhost login: 

Above should do it but if you want to see even the grub2 menu options you can try the following:

# grep serial /etc/default/grub 
GRUB_SERIAL_COMMAND="serial --speed=38400 --unit=0 --word=8 --parity=no --stop=1"

# grep LINUX_DEFAULT /etc/default/grub 
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0"

# grub2-mkconfig -o /boot/grub2/grub.cfg

Of course if you are setting grub DEFAULT options you don't need to set anything for the kernel entries in /boot/grub2/grub.cfg like I did in step 1.

Note that when connecting to the console you might need to move your up or down arrows to see the actual menu entries. The terminal and curses might look a little flaky but it is there. I also set the grub TIMEOUT a little longer to wait at the menu entries.

Comments Off on KVM virsh console on CentOS 7

Oct 07

Printing PCL to PDF

Anyone that ever worked on printing would know how much time can be wasted with root causing problems.  There are a lot of moving parts with different printers, drivers, conversions, operating systems, queue types and so forth.  Especially when special type of printing is required like barcodes.

One particularly painful area is printing and checking results.  A lot of time this is done to a printer not close by like on a manufacturing floor.  Or even across country.  And then depending on someone to check the printout, scan and email back to you introduce a cycle that can be very frustrating for everyone.

One good way to speed up the testing process is to print to PDF.  If you are just interested in generic printing to PDF and willing to tinker with CUPS you could look at CUPS-PDF which is fairly well documented.  In my case I had issues with the way PCL was being printed so I needed to do more than CUPS-PDF.  I might still circle back and see if I can get CUPS-PDF to do some kind pf PCL conversion but for now my solution that worked is documented below.

High level process is as follow:

1. Print from Solaris 11.1 to a remote queue using simple lp -d <queue> <file>

2. CUPS server identifies incoming file as text/plain mime type.  This is forced through adding *cupsfilter: "text/plain  0  -" to an Adobe distiller PPD. CUPS backend called "pdf" which converts to a file.  In my case the destination is /var/www/html/pdf since I want to share the pdf's through Apache.

3. CUPS backend "pdf" script use software called ghostpcl that is a subset of ghostscript to convert pcl to pdf.

4. Debugging Notes.

5. LPD vs IPP.

Details on above steps follow below.

Note copying any commands or scripts does not mean it is tested or working.  I provided below as guide but I tinker with the commands and scripts when editing the article.  I used Oracle Linux 6.5 in this instance so depending on your Linux variant files might have slightly different locations.

1. Printing from Solaris
Add the remote queue and print as follow. In my case I needed to match the printer name to the application so CUPS printer name is different from local queue.

# lpadmin -p testprinter -s lpd://
# lp -d testprinter /root/OUTPUT.TXT

2. Setup CUPS printer and accept incoming file as text/plain
You can also use other PPD files like the one that comes with the CUPS-PDF project but this one worked form me and available from Adobe.

# lpadmin -p pdfprinter -v pdf:/var/www/html/pdf -D "Generate PDF files" -E -P /usr/share/cups/model/distiller.ppd.gz
# chmod 777 /var/www/html/pdf

# pwd
# ls -l
total 20
-rw-r--r--. 1 root root 17172 Oct 6 13:43 pdfprinter.ppd

# grep plain pdfprinter.ppd
*cupsfilter: "text/plain 0 -"

# grep plain mime.*
mime.convs:text/plain application/pdf 0 -
mime.types:text/plain txt printable(0,1024)

# /etc/init.d/cups restart

3. Backend script

# pwd

# cat pdf
# -------------------------------------------------------------------
# "/usr/lib/cups/backend/pdf":
# -------------------------------------------------------------------
set -x
# filename of the PDF File
PRINTTIME=`date +%Y-%m-%d_%H.%M.%S`
# no argument, prints available URIs

# case of wrong number of arguments
if [ $# -ne 5 -a $# -ne 6 ]; then
echo "Usage: pdf job-id user title copies options [file]"
exit 1
# get PDF directory from device URI, and check write status
if [ ! -d "$PDFDIR" -o ! -w "$PDFDIR" ]; then
echo "ERROR: directory $PDFDIR not writable"
exit 1
# generate output filename
if [ "$3" = "" ]; then
if [ "$2" != "" ]; then

if [ $# -eq 6 ]; then

# run ghostpcl
/usr/src/ghostpcl-9.15-linux-x86_64/pcl6-915-linux_x86_64 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS="/ebook" -dAutoRotatePages=/All -dPDFFitPage -r300x300 -g2346x4100 -J"@PJL SET ORIENTATION = LANDSCAPE" -sOutputFile=$OUTPUTFILENAME $INPUTFILENAME


## Normally the PDF file will be emailed to the creating user.  Add emailing code here if needed. Emailing to who?
exit 0
# -------------------------------------------------------------------

4. Debugging Notes:

# grep debug cupsd.conf
LogLevel debug

# grep set pdf
set -x

The biggest pain in the whole process is to make sure CUPS applies only the filter for your backend and not run through any other filters.  Below is some of the lines in the log you want to pay attention to: "Auto-typing ...",  "File of type ..." ,  "Started backend ...". In my case if I see "Started filter ..."  it spells trouble.

# pwd

# grep "Job 134" error_log
I [07/Oct/2014:01:58:27 -0500] [Job 134] Adding start banner page "none".
I [07/Oct/2014:01:58:27 -0500] [Job 134] Queued on "pdfprinter" by "devuser".
D [07/Oct/2014:01:58:27 -0500] [Job 134] Auto-typing file...
D [07/Oct/2014:01:58:27 -0500] [Job 134] Request file type is text/plain.
I [07/Oct/2014:01:58:27 -0500] [Job 134] File of type text/plain queued by "devuser".
D [07/Oct/2014:01:58:27 -0500] [Job 134] job-sheets=none
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[0]="pdfprinter"
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[1]="134"
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[2]="devuser"
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[3]="standard input"
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[4]="1"
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[5]="document-name=/tmp/stdin-P3OQc job-originating-host-name= job-uuid=urn:uuid:0f507f16-0537-3307-6b15-b5134eda2bc5"
D [07/Oct/2014:01:58:27 -0500] [Job 134] argv[6]="/var/spool/cups/d00134-001"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[0]="CUPS_CACHEDIR=/var/cache/cups"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[1]="CUPS_DATADIR=/usr/share/cups"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[2]="CUPS_DOCROOT=/usr/share/cups/www"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[3]="CUPS_FONTPATH=/usr/share/cups/fonts"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[4]="CUPS_REQUESTROOT=/var/spool/cups"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[5]="CUPS_SERVERBIN=/usr/lib/cups"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[6]="CUPS_SERVERROOT=/etc/cups"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[7]="CUPS_STATEDIR=/var/run/cups"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[8]="HOME=/var/spool/cups/tmp"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[9]="PATH=/usr/lib/cups/filter:/usr/lib64/cups/filter:/usr/bin:/usr/sbin:/bin:/usr/bin"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[10]="SERVER_ADMIN=root@localhost"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[11]="SOFTWARE=CUPS/1.4.2"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[12]="TMPDIR=/var/spool/cups/tmp"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[13]="USER=root"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[14]="CUPS_SERVER=/var/run/cups/cups.sock"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[15]="CUPS_ENCRYPTION=IfRequested"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[16]="IPP_PORT=631"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[17]="CHARSET=utf-8"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[18]="LANG=en_US.UTF-8"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[19]="PPD=/etc/cups/ppd/pdfprinter.ppd"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[20]="RIP_MAX_CACHE=128m"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[21]="CONTENT_TYPE=text/plain"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[22]="DEVICE_URI=pdf:/var/www/html/pdf"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[23]="PRINTER_INFO=Generate PDF files"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[24]="PRINTER_LOCATION=VM"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[25]="PRINTER=pdfprinter"
D [07/Oct/2014:01:58:27 -0500] [Job 134] envp[26]="CUPS_FILETYPE=document"
I [07/Oct/2014:01:58:27 -0500] [Job 134] Started backend /usr/lib/cups/backend/pdf (PID 2170)
D [07/Oct/2014:01:58:27 -0500] [Job 134] + FILENAME=
D [07/Oct/2014:01:58:27 -0500] [Job 134] ++ date +%Y-%m-%d_%H.%M.%S
D [07/Oct/2014:01:58:27 -0500] [Job 134] + PRINTTIME=2014-10-07_01.58.27
D [07/Oct/2014:01:58:27 -0500] [Job 134] + '[' 6 -eq 0 ']'
D [07/Oct/2014:01:58:27 -0500] [Job 134] + '[' 6 -ne 5 -a 6 -ne 6 ']'
D [07/Oct/2014:01:58:27 -0500] [Job 134] + PDFDIR=/var/www/html/pdf
D [07/Oct/2014:01:58:27 -0500] [Job 134] + '[' '!' -d /var/www/html/pdf -o '!' -w /var/www/html/pdf ']'
D [07/Oct/2014:01:58:27 -0500] [Job 134] + OUTPUTFILENAME=
D [07/Oct/2014:01:58:27 -0500] [Job 134] + '[' 'standard input' = '' ']'
D [07/Oct/2014:01:58:27 -0500] [Job 134] + '[' devuser '!=' '' ']'
D [07/Oct/2014:01:58:27 -0500] [Job 134] + OUTPUTFILENAME=/var/www/html/pdf/devuser-2014-10-07_01.58.27.pdf
D [07/Oct/2014:01:58:27 -0500] [Job 134] + INPUTFILENAME=
D [07/Oct/2014:01:58:27 -0500] [Job 134] + '[' 6 -eq 6 ']'
D [07/Oct/2014:01:58:27 -0500] [Job 134] + INPUTFILENAME=/var/spool/cups/d00134-001
D [07/Oct/2014:01:58:27 -0500] [Job 134] + /usr/src/ghostpcl-9.15-linux-x86_64/pcl6-915-linux_x86_64 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/ebook -dAutoRotatePages=/All -dPDFFitPage -r300x300 -g2346x4100 '-J@PJL SET ORIENTATION = LANDSCAPE' -sOutputFile=/var/www/html/pdf/devuser-2014-10-07_01.58.27.pdf /var/spool/cups/d00134-001
D [07/Oct/2014:01:58:27 -0500] [Job 134] + chmod 644 /var/www/html/pdf/devuser-2014-10-07_01.58.27.pdf
D [07/Oct/2014:01:58:27 -0500] [Job 134] + exit 0
I [07/Oct/2014:01:58:27 -0500] [Job 134] Job completed.
D [07/Oct/2014:01:58:28 -0500] [Job 134] Unloading...

5. IPP versus LPD:
Note that I am using cups-lpd to accept on the lpd port on the CUPS server but I think it might not be necessary. IPP would also have worked. I had an odd CUPS issue that printing local on the CUPS server using lp worked but sending the file from a remote Solaris server CUPS insisted on tacking on a CUPS-BANNER which caused issues and even triggering the gziptoany filter and possibly more filters for ps.  Sounds like a bug with CUPS and the fix for to make sure no banner is added was here:

# grep server_args /etc/xinetd.d/cups-lpd
  server_args = -o job-sheets=none

Comments Off on Printing PCL to PDF