Converting CSRG’s SCCS history to SVN

October 19th, 2012 by jhb

There are many times when I look back in FreeBSD’s source code control history to better understand a particular piece of code I am working on.  I can better understand why a section of code is written the way it is by seeing the changes in that section of code across time along with the rationale for those changes in the log messages.  Sometimes while doing this I run into a wall since FreeBSD’s history stops at the import of the 4.4BSD sources from CSRG.  I have often longed to dive farther back into the code’s history.

The good news is that the folks at CSRG maintained their own source code repository using SCCS.  Dr. Marshall Kirk McKusick sells a 4-disc CD set that contains the SCCS repository (along with several other bits).  SCCS is a bit awkward to work with, however, so recently I derived a Subversion repository from the SCCS repository.

The Tools

The main tool I used was sccs2svn.py. This script required a couple of FreeBSD ports to be installed: devel/py-subversion and devel/cssc.   In addition, I had to patch sccs2svn.py to fix several things:

  1. Subversion 1.7 requires client.svn_client_create_context() to create a context rather than client.svn_client_ctx_t().
  2. Fixups to correct the timestamp on each commit in SVNInterface._commit() were applied to the previous revision rather than the revision being committed.
  3. One CSRG commit contained CR (‘\r’) characters in a log message that had to be converted to LF (‘\n’) to be accepted by Subversion.
  4. One SCCS file contained a corrupted log message that was not valid UTF-8.  I used this patch to get past the failure so I could identify and fix the corrupted log message.
  5. By default, the sccs2svn.py script makes two passes over the entire repository at the end of the conversion process applying fixups to SCCS keywords and ID strings.  These passes are intended to allow for future development in the resulting Subversion repository.  However, in this case of converting an historical repository, these passes merely added noise and obfuscation.  I added a new –pure option to disable these passes.

The command line used to run the conversion was:

python sccs2svn.py -u sccs2svn -o /home/csrg/svn -i /home/csrg/sccs -p

Fixups

A few of the SCCS files contained errors (single-bit errors) and the repository also contained a few “bad” SCCS files that muddled the results.  For the “bad” SCCS files I simply removed them from the copy of the SCCS repository I used for the conversion.  The following errors I fixed by hand:

  • usr.bin/pascal/src/SCCS/s.main.c had a corrupted status line for its initial revision where a ’0′ (0×30) had been replaced with a ‘p’ (0×70).
  • usr.bin/pascal/pdx/machine/SCCS/s.printerror.c had a corrupted status line for its initial revision where a ’5′ (0×35) had been replaced by a ‘^U’ (0×15).
  • usr.bin/pascal/pdx/machine/SCCS/s.printerror.c had a corrupted log message for its 1.2 revision where “init()” had been replaced by “i\xee\xe9t()”.  That is, ‘n’ (0x6e) had been replaced by 0xee, and ‘i’ (0×69) had been replaced by 0xe9.

Availability

The Subversion repository is available as a tarball via either FTP or HTTP.  It is also available for viewing at http://svnweb.freebsd.org/csrg/.

Using HPLIP on FreeBSD with an HP LaserJet 100 M175

February 20th, 2012 by jhb

Several years ago when I needed a new printer, I had gotten some sort of HP inkjet, and I was pleasantly surprised by how easy it was to enable printing using HPLIP on top of CUPS.  I had previously used Apsfilter with various printers.  That was still worlds better than manually configuring print filters and spools and hacking on /etc/printcap directly.  However, the HPLIP setup was even nicer out of the box than with Apsfilter.  Thus, when it was time for a new printer recently, I went with an HP printer.  With this printer I hit a few bumps with HPLIP and here is how I solved them:

Installing the HPLIP Plugin

My new printer required a plugin for HPLIP during setup, and trying to fetch and install the plugin using hp-setup did not work.  Instead, hp-setup just hung without any errors.  To get around this I had to install the plugin manually.

First, I had to find and download the plugin.  I probably could have sniffed the URL out via tcpdump on the connection hp-setup was opening when it tried to install the plugin, but I did not think of that at the time.  Instead, after some searching I eventually found the URL http://www.openprinting.org/download/printdriver/auxfiles/HP/plugins/hplip-3.11.12-plugin.run (Note that I am using version 3.11.12 of HPLIP, you can modify the URL for different HPLIP versions as needed).  I used fetch(8) like so:

> fetch -o /tmp/plugin http://www.openprinting.org/download/printdriver/auxfiles/HP/plugins/hplip-3.11.12-plugin.run

The file downloaded to /tmp/plugin was just a fancy self-extracting shell archive.  Running it by hand failed with this message:

> sudo sh /tmp/plugin
Verifying archive integrity... All good.
Uncompressing HPLIP 3.11.12 Plugin Self Extracting Archive.........................................
eval: ./hplip-plugin-install: not found

Of course, when I checked, there was no ./hplip-plugin-install file to examine.  After perusing the script, I found that it accepted an optional ‘–keep’ option that would leave the directory of extracted files around instead of cleaning them up on exit.  I also found that the script extracted to the current directory, so I ran the script from /tmp after that point.

> cd /tmp
> sudo sh /tmp/plugin --keep
Creating directory plugin_tmp
Verifying archive integrity... All good.
Uncompressing HPLIP 3.11.12 Plugin Self Extracting Archive.........................................
eval: ./hplip-plugin-install: not found

This left behind a /tmp/plugin_tmp directory that contained a hplip-plugin-install file:

> sudo cat plugin_tmp/hplip-plugin-install
#!/bin/bash

# su/sudo wrapper for HPLIP installer
python ./plugin_install.py $*

Of course, FreeBSD doesn’t typically have /bin/bash (nor does this script even need /bin/bash AFAICT).  Instead, I just ran the python script directly as root. The first time I tried this it failed:

> sudo -s
# cd plugin_tmp
# python ./plugin_install.py
Error setting home directory: /etc/hp/hplip.conf not found. Is HPLIP installed?

I created a symlink from /etc/hp to /usr/local/etc/hp and ran it again.  This time it popped up a dialog box with a EULA and installed successfully.  After it finished, I deleted /tmp/plugin_tmp and /tmp/plugin to cleanup.

Adding the Printer

Once the plugin was installed manually, hp-setup ran fine and recognized that the plugin was already installed.  However, I did run into a couple of glitches.

First, for the specific printer I was using (an HP LaserJet 100 M175nw), hp-setup wasn’t able to determine the ppd file automatically.  I was able to install the printer just fine though by selecting ‘hp-laserjet_100_color_mfp_m175-ps.ppd.gz’ manually.

Second, I let hp-setup use the default setting for discovering the printer over the network (mDNS).  However, the printer didn’t actually work even though hp-setup had claimed it had added it successfully.  All attempts to use it failed with this error:

> hp-info

HP Linux Imaging and Printing System (ver. 3.11.12)
Device Information Utility ver. 5.2

Copyright (c) 2001-9 Hewlett-Packard Development Company, LP
This software comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to distribute it
under certain conditions. See COPYING file for more details.

Using device: hp:/net/HP_LaserJet_100_colorMFP_M175nw?zc=NPIA32010

error: Unable to communicate with device (code=12): hp:/net/HP_LaserJet_100_colorMFP_M175nw?zc=NPIA32010                                                        
error:  Unable to open device hp:/net/HP_LaserJet_100_colorMFP_M175nw?zc=NPIA32010.                                                                             

Done.

Some web searching led me to suspect mDNS as the problem.  I tried starting avahi-daemon, but that did not help.  Eventually, I punted on mDNS and assigned my printer a static IP.  I  re-ran hp-setup to attach to the printer via the static IP at which point it worked fine.

Using CUDA with the native FreeBSD/amd64 NVIDIA driver

July 20th, 2010 by jhb

Nearly a year ago NVIDIA released a native GPU driver for FreeBSD/amd64.  At one point while testing an earlier BETA version of the driver (195.22) I played around with CUDA.  These notes are just a summary of the setup I used during my testing.  I built apps from the CUDA SDK on a Linux/i386 box and then ran them on a FreeBSD/amd64 box.  I will only cover setting up the FreeBSD box here.  For these tests I used version 2.3 of the CUDA SDK and toolkit for RHEL 4.x / i386.

  1. Setup Linux compatibility on the FreeBSD machine
    • Install a suitable linux_base package
    • Mount linprocfs(4) and linsysfs(4)
  2. Install the NVIDIA graphics driver and add missing libcuda.so symlink

    # cd /somepath/NVIDIA-FreeBSD-x86_64-195.22
    # make install
    # cd /compat/linux/usr/lib
    # ln -sf libcuda.so.1 libcuda.so

    The driver should attach to any NVIDIA GPUs or CUDA devices:

    nvidia0: on vgapci0
    vgapci0: child nvidia0 requested pci_enable_busmaster
    vgapci0: child nvidia0 requested pci_enable_io
    vgapci0: child nvidia0 requested pci_enable_io
    nvidia0: [GIANT-LOCKED]
    nvidia0: [ITHREAD]
    nvidia1: on vgapci1
    vgapci1: child nvidia1 requested pci_enable_busmaster
    vgapci1: child nvidia1 requested pci_enable_io
    vgapci1: child nvidia1 requested pci_enable_io
    nvidia1: [GIANT-LOCKED]
    nvidia1: [ITHREAD]

  3. Start a root Linux shell:

    # /compat/linux/bin/sh
    sh-3.00#

  4. Install the CUDA toolkit:

    sh-3.00# sh /somepath/cudatoolkit_2.3_linux_32_rhel4.7.run
    Verifying archive integrity… All good.
    Uncompressing NVIDIA CUDA………………………………………………………………………………………………………………………
    Enter install path (default /usr/local/cuda, ‘/cuda’ will be appended):
    <… lots of files installed into /usr/local/cuda >

  5. Add /usr/local/cuda to /compat/linux/etc/ld.so.conf and run the Linux ldconfig as root:

    sh-3.00# echo /usr/local/cuda/lib >> /etc/ld.so.conf
    sh-3.00# ldconfig
    ldconfig: /usr/local/cuda/lib/libcudart.so.2 is not a symbolic link

    ldconfig: /usr/local/cuda/lib/libcufft.so.2 is not a symbolic link

    ldconfig: /usr/local/cuda/lib/libcufftemu.so.2 is not a symbolic link

    ldconfig: /usr/local/cuda/lib/libcublasemu.so.2 is not a symbolic link

    ldconfig: /usr/local/cuda/lib/libcublas.so.2 is not a symbolic link

  6. Install the CUDA SDK:

    sh-3.00# sh /somepath/cudasdk_2.3_linux.run
    Verifying archive integrity… All good.
    Uncompressing NVIDIA GPU Computing SDK…………………………………………………………………………………………………………..
    Enter install path (default ~/NVIDIA_GPU_Computing_SDK):
    ….

In this case I installed the CUDA SDK to my home directory which was shared with the Linux/i386 build box that I used via NFS. I compiled the binaries on the Linux/i386 host and then ran them on the FreeBSD/amd64 machine. At this point I no longer have access to the hardware in question so I am not able to provide any output or screenshots from the CUDA SDK applications. While native support for CUDA applications with FreeBSD would be nice, the current capabilities are certainly enough for further investigation and evaluation.

Using svk and svn to Maintain a FooBSD

May 26th, 2009 by jhb

Several of the companies I have worked for have used a modified version of FreeBSD for various tasks. Generally these modified versions of FreeBSD are given their own name. Hence “FooBSD”.

My first attempt at doing this consisted of leaving local patches in a CVS checkout and dealing with conflicts when updating from one branch to another. Fortunately, there were very few patches in this particular FooBSD. However, the approach of just keeping patches around does not scale well.

My next experience was far more workable. In this case, my employer’s FooBSD lived in an actual source code repository as a branch of FreeBSD. This setup was very nice and also allowed this particular FooBSD to span many different versions of FreeBSD. However, the actual system to manage this was a bit complex and not easy to duplicate. It relies on custom scripts to import periodic snapshots of various branches of the FreeBSD source tree as a vendor sources into the source code repository. It also predates FreeBSD’s switch from CVS to Subversion.

I recently changed jobs. My new employer was maintaining a few modifications as local patches. I wanted to store these changes (along with future changes) as a branch of FreeBSD. I did not want to write and maintain a complex set of scripts to do this, however. After some investigation, I found that I could use svk to easily setup a mirror of FreeBSD’s Subversion repository in a local Subversion repository and to create branches of FreeBSD to hold my FooBSD changes.

Initial svk Setup

The first thing to do is configure svk to create a new Subversion repository. In this case, I am going to create the repository in the /home/foobsd directory. The first parameter to the depotmap command below is a nickname for this new repository that is used in svk commands.

# svk depotmap foobsd /home/foobsd

Next, I tell svk that it should mirror the FreeBSD source code repository into the mirror/FreeBSD path within my new repository. Note that this just establishes a mapping similar to a branch specification in Perforce. It does not copy any data into my local repository.

# svk mirror svn://svn.FreeBSD.org/base /foobsd/mirror/FreeBSD

Note: You may not want to mirror the entire FreeBSD repository in this manner. You probably only need to mirror certain branches of FreeBSD. I believe you can do that by mirroring each branch to a separate path in your local repository.

Finally, before I can create a branch of FreeBSD, I need to perform an initial update of my local FreeBSD mirror. This is done via svk’s sync command.

# svk sync /foobsd/mirror/FreeBSD

Note: This may take a long time. There may be ways to save a lot of time and bandwidth using by pulling from a local SVN mirror instead or using a seed. I couldn’t get the seed stuff to work the way I wanted and hadn’t thought of using a local svnsync’d mirror when I first set this up, however.

Creating a Branch

Once the initial sync has completed, you are ready to create a new branch of FreeBSD. The command below creates a branch of FreeBSD 7.x.

# svk cp /foobsd/mirror/FreeBSD/stable/7 /foobsd/stable/7

You can now use this branch using regular Subversion commands if you wish. Recall that /foobsd in svk maps to the Subversion repository in /home/foobsd. Thus, to checkout the FooBSD 7.x branch, simply use this svn command:

# svn co file:///home/foobsd/stable/7

You can commit your local changes to this branch using svn. You can also create new branches off of this branch using svn as well.

Merging Changes from FreeBSD

Eventually you are going to want to pull in changes from FreeBSD to your local FooBSD branch. svk makes this fairly painless. Merging consists of two steps. First, you need to use svk sync to update your local mirror of the FreeBSD repository.

# svk sync /foobsd/mirror/FreeBSD

Second, you need to merge the changes into your local branch. Note that this only merges the changes that have been synced into your local FreeBSD mirror. It does not pull changes directly from the FreeBSD repository.

# svk smerge /foobsd/mirror/FreeBSD/stable/7 /foobsd/stable/7

svk will first prompt you for the log message. It will then begin merging changes and will prompt you to resolve any conflicts. Finally, it will commit the result. If you wish to check for conflicts without doing an actual merge, you can pass the -C argument to smerge.
As an additional step, I like to tag each import that I merge into my FooBSD so I can easily generate diffs later. I do this using a plain svn copy of the FreeBSD mirror branch:

# svn cp file:///home/foobsd/mirror/FreeBSD/stable/7 file:///home/foobsd/freebsd7/YYYYMMDD

Generating Diffs

To generate a diff of a FooBSD branch, simply use svn to compare the FooBSD tree against the most recent import.

# svn diff file:///home/foobsd/freebsd7/YYYYMMDD file:///home/foobsd/stable/7

Conclusion

This is certainly not the only way to maintain a customized version of FreeBSD. However, it is very easy to setup and maintain.