Rely on PATH or provide an explicit path when using system() - c

I'm writing a 'C' program that makes several calls to system() to execute other programs. When constructing the command string is it better to explicitly give the full path to the program being called, or should I just give the executable name and let the shell resolve its location using the PATH environment variable?
The programs I'm calling are all part of a single package and I have the path to the installation directory from a preprocessor definition. Giving the explicit path would seem to avoid errors that might occur if multiple installed programs share the same name. However it makes building the command strings a little more complicated, and everything will break if the user moves the programs around after installation.
Is there a widely accepted best practice covering this?
[Clarification]
I'm using autoconf/automake to generate the distribuion. The preprocessor definition providing the installation directory is created by the makefile. It reflects the user's choice of the installation directory as specified either on the configure comamnd line or the make command line. I do take the point about using environment variables to specify the location for the binaries though. It seems like an unneeded pain in the butt to make users rebuild just to change the location of the binaries.

Best practice is never to assume that you know your install directory at build time. Let your users decide where to install and work anyway.
This means that you will need to find out where your programs are located using some other mechanism. Consider using environment variables or command line parameters to allow the user to specify the actual path, if your platform does not provide you with the means to find out where the executables are located. You can use your knowledge of where you are normally installed as a fallback option.
For your actual question, in case you can build the absolute path to your program (using another mechanism than preprocessor directives) - use that. Otherwise, fall back to having the system find out for you.

The best practice is to not presume anything about the system you're installing onto. You can have the best of both worlds if you just let the user choose. Make the command you call an application preference or require paths to be defined in the environment:
PATH_TO_TOOL1=foo
PATH_TO_TOOL2=/usr/bin/bar
You can, of course, just fall back to a default of some kind if the variables aren't defined or the preference isn't set. Writing your application to be more flexible is always the best choice!

You should definitely let the user specify the path with an environment variable to the installed binaries. Not all systems are the same and many people will want to put their execs in different places.
the best example I can think of is people doing a local install vs system install. If your program is installed in a home directory that user will have to set and env variable to say where the binaries are copied to.

If you're absolutely sure of the path names, and if they are not "well-known" commands (for example, POSIX shell utilities on Unix are "well-known"), you should specify the pathname, otherwise don't specify the full path, or let the user control it by using an environment variable.
In fact, you may be able to write something like a function such as int my_system(const char *);, which does the prefixing of the path for you. If later you determine that it was a bad idea, it's just a matter of making my_system() identical to system().

I'm not sure if it's a best practice, but what I do in these cases is I write my C code to extend the PATH environment variable to include the installation directory at the end. Then I just use the PATH. That way, if the user's PATH wants to override where I believe the stuff was installed, it can—but if the software was installed in an out-of-the-way place, I can call it without forcing my users to put the directory on $PATH themselves.
Please note that the extended PATH lasts only as long as the C program runs; I'm not proposing changing the persistent PATH.

Related

Finding file locations in offline softwares in C

At some point in my C program I have to deal with something like this.
FILE * fptr = fopen("/Parent/child/.../file.dat");
Which means in order to access any file I need to know it's location. That's all understandable.
But, how can I make this generic? In my computer "/Parent/child/.../file.dat" will work because that's where the file is stored, but I'm making a software to distribute to other users so the path obviously differs. My question is, how can I install a specific file into the user's computer such that I can know and get the location of that file. I a but confused about this concept so any resources that could help me understand it better would be greatly appreciated.
In Linux the default path to application files should be hardcoded. There is a standard which applications should follow. For example, architecture-independent files should go to /usr/share/ and then either your application name or, if you expect the data to be shared between applications, a generic category such as images. User-specific configuration files should go $HOME/.config/<app-name>. Older applications place their default configuration in $HOME/.<app-name> instead.
You should also provide an ability to override the default path to the data with a command line switch and/or an environment variable and/or a user configuration file (the location of the latter should also be overridable with a command line switch and/or an environment variable).
Some applications search for their data directory relatively to the executable position. An executable can know its own absolute path by reading /proc/self/exe symbolic link. For example, if an executable finds itself in /usr/local/bin/somename, it can look for /usr/local/share/<app-name> (two levels up from the executable name and down to share/<app-name>.).
Finally, if you distribute source code for the users to build, the file locations should be configuration parameters.

Clear the "Where to build the binaries" history in cmake gui

It's a simple question, yet for the life of me, can't find a simple answer to this question.
I don't believe there is a way to clear the cached build paths through the CMake GUI nor through the command line interface; however, in windows you can use the registry editor and navigate to HKEY_CURRENT_USER/SOFTWARE/Kitware/CMakeSetup/Settings/StartPath. There, you'll see some indexed variables prefixed by "WhereBuild". You can modify these paths or delete them entirely.
On OS X, these variables are stored in a properties list located in $HOME/Library/Preferences/com.kitware.CMakeSetup.plist.
On other Unix/Linux-based systems, you may find it in $HOME/.config/Kitware/CMakeSetup.conf

Execute a program with a custom .ini path

I make a fair amount portable Apps for personal use and they work perfectly for the most part. I do, however, find it quite frustrating that if I run them on another computer none of my preferences are retained, as a program always looks in appData for the configuration files (which obviously don't exist on another system), so I'm wondering whether there is some kind of command line to launch an .exe with a custom .ini location.
I'm asking this firstly because Google has proved fruitless (once again) and secondly because I know it's possible - I've actually done this before, but with only one of my Apps. I accomplished this by launching the App via the command programFile.exe -f configFile.ini /s (I have also seen programFile.exe -d -f configFile.ini /s elsewhere). Naturally, I thought I would try to apply this to some other Apps but it seems it only works for that particular App.
So, is there a command/switch that I am unaware of that will do this for an .exe file?
Thanks
It really depends on each executable file you are using. Some have support for what you are looking for, and some don't. Some programs don't even use .ini files. What you should look for is if each and every program you use have support for user data custom location.
Edit
The only case where generic arguments would be avaialble for a group of EXE files is if they are generated with the same tool, which automatically provides these arguments for you. InstallShield and MSI install programs have that kind of feature (with the silent install and automated installation for instance).
I suggest you look into the tool you are using to generate your portable Apps, and see if it does provide those generic arguments for you, and how they work. If it does not have that feature, then look into the Apps you were able to specify a custom location for your INI file. Somewhere into the code, there must be a piece of code that handles the arguments you specify to the EXE file and handles them. You should share that piece of code with your other Apps, to make sure they provide the same arguments list.

Tricking programs in C

Say I launch a program from the program I make. Is it possible to trick the launched program into thinking the windows directory is in a different place?
If it uses the %windir% or %systemroot% environment variables to determine the Windows directory, it would certainly be easy to change these. But if it uses an API call, you'll have to hook that call, as ChrisW suggests. You might take a look at Detours.
Faking the location of the windows directory is generally not something that is done. My own reaction is similar to those above, that its a recipe for disaster if it were even possible.
If you could explain your situation in more detail (possibly in a new question), there might be better suggestions to solve your actual underlying problem.
It would be difficult. There are several system APIs which the program might be using to determine the path of the windows directory. To trick it you would need to intercept the program's calls to whichever API it is, and return a different result.
There are many articles about intercepting APIs on Windows: here's the first one I found using Google: API hooking revealed.
The location of Windows directory is in the Registry. Vista may let you change it per user, but as far as I know it's impossible to do per-process.

How to allow a user to edit data in a separate app from the terminal?

I am writing a terminal-based application, but I want the user to be able to edit certain text data in a separate editor. For example, if the user chooses to edit the list of current usernames, the list should open as a text file in the user's favorite editor (vim, gedit, etc.). This will probably be an environment variable such as $MYAPPEDITOR. This is similar to the way commit messages work in svn.
Is the best way to do this to create a temporary file in /tmp, and read it in when the editor process is terminated? Or is there a better way to approach this problem?
There's already a $EDITOR variable, which is extremely standard and I have seen it working on a wide variety of unixes. Also, vi is always an option on any flavor of unix.
Debian has a sensible-editor command that invokes $EDITOR if it can, or falls back to some standard ones otherwise. Freedesktop.org has an xdg-open command that will detect which desktop environment is running and open the file with the associated application. As far as I know, sensible-editor doesn't exist on other distributions, and of course xdg-open will fail in a text-only environment, but it couldn't hurt to try as many options as possible, if you think it's important that a desktop user can see their happy shiny gedit or kate instead of scary old vi or nano. ;)
The way crontab and sudoedit work is also by making a file in /tmp. git puts it under .git, and svn actually puts it in the current directory (not /tmp).
The way svn and mercurial do it is by making a file in /tmp.
BTW, you don't need a MYAPPEDITOR, on nix there's EDITOR already present.
Since you mention svn in your post, why not just follow the same methodology? svn opens a file with a particular name with whatever $EDITOR (or $SVN_EDITOR) contains - this might actually require some work on your part; determining the parameters to each supported editor. In either case, you have the name of the file that was saved (or the error code of the application if something failed) and you can just use that.

Resources