Readline and rlwrap

I came across a neat little tool called [rlwrap](http://utopia.knoware.nl/~hlub/rlwrap/), which essentially wraps the functionality of [readline](http://tiswww.case.edu/php/chet/readline/rltop.html) (line editing, history, etc) for any other command line utility. For example, it works well with my [GCCalc](http://tlrobinson.net/blog/?p=31) hack, which I didn’t bother to integrate readline into, but rlwrap gives you the same thing for free:

rlwrap gccalc

It’s useful with many other tools, like telnet and netcat, and interactive interpreters that don’t have line editing or history, like [Rhino](http://www.mozilla.org/rhino/) (Javascript) and others.

Overriding library functions in Mac OS X, the easy way: DYLD_INSERT_LIBRARIES

Back at MacHack 2003 Jonathan Rentzsch talked about how to override functions and inject code in Mac OS X using [several neat tricks](http://rentzsch.com/papers/overridingMacOSX). He also released a framework called [mach_star](http://rentzsch.com/mach_star/) which has two components: mach_override and mach_inject. These are great, but overkill for some simple cases.

A much easier way of doing library function overrides is using the DYLD_INSERT_LIBRARIES environment variable (analogous to LD_PRELOAD on Linux). The concept is simple: at load time the dynamic linker (dyld) will load any dynamic libraries specified in DYLD_INSERT_LIBRARIES before any libraries the executable wants loaded. By naming a function the same as one in a library function it will override any calls to the original.

The original function is also loaded, and can be retrieved using the dlsym(RTLD_NEXT, “function_name”); function. This allows a simple method of wrapping existing library functions.

Here’s a simple example which prints out the path of every file opened using the “fopen” function (lib_overrides.c):

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>

// for caching the original fopen implementation
FILE * (*original_fopen) (const char *, const char *) = NULL;

// our fopen override implmentation
FILE * fopen(const char * filename, const char * mode)
{
    // if we haven’t already, retrieve the original fopen implementation
    if (!original_fopen)
        original_fopen = dlsym(RTLD_NEXT, "fopen");

    // do our own processing; in this case just print the parameters
    printf("== fopen: {%s,%s} ==\n", filename, mode);
    
    // call the original fopen with the same arugments
    FILE* f = original_fopen(filename, mode);
    
    // return the result
    return f;
}

And a simple test program (overrides_test.c):

#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char hello[] = "hello world";
    
    FILE *fp = fopen("hello.txt", "w");
   
    if (fp) {
        fwrite(hello, 1, strlen(hello), fp);
        fclose(fp);
    }

    return 0;
}

Compiled and tested:

tlrobinson$ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c
tlrobinson$ gcc -Wall -o overrides_test overrides_test.c
tlrobinson$ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib overrides_test
== fopen: {hello.txt,w} ==
tlrobinson$

There are certainly scenarios far more interesting than this, though!

Presenting GCCalc: a horrible abuse of GCC

Following an [interesting discussion on Reddit](http://programming.reddit.com/info/62v70/comments) about [first class functions](http://en.wikipedia.org/wiki/First-class_function) in C, I was inspired to see what I could do with this new-found knowledge. The result is what I affectionately call “GCCalc”, for reasons that will become clear below.

GCCalc is a simple command line calculator, much like the common [bc](http://en.wikipedia.org/wiki/Bc_programming_language) calculator on many Unix systems. It’s implementation, however, is *very* different than most calculators. While bc is said to have “C-like syntax”, GCCalc’s syntax *is* C. Whatever you enter on the command line automatically gets compiled, loaded, and executed, and the result is returned (as a double) and printed to the screen.

You can either enter expressions like:

round(46.95886*sqrt(1+2/9.99*sin((21%5)*pow(2,8))))

or you can enter whole C statements (as long as they’re on one line, for now) like:

int i; for (i=0;i<10;i++) { printf("hello world!\n"); } printf("goodbye\n"); Unfortunately variables are scoped to the function that wraps them, so they don't persist across multiple entries. However, you can access the last result using the "last" variable (a double). [Here's the source file](http://tlrobinson.net/projects/gccalc/gccalc.c), and here's a syntax highlighted version: It's been tested on Mac OS X (Leopard) and Linux (Ubuntu Gutsy), with GCC 4. Compile with "gcc -o gccalc gccalc.c" on OS X, or "gcc -o gccalc gccalc.c -ldl" on Linux.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <unistd.h>

#ifdef __ELF__
#define GCC_FLAGS "-fPIC -shared"
#define EXTENSION "so"
#else
#define GCC_FLAGS "-dynamiclib"
#define EXTENSION "dylib"
#endif

#define HEADERS "#include <stdio.h>\n#include<math.h>"

typedef double(func_return_double)(double);

unsigned count = 0;
char *cwd;
char tmp_path[1024] = {‘\0’};

void *lib = NULL;

int main(int argc, char **argv)
{
    double result = 0.0;
    char input_buffer[1024], code_buffer[2048], function_name[32], command_buffer[1024];
    
    // get out current directory, which we’ll use for tmp files (dlopen seems to need absolute paths)
    cwd = getcwd(NULL, 0);
    
    while (1)
    {
        // for unique function and file names (needed for dlopen/dlsym to work correctly)
        count++;
        
        // read in the next line
        printf(">> ");
        fgets(input_buffer, sizeof(input_buffer), stdin);
    
        // format the function name
        sprintf(function_name, "f%d", count);
        
        // format the code string: if it doesn’t contain a semicolon, assume it is just an expression
        if (strchr(input_buffer, ‘;’))
            sprintf(code_buffer, "%s\ndouble %s(double last) { %s\nreturn 0; }", HEADERS, function_name, input_buffer);
        else
            sprintf(code_buffer, "%s\ndouble %s(double last) { return (%s); }", HEADERS, function_name, input_buffer);
            
        // format the filename string, delete the file if it exists
        sprintf(tmp_path, "%s/libtmp%d.%s", cwd, count, EXTENSION);
        unlink(tmp_path);
        
        // format the gcc command string
        sprintf(command_buffer, "gcc -Wall %s -x c – -o %s", GCC_FLAGS, tmp_path);
        
        // execute gcc command, write out the code
        FILE *fp = popen(command_buffer, "w");
        fwrite(code_buffer, 1, strlen(code_buffer), fp);
        fprintf(fp, "\n");
    
        // pclose waits for gcc to terminate (fclose/close do NOT thus compilation will sometimes not finish prior to the dlopen)
        pclose(fp);

        void *ptr = NULL;
        
        // open the just-compiled dynamic library
        if ((lib = dlopen(tmp_path, RTLD_NOW|RTLD_LOCAL)) == NULL) {
            puts(dlerror());
        }
        // get the function pointer
        else if ((ptr = dlsym(lib, function_name)) == NULL) {
            puts(dlerror());
        }
        
        // execute it
        if (ptr != NULL)
        {
            func_return_double *func = (func_return_double*)ptr;
            result = (*func)(result);
            // print the result
            printf("=> %.*lf\n", (result/((int)result)>1.0)?5:0, result);
        }

        // clean up: close the library, delete the temp file
        dlclose(lib);
        unlink(tmp_path);
    }

    return 0;
}

Thanks to jbert on Reddit for the initial code and inspiration.

If only I had known about this back when The Daily WTF has having their [OMG WTF](http://omg.thedailywtf.com/) crazy calculator programming contest…

Geolocation possibilities on the iPhone

Ever since the iPhone was announced, I thought it would be really cool if it had a GPS receiver, or at the very least was able to find your general location via cell phone tower triangulation (technically [trilateration](http://en.wikipedia.org/wiki/Trilateration)). The obvious benefits of such a system would include automatic positioning of Google Maps to your location, or geotagging of photos taken on the iPhone’s (surprisingly decent) camera. Unfortunately, no such feature was included in the iPhone.

Now that a decent set of developer tools has been put together by hackers, there is the possibility of adding something like this. A few other people, including the famed [geohot](http://iphonejtag.blogspot.com/2007/08/im-at-rit.html), have also expressed interest in such a project. This is a summary of my endeavor so far to add some sort of location finding tool to the iPhone.

### Cell Tower Triangulation / Trilateration ###

The basic idea behind cell tower [triangulation](http://en.wikipedia.org/wiki/Triangulation) and [trilateration](http://en.wikipedia.org/wiki/Trilateration) is to locate the phone’s position relative to the cell towers by using the angles and distances between them, respectively.

Triangulation on the phone is impractical since there’s no way to easily measure the angles between the phone and the cell towers.

Trilateration is *sort of* possible by using the signal strengths to estimate the distance to the cell towers. This is very inaccurate due to multipath interference from stationary and moving objects, variation in cell tower antennas and equipment, etc. However, it would be *good enough* to get an approximate location to be used in Google Maps or rough geotagging of photos, assuming you know where all the cell towers are and can get their identities and signal strengths from the phone. That’s where the problem is.

### Issues with Trilateration ###

Cell towers locations are *supposed* to be public information, and the FCC does have a database called the [Antenna Structure Registration](http://wireless.fcc.gov/antenna/) (ASR)… BUT it’s missing many towers (it’s rumored to be about 25% complete), and the bigger problem is the networks aren’t required to provide the cell IDs along with the locations (and I doubt they would want to), so there’s no way to directly match a cell ID / signal strength from the phone to an actual physical location in the ASR database.

FCC ASR:
[http://wireless.fcc.gov/antenna/](http://wireless.fcc.gov/antenna/)
[http://wireless.fcc.gov/uls/](http://wireless.fcc.gov/uls/)

There’s *supposedly* more complete databases, such as [towermaps.com](http://www.towermaps.com), but again I don’t think they have the cell tower IDs, and even worse they charge $500 per COUNTY. There’s also [cellreception.com](http://www.cellreception.com) but it apparently just repackages the ASR data. I’m sure there’s others, but nothing I’ve come across is suitable. Let me know if you find something.

### Signal Strength Signatures ###

An alternative to triangulation and trilateration is to simply record a “fingerprint” of the cell tower signal strengths at every location you wish to be able to recognize. Then, when you want to find out where you are, simply take a reading of signal strengths, and compare them to the recorded fingerprints, picking the one that matches most closely.

The advantage of this is that you don’t need to know the exact locations of every cell tower, and it takes into account interference from buildings, land masses, etc. The obvious disadvantage is that you must map out every location where you want coverage. You must “cell-stumble”, the cellular equivalent of war driving.

A project that’s similar to this, but with Series 60 phones, exists at [GSMLoc.org](http://www.gsmloc.org) but they only have very limited data in a few scattered locations, and they appear to have pretty much abandoned the project.

### GPS ###

A built in GPS receiver in the iPhone would be the ideal solution, but of course this is out of the question at least until iPhone “2.0” (wink wink Apple).

Bluetooth GPS support for the iPhone would be awesome as well. It would require the Bluetooth serial port profile, which I would be surprised if the iPhone already has. iPhone uses the [BLUEmagic Bluetooth stack](http://www.oi-us.com/Uploads/File/Bluemagic_Brief.pdf) which is “modular”… it’s unlikely that Apple would pay for unnecessary modules or include them if they did. Maybe someone could port an existing open source Bluetooth stack to the iPhone ([Bluez](http://www.bluez.org/), perhaps? OS X probably isn’t similar enough to Linux for that to be easy). Worst case, we could use a laptop as the missing link (iPhone -> WiFi -> laptop <- serial/USB/bluetooth <- GPS) but that seems like a really poor solution. Maybe iPhone <- serial <- GPS? ### Moving Forward ### The first thing that needs to be done is to figure out how to get the cell tower IDs, signal strength, etc programmatically from the iPhone. Obviously this is possible since FieldTest.app is able to do it. I don't think it's as simple as sending AT commands directly to the baseband, since you can't do that unless CommCenter is disabled, which of course disables the phone features (obviously unacceptable in this case). Also, I have tried disabling CommCenter and sending "AT+CREG=2" then "AT+CREG", which should give signal strength, but wasn't getting anything useful back (perhaps because CommCenter was disabled and the phone wasn't connected to any cells?) Once that's done, we could interface with GSMLoc.org but again, their coverage is extremely sparse, and I don't think their approach is the best (they don't store signal strengths, which would be good for fingerprinting). It would be a good first step though. The mapping of fields in FieldTest.app to the GSMLoc.org database fields is as follows:

FieldTest.app GSMLoc.org Notes
# Net #1
Network Net #2
Location LAC
Cell id CellId Only the first entry appears to be valid, all others are “65535”
Station
Freq
Rx Level
C1
C2

The next step would be to do our own “cell stumbling”, but that would require interfacing the iPhone with a real GPS receiver… again, problematic. See above.

Once we’re able to get cell tower IDs and signal strength correlated to lat/lon coordinates we can either add to the GSMLoc.org database or start our own. GSMLoc’s database of coordinate/cell id pairs seems too simplistic for accurate fingerprinting or trilateration.

Joel De Gan wrote about [matching this data up with the FCC records](http://blog.peoplesdns.com/archives/34), but I’m not convinced that’s necessary. I think the fingerprinting approach would be better. Simply store the raw readings of cell tower ID and signal strength mapped to locations, and use a little AI to intelligently infer your unknown location from known cell IDs and signal strengths. This could take into account interference from buildings, mountains, etc, rather than trying to map out every single cell tower then perform the trilateration. Actual trilateration using signal strength would assume every tower has identical antennas and transmit power, and is uniform 360 degrees around.

Finally, we need massive armies of people willing to cell stumble across the country (or at least every major metropolitan area).

Once that’s all done, we can pretty much take over the world (or at least make Google Maps way cooler and tag photos with approximate lat/lon coordinates…)

### Another Option: WiFi ###

One more possibility would be to use the known locations of WiFi access points for geolocation. There are already free and open repositories of millions of WiFi access points: [wigle.net](http://www.wigle.net/) seems to be one of the largest.

The problem is that WiFi signals are much shorter range than cellular signals, thus the coverage of a single WiFi access point is much smaller than a single cell tower. Of course there are many more WiFi access points than cell towers (11 million registered on wigle.net), but this just means you need to wardrive along much finer resolution “grid” (essentially at the individual street level) to get good coverage.

### Conclusion ###

There are plenty of obstacles to making a useful location service for cell phones, but I think it would be fun to try anyway. Even if we can’t cover the entire U.S., as long as there’s on person per major city willing to cell stumble for a weekend, I think you could get a pretty useful system.

If you’re interested in helping, email me at .

Update: it appears a company called Navizon has released [a product exactly like this](http://navizon.typepad.com/my_weblog/2007/09/a-version-of-na.html). Unfortunately it costs money, but supposedly the money goes to the users who upload new cell tower locations and WiFi access points. $20 for 1000 unique cell towers or 5000 unique WiFi access points doesn’t seem like a very good deal though.

Update 2: With the release of the iPhone 1.1.1 software updates all 3rd party applications are essentially locked out (for now). Navizon is offering a refund for customers who purchased their product.

So it’s on Apple to do this. If they partner with AT&T this would be trivial to implement, since of course AT&T knows where all their own cell towers are located.

Update 3: This exactly functionality is now built into iPhone software version 1.1.3. Apple is using both cell tower data from Google, and WiFi access point data for approximating your current location.

Open new Terminal window in current (or other specified) directory

A lot of times I find myself wanting to open another (Mac OS X) Terminal window in the same directory as my current one. This little shell script, which executes a little AppleScript, makes that trivial:

#!/bin/sh

if [ $# -ne 1 ]; then
    PATHDIR=`pwd`
else
    PATHDIR=$1
fi

osascript -e "tell application \"Terminal\"" -e "do script \"cd $PATHDIR\"" -e "end tell"

Save this script somewhere in your $PATH with executable permissions. Now instead of hitting Command-N then typing “cd really/long/path/to/your/current/directory”, you can simply type the name of the script (I used “term”):

term

Chain them together to open multiple windows. The following would open three new windows with the same current directory:

term; term; term

It can also take an optional directory path argument to override the current directory:

term /System/Library/

iPhone Accelerometer Fun-ness

If you’re an Apple geek like myself, you might remember back in 1999 when WiFi was a brand new technology, and [Phil Schiller](http://en.wikipedia.org/wiki/Philip_W._Schiller) demonstrated the new iBook’s Airport feature by jumping off a balcony holding an iBook with an attached accelerometer, which sent the accelerometer data wirelessly to Steve’s demo machine for display (see below).

Well, when I found out someone figured out [how to access the raw accelerometer data](http://blog.medallia.com/2007/08/fun_with_the_iphone_accelerome.html) from the iPhone I decided it would be cool to do something with it, and I used Phil’s demo as inspiration.

The demo consists of two simple applications. One application runs on the iPhone collecting accelerometer data and sending it over the wireless network to the other application running on a computer to display the data:

The three lines correspond to the three axes of the iPhone’s accelerometer plotted over time (if you’re looking at the iPhone from straight ahead then x is red, y is green, z is blue). Source code for the applications will be up eventually, but it’s really pretty straightforward.

Of course this is just a simple little demo, but I’ve got some plans for other cool things…

As an added bonus, I found the video of Phil’s demo:

Ad-blocking and whyfirefoxisblocked.com

Recently it [came to the attention of the Digg masses](http://www.digg.com/software/Why_Firefox_is_blocked) that some slimy SEO guy was advocating web site owners block *every* Firefox user simply because Firefox allows ad-blocking plugins, and doesn’t provide web site owners with any way to block users of such plugins.

I find this incredibly silly for a number of reasons. The number of Firefox users who use such plugins is likely very small. By blocking *all* Firefox users, you not only keep the ad-blocking users away (who most likely wouldn’t click on your ads anyway), but also the much larger number of users who *might* click on your ads. Mmmmkay…

Even if he’s doing this out of principle, or to make a point, he apparently doesn’t realize that *every* popular browser has ad-blocking software available. See below.

Personally, I’ve realized that I’m completely web ad blind. After 10+ years of web browsing, I’ve subconsciously conditioned myself to ignore all web advertising, unless it’s something truly obnoxious like Flash ads with sound, etc.

That said, this guy has inspired me to install both ad blocking software, and plugin to change the browser’s user-agent string to get around silly browser-specific filters (although if a site resorts to blocking certain browsers, do you really want to support them?).

### Ad Blocking ###

Firefox: [Adblock Plus](http://adblockplus.org/), also available from the Firefox plugin directory.

Safari: [PithHelmet](http://www.culater.net/software/PithHelmet/)

### User-Agent Changing ###

Firefox: [User Agent Switcher](https://addons.mozilla.org/en-US/firefox/addon/59)

Safari: built in, enable Safari “Debug” menu by entering the following on the command line:
defaults write com.apple.Safari IncludeDebugMenu 1

Update: the ad-blocking debate got picked up by [at least one mainstream newpaper](http://www.nytimes.com/2007/09/03/technology/03link.html), surely causing a surge of new Ad-block users… not quite what the slimy SEO guy had in mind. Karma?

Mystery solved: iTeaHAL

I’ve been getting strange messages in my system and console logs, or when executing certain applications from the command line. Notably iMovie and Skype:

iTeaHAL: Entering...
iTeaHAL: Not iTunes, exiting.

And when executing iTunes, I get this:

iTeaHAL: Entering...
iTeaHAL: Early startup...
itea_hijack_init: result: 0
iTeaHAL: Early startup done.
new_AudioDeviceAddIOProc:0x2281b68
link added
iTeaHAL: Late startup...
{length = 6, capacity = 6, bytes = 0x000a95c4a60e}
itea_fx_init: result: 0
itea_menu_init: result: 0
iTeaHAL: Late startup done.

If you have no idea what “iTeaHAL” is, this sounds rather ominous… something’s hijacking my iTunes?! It also didn’t help that I noticed this soon after using my laptop (if only for about 30 seconds) on [“the worlds most hostile network”](http://defcon.org/html/defcon-15/dc-15-faq.html) at DEFCON 15. I thought perhaps this was some kind of trojan backdoor that was piggybacking off of iTunes Music Sharing or something.

It turns out it’s nothing quite so evil.

Google turned up nothing except other people also wondering what the hell iTeaHAL was. Then I tried finding files named iteahal: “find / -iname iteahal*” also turned up nothing. I knew those strings must be stored somewhere, so next up was a grepping of the entire drive: “grep -arsi iteahal /”.

Success! Other than the system and console logs, the following files were found to contain “iteahal”:

/Library/Audio/Plug-Ins/HAL/iWow.plugin/Contents/Info.plist
/Library/Audio/Plug-Ins/HAL/iWow.plugin/Contents/MacOS/iTea

It’s the [SRS iWOW](http://www.srs-store.com/store-plugins/mall/iwow-plugin.asp) iTunes plugin from SRS Labs that’s supposed to make crappy laptop and computer speakers sound better (it actually does a decent job)

Apparently when an application loads audio plugins (like iTunes, iMovie, Skype, and other audio applications), it tries to load the iWow plugin, which detects whether or not it is iTunes, and spews all this debug information to the console.

Skype outage

Users of the popular VoIP network, Skype, have been experiencing widespread outages for more than a day now. And of course thanks to Murphy’s Law I happened to pick today to try to get my family set up on Skype.

So far I’ve heard three theories as to what is going on.

– Skype says the problem is [a deficiency in an algorithm within Skype networking software](http://heartbeat.skype.com/2007/08/the_latest_on_the_skype_signon.html), whatever that means. After reading a little about the [great lengths Skype goes to](http://www1.cs.columbia.edu/~salman/skype/) in order to obfuscate their network protocol and prevent reverse engineering, it wouldn’t surprise me if they spent more time protecting the protocol than making sure it works well…

– A [Microsoft update caused the outage](http://blog.tmcnet.com/blog/tom-keating/skype-outage.asp).

– A [remote DoS exploit](http://en.securitylab.ru/poc/301420.php) that was published on securitylab.ru was responsible:

#!/usr/bin/perl
# Simle Code by Maranax Porex ;D
# Ya Skaypeg!!

for ($i=256; $i>xCCCCC; $i=$i+256){
    $eot=‘AAAA’ x $i;
    call_sp();
}
exit;

sub call_sp(){
    $str="\"C:\\Program Files\\Skype\\Phone\\Skype.exe\" \"/uri:$eot\"";
}

Now, I don’t know much about Perl, Skype, or Windows… but I can tell you this little piece of code generates a series of strings containing a Windows path to the Skype.exe followed by a parameter starting with “/uri:” and ending with reaaaallly long strings of A’s:

"C:\Program Files\Skype\Phone\Skype.exe" "/uri:AAAAAAAAAA...AAAAAAAAAA"

…starting with 256 copies of “AAAA”, incrementing by 256 until it reaches 0xCCCCC (that’s 838,860). The problem is, the code doesn’t do anything with the strings, it simply assigns them to a variable and continues on with the next iteration.

Edit: actually, the condition in the for loop, “$i>xCCCCC;”, effectively always evaluates to true, thus the loop will repeat infinitely. The “correct” condition would have been “$i<0xCCCCC;". Yet another sign this thing is fake?

If it were actually complete, it would be a really simple command line argument [fuzzer](http://en.wikipedia.org/wiki/Fuzz_testing): basically executing Skype.exe with varying length “uri:” arguments. And if, in fact, this type of thing could take down the entire Skype network, well, Skype definitely needs to put more effort into the security and robustness of their program, rather than trying to prevent reverse engineering of their protocol.

Perhaps leaving the tool incomplete was a deliberate attempt by the writer to demonstrate the vulnerability exists without quite providing a working tool, or perhaps the exploit is a hoax. I don’t know Russian, so I can’t tell if there’s more information on securitylab.ru.

It will be interesting to see what the real reason for the outage is. Of course, with the Skype protocol so locked down, we may never know what the real reason is…

Update: [according to Skype](http://heartbeat.skype.com/2007/08/what_happened_on_august_16.html), the outage was caused by the massive number of Windows machines rebooting and reconnecting to Skype after a Microsoft update, and a flaw in Skype’s “self-healing” ability. Microsoft effectively DDoS’d Skype…

multiwhich

The “which” Unix command lists the location of the first matching executable in your PATH. The GNU version of “which” has several extra features including the ability to display all matching executables in your PATH, not just the first. This is useful for finding duplicates, etc. Unfortunately, whatever version of “which” is included in Mac OS X (and MacPorts) doesn’t have these extra features.

A quick Google search didn’t turn up anything, and I was in a shell scripting mood when I needed it, so rather than downloading and compiling GNU which I whipped up my own, “multiwhich”:

#!/bin/sh

for PATHDIR in `echo $PATH | tr ":" " "`
do
    sh -c "ls -1 $PATHDIR/$1" 2> /dev/null
done

Simply put this somewhere in your PATH with execute permissions, and type “which command“.

One other accidental “feature” of this script is the ability to list every executable in your PATH. This is great for finding duplicates:

multiwhich | sort | uniq -c | sort -n

It’s probably not the most elegant way to do it, but it serves it’s purpose. Perhaps someone will find it useful…

Update: I modified the multiwhich script slightly to support wildcards like “*” and “?”. You can now do things like “multiwhich x*” to get all binaries beginning with “x”, etc.