Martin,
Can you elaborate on this a bit.
Doug Dumitru
EasyCo LLC
> Can you elaborate on this a bit.
It is more widespread than we thought at the time of posting the notice but
it is fixed so the issue has gone away.
A bit of background for those who are not C programmers......
A C program such as the QM executable receives the command arguments in an
array variable traditionally known as argv. The first element of this array,
argv[0], contains the name of the executable. Or, at least, that is what is
supposed to happen. The K&R C manual, widely accepted to be the C
programmers' bible, qualifies this with the phrase "by convention".
On Windows systems, regardless of how you start a program, argv[0] contains
the fully qualified pathname of the executable. On Linux systems, it
contains what you typed to start the program. So, if I type
/usr/qmsys/bin/qm
that is what I see in argv[0]. On the other hand, if I simply type
qm
and let Linux follow its search process to find the executable, all I see in
argv[0] is "qm".
Why is this an issue?
As a step towards allowing multiple instances of QM to run on the same
system totally independently, but more importantly to get around
restrictions introduced in newer versions of Windows, we needed to move
everything that makes up the QM software into the QMSYS directory. When you
run QM, we need to be able to find the pathname of this directory and the
easy way seemed to be to look in argv[0] to find the executable and then
backtrack up the directory hierachy two levels.
For Windows, this is trivial. For Linux, it is a bit more complex as we need
to resolve links and the more common case of the user who simply types "qm"
and relies on the PATH variable to find the program. We handle this
internally by our own scan of the PATH variable directories and by following
links.
All seemed ok. Everything was working nicely. Then we dicovered a flaw in
the process. When our installer creates the configuration files for xinetd
(the Linux network connection management process), it was not using the
NAMEINARGS flag and, despite us setting the fullpath of the executable,
xinetd puts only the last element of the pathname into argv[0]. Everything
is fine if the PATH variable is set to include the QMSYS bin directory, but
it fails if this is not the case.
This was fixed urgently for release 2.8-4. The change is trivial but means
that users upgrading for whom the PATH variable is not set correctly will
continue to run successfully.
We are aware that there may be other Linux subsystems that also break the
convention and do not set argv[0] correctly. The stunnel process is one such
example though there is much discussion and a documented fix on the internet
as we are not the only software to fall over this issue. We will publish
some guidance on the issue when we have done a little more research.
Martin Phillips
Ladybridge Systems Ltd
17b Coldstream Lane, Hardingstone, Northampton, NN4 6DB
+44-(0)1604-709200
Martin,
It is actually more interesting that you might think. It is also legal
to run the 'qm' program as a symlink. My general install method is to
setup a symlink as /usr/local/bin/qm -> /usr/qmsys/bin/qm.
/usr/local/bin is in the default path.
Not sure how you are approaching this problem, but one method that
should work on nearly all Linux systems is:
char procname[FILENAME_MAX];
int len = readlink("/proc/self/exe", procname, FILENAME_MAX - 1);
if (len <= 0) {
// I guess we're not running on the right version of unix
return FALSE;
}
procname[len] = '\0';
This should give you the "real" path to the executable.
Even this is not 100% safe. It is legal to:
mkdir -p /usr/qmsys-1/bin
ln /usr/qmsys-1/bin/qmxxx /usr/qmsys-1/bin/qm
/usr/qmsys-1/bin/qmxxx
This will run the 'qm' executable, but the path will be
/usr/qmsys-1/bin/qmxxx and there is no way to know this is happening.
Hard links like this literally create a 2nd directory pointer to the
same storage blocks.
Now, before you curse too much at hard links, they are actually very
useful. They are great for storing rotating backup sets and keeping
space for static files low.
Now I want to mention some alternate points here. I do not expect you
to do any of these, but I want to mention them in terms of "Linux Style".
First, the /usr directory is supposed to be for programs that are mostly
static and not for data. The /var directory is for data. So 'qm' in
Linux style would have its programs in /usr/qmsys and its data in
/var/qmaccts/...
Second, the /etc directory is the correct place for config files. If 2
configs are to be used on a single system, then either command-line
options or environment variables are used to override the config path.
Some products will also search for config items in /etc, /usr/local/etc, ...
Once you have found the config directory, if you need a unique ID for
things like shared memory maps, then ftok(...) is used to build a unique
number. You pass the config path to ftok so the result should be
unique. This is not perfect.
File names like ~0 (or %0) are frowned upon. Files should always have
extensions and these extensions should be unique for the application.
This is mostly a Windows construct, but Linux has adopted it. If you
ever change file names again, the 'part0.qmd' would make much more sense.
Now, you are encouraged to ignore all of these, but I wanted to get them
out there so that they could get mixed in with "future stuff".
Cheers,
Doug Dumitru
EasyCo LLC
> It is actually more interesting that you might think. It is also
> legal to run the 'qm' program as a symlink.
That's fine. We follow the link when resolving the executable pathname.
If there are contrived situations that make this impossible, they will be
not work with QM and we will make it a restriction but I think we have
covered everything except hard links which we banned long ago. Use of hard
links such that a single data file has two distinct pathnames will cause
problems inside QM.
The underlying requirement here is that we are building the first steps of
being able to run multiple independent instances of QM on the same system.
To do this, we need to impose some rules.
Re the "Linux style" issues, a side effect of this development is that we
have made the location of QM more flexible. Here we use /usr/qmsys on our
Linux systems but /var/qmsys on Mac. There should be no reason why a user
cannot install a private QM system in his own home directory.
Much as the /etc directory may be the usual place to store config files, we
cannot do this if we are to avoid needing options to identify the
configuration file to use. Our method of deriving the QMSYS pathname from
the executable makes it impossible to link up the wrong ones. This is
essential for truly separate multiple instances that are seen to be private.
There has also been comment in the past about wanting to be able to install
QM without needing write access to /etc.
Use of ftok() to generate shared memory identifiers may work for us but
there are many other things that need to be separated too. We are currently
working through how to handle these.
> File names like ~0 (or %0) are frowned upon.
Given that the directory belongs to QM, what we do in it should be totally
up to us. This is essential for directory files where the names are the same
as the records. For hashed files, we need names that can never occur in
directory files and, because of the name transformations used to ensure that
we can store items identically on all platforms, the names we have chosen
work.