Multi-call binary in FreeBasic

Linux specific questions.
Post Reply
angros47
Posts: 2321
Joined: Jun 21, 2005 19:04

Multi-call binary in FreeBasic

Post by angros47 »

Multi-call binaries are used, under Linux, for several system utilities, to reduce disk space usage. For example, let's take the linux utilities "diff" and "cmp": they both perform a similar task (comparing two files), likely most of the binary code is identical, there is no need to have two copies of that code. The most known solution, when two programs share some parts of code, is to place the shared code into a dynamic library (also called "shared object", in linux). But there is also another solution: making a single program, that behaves in different ways depending on the name used to invoke it. In the example, I can have a single compiled program that if is named "cmp" acts as the cmp utility, if it's named "diff" it acts as the "diff" utility. Then, I just have to create links to that file using different names, to have what look like different programs.

This can be especially useful for compression programs: I can have the programs gzip, and gunzip, that are actually the same binary file (so, the compression algorithm is stored on the hard drive only once), and depending on the name used, they compress or uncompress.

Actually, all the examples I mentioned (cmp, diff, gzip, gunzip... but also cat, ls, wget and so on) can be implemented by a single file, named BusyBox, that on some embedded or light distributions of Linux provides all the system utilities.

Since programs compiled with FreeBasic can contain some runtime code that bloat them (not much, but still more than an equivalent program written in C, and on embedded or minimalist systems this can still be an issue), if the program is supposed to be very small sometimes it might be useful to combine several programs into a single multi-call binary. In FreeBasic it can be done using the Command(0) function:

Code: Select all

dim c as string=command(0)
dim c1 as string


do		'strip the path info
	c1=c
	c=mid(c,instr(c,"/")+1)
loop until c1=c

select case c
case "test"

	print "this is the test program"

case "game"

	print "this is the game program"

end select
Save as "multicall.bas", compile it and then create two links, with:

Code: Select all

ln multicall test
ln multicall game
then try invoking the file "test" and the file "game"
marcov
Posts: 3454
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Multi-call binary in FreeBasic

Post by marcov »

The question is however, how reliable is command(0)? Binaries might be moved right after modification, filesystems might not support the functionality (e.g. what if the binary is on a filesystem with a special driver, like samba or NFS drives).

For busybox, that is less of a problem, since it is only used on an embedded environment where those special cases are rare.

I don't have an answer, I ran into it when we had a couple of linux boxes that shared /usr over NFS. Since then, I have seen in multiple places that reading the commandline from /proc/self/<pid> is not 100% reliable, yet reports about it not working are rare. But never forget that it is not a 100% thing
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: Multi-call binary in FreeBasic

Post by TeeEmCee »

COMMAND(0) doesn't read from /proc/self/cmdline, it returns the argv[0] passed to main(). I have no idea whether that differs from /proc/self/cmdline, but it is possible to get different opinions of what the name of a program is (e.g. ps has "comm" vs "args" format keywords)
But I don't see a reliability problem. If an executable is moved after being run, or the network drive disconnects, that doesn't affect how it was called, which is the only thing that matters. And we can assume that you don't rewrite your own commandline (eg setproctitle(3)).
marcov
Posts: 3454
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Multi-call binary in FreeBasic

Post by marcov »

The kernel communicates it to libc that way, so while argv is easier under *nix, that difference probably doesn't matter.

Note that the moving is a problem if you self open (for debuginfo (for traceback), resources etc).

The problem with network drives is that some network and other non native FS drivers don't allow this because they don't allow the inode to the file to be cached. The resulting argv[0] will be just the binary name then, without the path.

But maybe then it doesn't matter for this case either since then symlinks will probably not work anyway.

So just forget most of it, just add a check that the routine actually delivers a sane path, and revert to some default or error otherwise.
Post Reply