Wednesday, December 07, 2011

Find android branch names

Crossposted from stackoverflow.

mkdir /tmp/zug
pushd /tmp/zug
git clone
cd manifest
git branch -a | sed -n '/^ r/s,.*/,,p'|sort -u|column
rm -rf /tmp/zug

gives the following output

android-1.6_r1 android-2.2.1_r1 android-2.3.4_r1
android-1.6_r1.1 android-2.2.1_r2 android-2.3.5_r1
android-1.6_r1.2 android-2.2.2_r1 android-2.3.6_r0.9
android-1.6_r1.3 android-2.2.3_r1 android-2.3.6_r1
android-1.6_r1.4 android-2.2.3_r2 android-2.3.7_r1
android-1.6_r1.5 android-2.2_r1 android-2.3_r1
android-1.6_r2 android-2.2_r1.1 android-4.0.1_r1
android-2.0.1_r1 android-2.2_r1.2 android-4.0.1_r1.2
android-2.0_r1 android-2.2_r1.3 froyo
android-2.1_r1 android-2.3.1_r1 gingerbread
android-2.1_r2 android-2.3.2_r1 gingerbread-release
android-2.1_r2.1p android-2.3.3_r1 ics-mr0
android-2.1_r2.1p2 android-2.3.3_r1.1 master
android-2.1_r2.1s android-2.3.4_r0.9 tradefed

Tuesday, December 06, 2011

Modifying udev on Ubuntu so that an unpriveleged user can use Android adb on a physical Android device:

sudo touch /etc/udev/rules.d/51-android.rules
sudo ln -s /lib/udev/rules.d/51-android.rules
# make sure device is NOT plugged in
lsusb | cut -d" " -f 6 | sed 's/:/ /' > ~/.tmp
# plug in the device
lsusb | cut -d" " -f 6 | sed 's/:/ /' > ~/.tmp1
diff ~/.tmp ~/.tmp1 | sed -n '/^>/s/^..\([^ ]*\) \(.*\)/SUBSYSTEM=="usb", ATTR{idVendor}=="\1",ATTR{idProduct}=="\2", GROUP="plugdev"/p' | sudo tee -a /etc/udev/rules.d/51-android.rules > /dev/null
rm -f ~/.tmp ~/.tmp1
#unplug USB device
adb kill-server
sudo service udev restart
adb start-server
# you should be good to go.
adb devices # the new device should appear

If you need to check out all permissions for all USB devices:

find /dev/bus/usb -not -type d | xargs ls -l

For Kindle Fire:

It seems that it works if you edit ~/.android/adb_usb.ini and add 2 lines containing 0x1949 and 0x0006 and restart the adb server using adb kill-server adb start-server Also, the 51-android.rules file contains the Lab126 vendor id. (thanks r1k0)

Sunday, December 04, 2011

I use tightvnc a lot. It's a great way to keep the context of what you were doing going over time. Last weekend I set up a new Ubuntu 10.04 LTS based development box for developing Android applications. The problem was the vncserver I was using kept dying. It took awhile to figure out what the problem was -- I eventually noticed a line similar to the following in /var/log/messages:

Dec 4 09:18:00 bishop kernel: [317333.194448] Xtightvnc[8667]: segfault at 7fff3584c000 ip 000000000044e4f1 sp 00007fff3584a920 error 6 in Xtightvnc[400000+17e000]

After a bit more googling around, I found this article. That led me to this article explaining that the problem is in TightVNC 1.3.9 and is fixed in 1.3.10. It also explains how to implement the fix, but that implementation has some problems. So I set about fixing the problem myself. Below are the steps I came up with. They worked for me, but YMMV.

pushd ~
sudo apt-get install xorg-dev libjpeg62-dev zlib1g-dev xmkmf
mkdir -p vnc-problem/new
cd vnc-problem/new
tar xzf tightvnc-1.3.10_unixsrc.tar.gz
cd vnc_unixsrc
make World
cd Xvnc
time make
sudo mv /usr/bin/Xtightvnc /usr/bin/Xtightvnc-1.3.9
sudo cp programs/Xserver/Xvnc /usr/bin/Xtightvnc-1.3.10
sudo chown root:root /usr/bin/Xtightvnc-1.3.10
sudo chmod 755 /usr/bin/Xtightvnc-1.3.10
sudo update-alternatives --install /usr/bin/Xtightvnc Xtightvnc /usr/bin/Xtightvnc-1.3.9 50
sudo update-alternatives --install /usr/bin/Xtightvnc Xtightvnc /usr/bin/Xtightvnc-1.3.10 60
sudo update-alternatives --config Xtightvnc # choose Xtightvnc-1.3.10
sudo update-alternatives --set Xtightvnc /usr/bin/Xtightvnc-1.3.10

If this doesn't work for you, then you can go back with this command:

sudo update-alternatives --set Xtightvnc /usr/bin/Xtightvnc-1.3.9

At some point, if I get the chance, I'll try my hand at updating the Ubuntu package itself so that this can be fixed once and for all.

Labels: , ,

Friday, December 02, 2011

Here's a handy tidbit that will take the output of an strace and process it so you can figure out what are the likely errors:

sed -n '/= -1 E/s/.*= -1 \(.*\)/\1/p' strace.output | sort | awk 'BEGIN{last=""}{if (last=="")last=$1;if ($1==last)lines++; else {printf "%d %s\n",lines,last; lines=1;last=$1;}}END{printf "%d %s\n",lines,last}' | sort -n
3078 EBADF
25369 ENOENT
692843 EAGAIN

Wednesday, September 12, 2007

It's been awhile.

Here's how to use Clearcase's cleartool with rsync:

First, on the machine where clearcase is (ie, where you're pulling files FROM), create a script like so: (call it /bin/setviewrun)

while [[ -n "$1" && "$1" != "rsync" ]]; do
/usr/atria/bin/cleartool setview -exec "$*" $view

Now, on the machine where you want to copy the files to use this rsync command:

rsync -navz --rsh "ssh id@box /bin/setviewrun viewname" id@box:/path/to/file.txt .

Take the -n away once it actually works!

Thursday, May 11, 2006

C# Beautified Menu Entries

There are not many examples of how to do things in C# in a beautiful way. Even the O'Reilly examples are sometimes pretty crufty. Here's an example of how to create an entire menu, including submenus without any goofy placeholder variables.

public void CreateMenus() {
MenuStrip menu = new MenuStrip();
menu.Items.AddRange( new ToolStripItem[]{
new ToolStripMenuItem("&File", null,
new ToolStripMenuItem("&Close", null, new EventHandler(CloseMenu_Click)),
new ToolStripMenuItem("E&xit", null, new EventHandler(ExitMenu_Click)))
new ToolStripMenuItem("&Edit", null,
new ToolStripMenuItem("&New Thing", null, new EventHandler(EditNewThingMenu_Click)))
new ToolStripMenuItem("&Pen", null,
new ToolStripMenuItem("&Pencil", null, new EventHandler(PenMenu_Click)),
new ToolStripMenuItem("Bl&ack Pen", null, new EventHandler(PenMenu_Click)),
new ToolStripMenuItem("Bl&ue Pen", null, new EventHandler(PenMenu_Click)),
new ToolStripMenuItem("Eraser", null, new EventHandler(PenMenu_Click)))
foreach( ToolStripItem i in menu.Items)
i.Font = Global.MenuFont;
Global.ExplorerForm.MainMenuStrip = menu;

Friday, May 05, 2006

.NET PrintPreviewDialog very slow

I was having a problem with PrintPreviewDialog.ShowDialog() taking 10s of seconds to show any output. I did a single step from the ShowDialog() line and none of my code was in the way -- it took ~10 seconds to get to the first line of my PrintPageEventHandler. After some googling, I tried changing default printers from my network printer to PDFCreator and voila, proplem solved.

So the moral of the story is that if PrintPreviewDialog.ShowDialog() spends an inordinate amount of time just getting to your print routines, it's probably got something to do with the Windows print driver and not your code.

Wednesday, August 31, 2005

Setting Credentials of your Crystal Reports using your ConnectionString

When using Crystal reports with ASP.NET, you'll need to set the credentials for accessing the database because the .rpt file doesn't keep all of the login information (namely the password). You probably already have this info handy in Your Configuration Settings. This is a handy routine (I put mine in Global.asax.cs) to apply the credentials from your "ConnectionString" of your AppSettings to the CrystalDecisions.CrystalReports.Engine.Tables object.

public static void CrystalReportLogin(CrystalDecisions.CrystalReports.Engine.Tables tables) {
CrystalDecisions.Shared.TableLogOnInfo logOnInfo = new CrystalDecisions.Shared.TableLogOnInfo();
foreach( string s in System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"].Split(';')) {
string[] nv = s.Split('=');
switch(nv[0]) {
case "Password": logOnInfo.ConnectionInfo.Password = nv[1]; break;
case "User ID": logOnInfo.ConnectionInfo.UserID = nv[1]; break;
case "Initial Catalog": logOnInfo.ConnectionInfo.DatabaseName = nv[1]; break;
case "Data Source": logOnInfo.ConnectionInfo.ServerName = nv[1]; break;
foreach( CrystalDecisions.CrystalReports.Engine.Table table in tables)

With this in place, displaying a Crystal Report is as simple as this:

CrystalReportViewer1.ReportSource = reportDocument1;

Tuesday, July 26, 2005

NUnit - quick and easy

I searched for a quick and easy introduction to NUnit. There are some nice articles, but they all go into more detail than I want. I just want to take a look at something simple to see what all the fuss is about.

So, here's the smallest introduction to NUnit 2.2 you'll find. Hopefully after you've gone through this procedure you'll be able to see where you can use NUnit in your own projects. You'll then be ready to look at the more complex articles referenced at the end of this one.


The Procedure

  1. Download and install NUnit. This article was based on NUnit-2.2.0.

  2. Start Visual Studio.NET

  3. Create a blank solution.

  4. Within your blank solution, create a new project called "NUnitTesting".

  5. Within the "NUnitTesting" project, right click "References", then click on "Add Reference" in the context menu.

  6. Click the Browse button.

  7. Navigate to C:\Program Files\NUnit 2.2\bin

  8. Doubleclick nunit.framework.dll

  9. Click OK. You have just added the NUnit framework to your project.

  10. Modify the Class1.cs file so that it looks like this:

    using System;
    using NUnit.Framework;

    namespace NUnitTesting{
    public class CalcInt{
    public int add(int a,int b){
    return a+b;

    public class CalcIntTestFixture{
    CalcInt testCalcInt;

    [SetUp] public void Init(){
    testCalcInt = new CalcInt();

    [Test] public void AddSuccess(){

    [Test] public void AddFails(){
    Assert.AreEqual(3,testCalcInt.add(1,1)); // FAILS, 1+1 != 3

  11. Press Shift-Control-B to save/compile the dll

  12. Start->All Programs->NUnit 2.2->NUnit-GUI

  13. File->Open

  14. Navigate to the DLL that was created when you compiled 3 steps ago, and open it.

  15. Click on the Run button.

  16. One test should succeed, and one should fail -- hopefully the tests are simple enough to not need explanation.

  17. That's it! There is a lot more to learn about NUnit, but this article should give you some tools to get started.


Monday, June 27, 2005

Reading your Outlook Inbox from C# using OleDbDataAdapter

private void ListInbox()
string Mailbox = "Inbox";
string Provider = "Microsoft.Jet.OLEDB.4.0;Outlook 9.0";
string MAPILEVEL = "Mailbox - Lastname, Firstname";
string PROFILE = "Lastname, Firstname";
string TABLETYPE = "0";
string DATABASE = @"c:\temp";
DataSet ds = new DataSet();
DataTable dt = new DataTable();

string sql = string.Format(@"SELECT * FROM {0}", Mailbox);
string ConnectionString = string.Format(
OleDbDataAdapter da = new OleDbDataAdapter( sql, ConnectionString );
dt = ds.Tables["Outlook"];
dataGrid1.DataSource = dt;
catch (Exception ex)
MessageBox.Show("Error: "+ex.Message);

Saturday, June 11, 2005

Allow the UI to catch up on a windows forms app

for(a very long time)

Friday, June 03, 2005

How to hide null ASP.NET data fields

Say you have a bit of data called Symptoms that you want to display on your web page, and it contains a label (also called "Symptoms"). It might look something like this in your form:

Symptoms: <%# DataBinder.Eval(Container.DataItem, "Symptoms") %>

Now say, if there is no data in the database, you don't want the field to appear at all. I did some research to find a nice way to do this, but I didn't like any of them (if someone has a nice server side way of doing this (without peppering the html with >1 "DataBinder.Eval...", I'd like to hear).

So, here's my solution. First, decorate your html with a div and a span like this:

<div class="hide" id="SymptomsDiv">
<span id="SymptomsSpan"><%# DataBinder.Eval(Container.DataItem, "Symptoms") %></span>

Then add the following css classes:
<style type="text/css">
.hide{display: none;}
.show{display: block;}

And the following script code:

function sectionObjects(name){
o = new Object; = name;
o.div = document.getElementById(name+"Div");
o.span = document.getElementById(name+"Span");
return o;
window.onload = function(){
var sections = new Array;

// Show those sections that have data
for(var i = 0; i<sections.length; i++)
if (sections[i].span.innerHTML!="")
sections[i].div.className = "show";

All the sections (all one in this case) start out hidden. The onload function runs when the window loads. It finds any sections that are not null using .innerHTML -- this'll work on all modern browsers.

Thursday, June 02, 2005

An app specific bookmarklet that shows known hidden frames


ASP.NET Response.TransmitFile() sometimes fails with networked UNC files

Simply replace this:

With this:

Stream s = new FileStream( filename, FileMode.Open, FileAccess.Read );
const int bufLength = 1024;
byte[] buf = new byte[bufLength];
int red;
while( (red=s.Read(buf,0,bufLength))>0 )
if (Response.IsClientConnected)

UNC networked files error failure fail C# TransmitFile WriteFile

Tuesday, May 31, 2005

CacheDependency Limitation

As of ASP.NET 1.1, it looks like you can only get an ASP.NET cache item
to be dependent on about about 40 remote directories or so, then you'll run
into an arbitrary limitation of the ReadDirectoryChangesW win32 api
call. The exception generated will look something like this:

Failed to start monitoring changes to '\\Your\remote\directory'.

I doubt that this will be fixed in ASP.NET 2.0, since it is really a
limitation of the underlying OS.

This issue is especially ugly when you have to monitor a large number
of directories, such as an entire directory tree. It would be
nice if CacheDependency would allow you to monitor a deep directory --
that is, monitor if any changes were made to any file within an entire
tree structure. My guess is that this is just something the OS
does -- it would be a nice addition.

Supporting URLs:
(See the box titled "Under the Hood of the ASP CacheDependency" at the
bottom of the article)
(ReadDirectoryChangesW fails with ERROR_INVALID_PARAMETER...)

Tuesday, May 24, 2005

Calling a server side func in JavaScript with document.createElement('script')


The following bit of JavaScript and C# code work to gether to do
some remote scripting from the browser to the server.  Basically
some javascript function running on the client wants to call the
'ServerFunc' C# code, and pass it a single parameter named "user".


// Within a javascript function that wants to call the server:


// The ServerCall function calls a function in the MYPAGE.aspx on the server.

function ServerCall(call){

       var head      = document.getElementsByTagName("head")[0];

       var script    = document.createElement('script');

       script.src    = "MYPAGE.aspx?nocache="+new Date().getTime()+"&cmd="+call;


       script.type   = 'text/javascript';



NOTE: The rest is C# code in the aspx. If you're not into C#, replace this with whatever you like. The ServerCall() bits should still work.

// Within MYPAGE.aspx’s Page_Load(), we find the desired function and call it.

// Long live reflection

private void Page_Load(object sender, System.EventArgs e){

       // Find and execute the command

       MethodInfo m = GetType().GetMethod("page"+Request["cmd"]);

       if (m==null)

              m = GetType().GetMethod("pageDefault");



// the m.Invoke() in Page_Load() calls this function.  Note, we prepend each page

// function with the word 'page' -- this way baddies can't run arbitrary funcs

public void pageServerFunc(){

       string user = Request["user"]; // This came from the client


       Script.Append("alert('You can do anything in here');");

       Script.Append("SomeClientFunc('Then call a client func to wrap up!');");





StringBuilder script = new StringBuilder();

Wednesday, January 14, 2004

How to use ldapsearch...

[root@prm99ws1 root]# ldapsearch -x -D cn=manager,dc=zzz,dc=net -w ##PASS## -H ldaps:// -b "dc=zzz,dc=net" -s sub "(uid=uidofuser)"
version: 2

# filter: (uid=uidofuser)
# requesting: ALL

bla bla bla...

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

Tuesday, April 29, 2003

Converting a file to/from hex using Perl

I needed to store binary images in Pick. Pick, of course, doesn't like to store binary (it can't deal with char(255)), so I deceded to convert to hex. I could have uuencoded but hex is fine for my purposes.

So here's how to convert a file.gif to file.gif.hex:
perl -n0777e 'print unpack "H*",$_' < file.gif > file.gif.hex
To convert it back:
perl -n0777e 'print pack "H*",$_' < file.gif.hex > newfile.gif

Sunday, April 06, 2003

Hacking the D3 Executable

Ok, here's the problem. D3's filesystem osfi is set to create files with 660 permissions (rw ower, rw group, nothing other). This is secure, but if you want to create files that will work for other users, you have to then go in and change the permissions. And if you have a boat load of software that doesn't do this, then it just doesn't work out well. What you'd really like to do is create all files with 777 (rwx for everybody) and let the umask mask out the unwanted bits (umask of 117 will give you the original result).

At first, this seemed easy, Raining Data gives you the source to rp_driverux.c. But alas, they don't give you the rp_driverux.h source, so you can't compile it. And in our special circumstance, we can't build coff files anyway. So I was left with the second alternative -- using a binary editor to change the executable code. The rest of this howto details how I did it.

Within /usr/lib/pick/rp_driverux.c you'll find:

static int
rp_upditm( long fd, rp_hdr *hd, unsigned char *buf, int length )
int code = -1;
unsigned char *p, *q;
int localfd;
localfd = RP_FDNUM(fd) - 1; /* Translate FD into table index */
. . .
/* Go open it */
if ((code = rp_retixux(localfd,O_WRONLY | O_TRUNC | O_CREAT,0660)) < 0)
hd->rp_rtncd = code;
return code;
. . .

The code=rp_retixux... line contains the permissions, 0660. This is the trouble spot. To find this in the actual d3 executable is pretty simple. (Note: there is probably a better way, but this worked for me).

First step is to disassemble the d3 executable into a file: dis /usr/bin/d3 > /tmp/d3.dis

This d3.dis file can now be examined. We know that we're looking for a function named rp_upditm, so just vi the file and search for it. For me, it looked something like this:

8054ed8: e9 79 03 00 00 jmp 0x379 <8055256>
8054edd: 90 nop
8054ede: c7 45 fc ff ff ff ff movl $0xffffffff,-4(%ebp)
8054ee5: 8b 45 08 movl 8(%ebp),%eax
8054ee8: 25 ff ff 00 00 andl $0xffff,%eax
8054eed: 48 decl %eax
8054eee: 89 45 f0 movl %eax,-16(%ebp)
. . .

Now, search for 1b0 (which is 0660 in hex). Voila, you found the code:

. . .
805504d: ff 48 08 decl 8(%eax)
8055050: 68 b0 01 00 00 pushl $0x1b0
8055055: 68 01 03 00 00 pushl $0x301
(NOTE: I showed the line before and after too)

The pushl $0x1b0 is the push of the 0660 onto the stack for the call to rp_retixux(). Now all we need to do is change the 0660 to 0777 (1b0 to 1ff). To do that, we need the offset. I could have probably figured it out using the address (0x8055050), but I decided just to search for it since I had the object code available. To do that, I did "od -x d3 > d3.od" to create a hex dump of the file, then I did a grep for "b068". Here's the output I got:

# grep "b068" d3.od
0025760 0000 b068 12c5 e808 71d4 000c 6859 c1f4
0043260 0812 b068 12cd ff08 6835 12c3 6a08 e800
0044360 b068 12ce 6808 dcec 0814 b9e8 0ba5 8300
0046100 b068 0003 ff00 7c35 12c3 a108 c850 0815
0056420 1de9 0001 9000 b068 0003 6a00 a105 c850
0056560 5900 016a 37e8 0cba 5900 b068 0003 ff00
0056720 b068 0003 a100 c850 0815 000d 0000 5080
0072260 31eb b068 04f4 6a08 e805 a22a 000c c483
0074600 0f6a 11e8 ffff 83ff 0cc4 b068 04f4 6808
0150120 b068 0001 6800 0301 0000 75ff e8f0 101e
0566300 cde8 0995 8300 10c4 c085 0b7d b068 1322
1127720 038b c085 0d74 b068 1552 e808 0a10 0000
1142660 c483 eb10 8325 00c7 b068 1559 0f08 07bf
1227600 ac15 1361 e808 1366 0000 b068 156b 6808
1363440 4875 94a3 1612 eb08 836d 00c7 b068 1579
1477540 c35d 9090 b068 13df e808 d526 ffff c483
1514440 47f8 088b f93b 847e b068 13e8 e808 bb62
3367300 b85f 0001 0000 e58b c35d 9090 b068 1526

Looking through you'll find the one we want is at 0150120. A couple of things to remember: this is a sco machine so the bytes are switched in words (16 bit). Also, you need the context of the object code around it (from the assembly listing) to distinguish the correct line. Also remember, the offset is in octal (0150120 = 0xd050). For awhile I thought it was decimal which threw me off a bit.

Now that you have the offset of the change and the change to make, you just need to make it. You could write a C program to do it, but I just found myself a hex editor and used it. I copied the d3 exec to my laptop and used frhed to modify it. Then I sent it back.

Wednesday, March 19, 2003

How to do a HTTP request with authentication by hand:

  1. Let's say your user:pass is fred:supersecret
  2. /bin/echo -n "fred:supersecret" > /tmp/x
  3. uuencode -m /tmp/x /tmp/y
    You'll get:
    begin-base64 644 /tmp/y
  4. Copy the ZnJIZ... string (including the == at the end) to your cut buffer. This is your uuencoded user:password.
  5. telnet 80
  6. Type in: GET /path/to/file.html HTTP/1.0
  7. Optionally type in: HOST:
  8. Type in: Authorization: BASIC ZnJlZDpzdXBlcnNlY3JldA==
  9. Type in: A Blank line
  10. You should get the output web page now.

Friday, March 14, 2003

How to upgrade Red Hat 8.0's apache RPMs to the latest Apache release

  1. rpm -i /rhs80.2/SRPMS/httpd-2.0.40-8.src.rpm
    Install the Apache source RPM. Ignore the warning. You may need to get the src.rpm file from the CD directly.
  2. cd /usr/src/redhat
    Go to the Red Hat sources directory
  3. wget
    Get the latest version of Apache. Go to and follow the download link.
    Read this tedious set of gpg instructions about how and why you should verify the code. Ho hum.
  5. mv httpd-* SOURCES
    Move the source you just downloaded into the SOURCES directory
  6. vi SPECS/httpd.spec
    Make the following changes:

    • Version: 2.0.40 -> 2.0.44
    • Release: 8 -> jl1
    • Comment out the line that says %patch3 -p0 -b .sslink
    • Comment out the line that says %patch40 -p0 -b .cnfdir
    • Comment out the section that has the comment "fix man page paths"
    • Change all occurances of "libapr\." to "libapr-0\."
    • Change all occurances of "libaprutil\." to "libaprutil-0\."
    • Comment out the line that says %{_mandir}/man8/apachectl*.
    • Comment out the line that says %{_mandir}/man8/httpd*.
    • Find the line that reads: "--enable-deflate \". Add a line after it that reads: " --with-ldap --enable-ldap --enable-auth-ldap \". The tab before the "--enable" and the backslash after the end are very important.
    • Add a changelog entry
    • And here's the diff:

      < Version: 2.0.40
      < Release: 8
      > Version: 2.0.44
      > Release: cli1
      < %patch3 -p0 -b .sslink
      > #%patch3 -p0 -b .sslink
      < %patch40 -p0 -b .cnfdir
      > #%patch40 -p0 -b .cnfdir
      > --with-ldap --enable-ldap --enable-auth-ldap 225,232c226,233
      < sed -e "s|/usr/local/apache2/conf/httpd.conf|/etc/httpd/conf/httpd.conf|"
      < -e "s|/usr/local/apache2/conf/mime.types|/etc/mime.types|"
      < -e "s|/usr/local/apache2/conf/magic|/etc/httpd/conf/magic|"
      < -e "s|/usr/local/apache2/logs/error_log|/var/log/httpd/error_log|"
      < -e "s|/usr/local/apache2/logs/access_log|/var/log/httpd/access_log|"
      < -e "s|/usr/local/apache2/logs/|/var/run/|"
      < -e "s|/usr/local/apache2|/etc/httpd|" < docs/man/httpd.8
      < > $RPM_BUILD_ROOT%{_mandir}/man8/httpd.8
      > #sed -e "s|/usr/local/apache2/conf/httpd.conf|/etc/httpd/conf/httpd.conf|"
      > # -e "s|/usr/local/apache2/conf/mime.types|/etc/mime.types|"
      > # -e "s|/usr/local/apache2/conf/magic|/etc/httpd/conf/magic|"
      > # -e "s|/usr/local/apache2/logs/error_log|/var/log/httpd/error_log|"
      > # -e "s|/usr/local/apache2/logs/access_log|/var/log/httpd/access_log|"
      > # -e "s|/usr/local/apache2/logs/|/var/run/|"
      > # -e "s|/usr/local/apache2|/etc/httpd|" < docs/man/httpd.8
      > # > $RPM_BUILD_ROOT%{_mandir}/man8/httpd.8
      < %{_libdir}/*
      < %{_libdir}/*
      > %{_libdir}/*
      > %{_libdir}/*
      < %{_mandir}/man8/apachectl*
      < %{_mandir}/man8/httpd*
      > #%{_mandir}/man8/apachectl*
      > #%{_mandir}/man8/httpd*
      < %{_libdir}/
      < %{_libdir}/
      > %{_libdir}/
      > %{_libdir}/
      > * Fri Mar 14 2003 John Lombardo 2.0.44-cli-1
      > - Make it work with Apache 2.0.44 (so we get mod_auth_ldap)

  7. rpmbuild -ba SPECS/httpd.spec
    Finally, you can build the bugger. This will take a few minutes, even on a fast machine. Pay attention to the last thing it says. If it worked it should tell you about your new RPMs, if not, the final few (50 or so) lines will probably tell you where it went wrong.
  8. You should now have the following new files:

    • SRPMS/httpd-2.0.44-cli1.src.rpm
    • RPMS/i386/httpd-2.0.44-cli1.i386.rpm
    • RPMS/i386/httpd-devel-2.0.44-cli1.i386.rpm
    • RPMS/i386/httpd-manual-2.0.44-cli1.i386.rpm
    • RPMS/i386/mod_ssl-2.0.44-cli1.i386.rpm

Install them and you're done. (Don't forget to uninstall the old ones first!)

Tuesday, March 04, 2003

"The corollary of constant change is ignorance. This is not often talked about: we computer experts barely know what we're doing." (Ellen Ullman)

Friday, February 28, 2003

How to send email w/o a mail client

Note: you have to telnet to your email server
[jl@www jl]$ telnet 25
Connected to
Escape character is '^]'.
mail from:
250 ok
rcpt to:
250 ok
354 go ahead
Subject: This is a hand _made_ message
Hi Arthur,
How are you today?

250 ok 1046474020 qp 32526
Connection closed by foreign host.

And so here is my first LDAP schema. It's pretty simple, it just holds the D3 server and SSH Public key for a user. It goes in /etc/openldap/schema/cli.schema on Red Hat Linux using OpenLDAP:

# My Fabulous private schema
# 1 3 6 1 4 1 15823 1 1 1
# 1 3 6 1 4 1 15823 1 1 2
# Created by: John Lombardo <>

# Attribute Type Definitions

attributetype ( NAME 'SSHPublicKey'
DESC 'Public key for ssh'
EQUALITY caseExactIA5Match

attributetype ( NAME 'DBHost'
DESC 'Which DB server does this user use.'
EQUALITY caseIgnoreIA5Match

# Object Class Definitions

objectclass ( NAME 'CliUser'
MUST ( uid )
MAY ( SSHPublicKey $ D3Host )

This is about a month old, but it bears blogging: The IANA has assigned the following Private Enterprise Number to 15823

The prefix is: (

I'm assigning the .1 sub-code for use at my customer.

Thursday, February 27, 2003

These are the notes and important command lines that we learned today on how to build PDF files from TIFF (or other graphic format) files.

The test stuff is here: /var/www/dev/html/test/x

Here's the command to build the pdf:
htmldoc --header ... --footer ... --webpage --bottom 0 --top 0 --left 0 --right 0 -f jl.pdf a1.html 2> /dev/null

Here's what the HTML file should look like (a1.html in the above line):

<!-<img src="1/fred.img319.001.gif" width="100%" height="130%">-->
<img src="y.gif" width="100%" height="130%">

Here is our first attempt at trying to convert the tiff to a gif. It works, except that it's inversed:
tifftopnm tiff.tif | ppmquant 256 | ppmtogif > GIF.gif
These programs are all part of the netpbm-progs-9.14-2 package.

HTMLDOC is the groovy package that converts html (and through it gif, jpeg, others) to pdf. It can do it both on Windows and on Linux. A command line version is available.

And this is the magic command line that makes it all work...
X=1/fred.img319.011; tiff2rgba $X x.tif; tifftopnm x.tif | ppmtogif > z.gif ; htmldoc --header ... --footer ... --webpage --bottom 0 --top 0 --left 0 --right 0 -f jl.pdf a1.html

It turns out that the Image Magick package works better than the netpbm stuff for what we need.

So here's a script that converts all of the listed files into one big PDF file using HTMLDOC and ImageMagick. Cool.

# mkpdf: make a pdf out of a bunch of graphic files
OUT=$1; shift
if [ -e $OUT ]; then
echo $OUT already exists
exit 1
mkdir $DIR
while [ -n "$1" ]; do
cat <<DONE >$DIR/$i.html
<html><body><img src="$i.png" width="100%" height="130%"></body></html>
# tiff2rgba $1 $DIR/x.tif
# tifftopnm $DIR/x.tif | ppmtogif > $DIR/$i.gif
convert $1 $DIR/$i.png
FILES="$FILES $DIR/$i.html"
htmldoc --header ... --footer ... --webpage --bottom 0 --top 0 --left 0 --right 0 -f $OUT $FILES
rm -rf $DIR

Tuesday, February 25, 2003

One more thing about the email server; I wanted to try my email list test again (send an email to a test list of 50 test users). So I changed the loglevel-send back to 127. When I sent to the test list, I had troubles. After I changed the loglevel-send back to nothing (file exists, but is empty), my list went through with no trouble. Hmmm, seems that having a loglevel can muck things up a bit.

One other thing: when I restarted with the message in the queue, I got double entries in my test users email accounts for the same message. Yuck.

Here's the command line for showing what's in the test email boxes:

for i in `awk 'BEGIN{for(i=0;i<=49;i++)print i}'`;do /bin/echo -n "$i ";ls test$i/Maildir/new;done

Well, that (see yesterdays blog) didn't work. I got a call from the admin this morning that email didn't work, and sure enough it was not delivering mail at all. I undid the change to /var/qmail/control/ldaptimeout and restarted. It took about 5 restarts ((vi /etc/inittab; kill -HUP 1)*2), but eventually it got through the whole deliver queue. The problem still remained of why was this happening. One clue was found by setting /var/qmail/control/loglevel-send to 127 and restarting. I would get something like exhibit 1, except the "success" time was a minute and a half later than the "executing..." time.

The other big clue was that "top" on the openldap server box showed slapd pegged at close to 100% of the cpu. This told me that OpenLDAP was too busy.

Upon further examination of exhibit 1, I noticed that the mailAlternateAddress was being searched every time. The "mail" field is indexed by default, but the mailAlternateAddress was not indexed. I changed the /etc/openldap/slapd file on the OpenLDAP server by adding the line index mailAlternateAddress eq, and that seems to have fixed everything up quite nicely.

Along the way, I developed two useful utilities for looking at the logs; delivery and deliveries. Delivery's output is shown in exhibit 1. It shows all the information about a specific delivery. The source is in exhibit 2. Deliveries simply shows multiple deliveries. It's source is in exhibit 3.

Exhibit 1

[root@mail qmail]# ./delivery 42

2003-02-25 15:48:18.344906500 starting delivery 42: msg 451289 to local
2003-02-25 15:48:18.402715500 delivery 42: log: LOGLEVEL_set_to_127/
2003-02-25 15:48:18.402858500 delivery 42: log:
2003-02-25 15:48:18.422529500 delivery 42: log: ldapfilter:_'(|( ...
2003-02-25 15:48:18.431933500 delivery 42: log: ldap_get_userinfo:_qmailUID:_
2003-02-25 15:48:18.432307500 delivery 42: log: 508_(default)/
2003-02-25 15:48:18.435458500 delivery 42: log: homeDirectory=/u/eddie_(from_server)/
2003-02-25 15:48:18.439944500 delivery 42: log: found:_user='eddie'_uid=508_gid=508_...
2003-02-25 15:48:18.441235500 delivery 42: log: executing_'qmail-local_--_eddie_/u/eddie_...
2003-02-25 15:48:18.604907500 delivery 42: success: did_1+0+0/

Exhibit 2: delivery


CAT="@* current"
cat $CAT | grep "delivery $1:" | /command/tai64nlocal

Exhibit 3: deliveries


if [ -z "$START" ]; then
echo "$0 usage:"
echo "$0 r1 {r2}"
echo "if r2 is not given, then deliveries 1-r1 are shown, else"
echo "deliveries r1-r2 are shown"
exit 1
if [ -z "$FINI" ]; then

for i in `awk 'BEGIN{for(i='$START';i<='$FINI';i++)print i;}'`;do
./delivery $i
/bin/echo -n "continue: "
read x

Monday, February 24, 2003

I've modified the /var/qmail/control/ldaptimeout so that it now takes 120 seconds (2 minutes) for an LDAP connection to timeout. The default is thirty seconds. People who send messages to lists have been getting bounce messages that look like this:
Hi. This is the qmail-send program at

I'm afraid I wasn't able to deliver your message to the following
This is a permanent error; I've given up. Sorry it didn't work out.

Sorry, no mailbox here by that name. (#5.1.1)

--- Below this line is a copy of the message.

Friday, February 21, 2003

Working on my client's email server.

Created three new /var/qmail/control files that contain the loglevels for different services

The problem is this. When delivering to a large ldap list ( for example), some of the deliverys fail with this error message:

@400000003e56be0628768734 starting delivery 54492: msg 450906 to local
@400000003e56be65359844ac delivery 54492: failure: Sorry,_no_mailbox_here_by_that_name._(#5.1.1)/

On Monday, I'll create a bunch of test users in cvs2ldif and a list to send to them all. Then I can test this extensively.
In the being careful dept, I should rebuild the qmail binaries before making any changes, then cmp them to the binaries that are in /var/qmail/bin to make sure that I have the right version of stuff.

Linux Certification:

Doh! Query programs work so much better when you tell them what, exactly, you are querying. I had harvested the CHLReferenceNumber from the request response:

CHLReferenceNumber = node.Attributes["CHLReferenceNumber"].Value;
} catch( Exception e){
throw new Exception(" get error: "+e.Message);

But I forgot to put the CHLReferenceNumber in my Response query. It's in there now:

node = xml.DocumentElement.SelectSingleNode("//EQUAL_RESPONSE_QUERY");
try {
node.Attributes["CHLReferenceNumber"].Value = CHLReferenceNumber;
} catch (Exception){
throw new Exception(" set error");

Crazy morning: raquetball, back and forth to Cam's school, finally to work at 10:00. Still can't figure out why PD is not working. CW has fixed their credit reporting problem, but still it times out. Investigating...

Thursday, February 20, 2003

Ok, I admit it -- I really like C# (and visual studio -- I'm going to mix them up here). They're really cool for several reasons:

C# get current thread
int tid = System.Threading.Thread.CurrentThread.GetHashCode();
This doesn't seem to be the same as the thread id, but can be used in a similar way.

C# format strings: See the nutshell book

DateTime t = System.DateTime.Now;
"{0:00}{1:D2}{2:D2} {3:D2}:{4:D2}:{5:D2}+{6:D4} {7}",
t.Year-2000, // Y21K!
t.Month, t.Day, t.Hour, t.Minute,
t.Second, t.Millisecond, s );

Is Tarentella TE3 useful for my client?

"TE3 can take most legacy terminal emulation and display protocols, Remote Desktop Protocol (RDP) for Windows Terminal Server, and any Java-wrapped application, and resolve them to one display protocol for shipment to a Java-enabled Web browser or Tarantella's own proprietary thin client."
       -- ZD Net

Showing Dena my blog...

> From: Lynn []
> Sent: Thursday, February 20, 2003 8:22 AM
> did you make up the word snarf? I've never heard of it before! I'm assuming it means stolen/copied/pirated, correct?

I replied:

Snarf has a long and hallowed history...

It's actually a command line utility too...

Moved blog from to

Power failed last night. Everything seems to have rebooted nicely. The only problem was the time setting for the gl2 box. Gotta fix that in CMOS some time.

Wednesday, February 19, 2003

Just got back from the Ducks game. They won against the Blue Jackets 2-0. The last point came in the final seconds against a golie-less net.

I went with Bevan. We sat in really great seats -- a "suite" actually, with a couch and leather seats!

The csv2ldif python program converts the user database CSV file exported from Outlook to ldif, which is then imported to our LDAP database. It has been modified so that it now adds two new lines:

objectClass: sambaAccount

Here are the changes that were made:

> o.outnv( "objectClass","sambaAccount")
> if userPassword!="":
> ntpass = os.popen("mkntpwd -N "+userPassword).read();
> ntpass = string.rstrip(ntpass);
> o.outnv( "ntPassword", ntpass)

Note the use of the new "mkntpwd" program. It's source is in the /usr/src/mkntpwd directory of It was snarfed from the internet at this address:

This page is powered by Blogger. Isn't yours?