Accessing and running /usr/bin programs in C - c

What is the most efficient method for running programs from the /usr/bin directory in a C program? I am tasking with getting user input, and if the user input matches up with a program in bin, running the respective program.
I had the idea of throwing the names of all the bin's programs in a text file, and using a loop to iterate through each word in the file while comparing the word to the input. However, I figured that might be reinventing the wheel a bit. Are there any streamlined ways to do this?

The "classical" way of invoking a program from an existing process on any of the UNIX-like OS'es is to use one of the exec() functions. When you read about exec() most tutorials will start by explaining another function: fork(). These functions are very commonly used together, but don't get too caught up on that, because they are both useful in their own right.
To answer your question, a fairly efficient way of doing what you're after:
Take the user generated input from whatever your source happens to be
(Optionally, call fork())
Call the execvp() function
What you do here will depend on whether you called fork() in step (2), and what you intend to do (if anything) after performing the task you described.
execvp() will do the legwork for you, by automatically searching on your environment PATH for a filename matching the first argument. If the current environment does not have a PATH set, it will default to /bin:/usr/bin. Since the only way that a call to exec() can yield a return value is when that call failed, you might want to check the value of errno as part of step (4). In the event that the user input didn't match any executable in the environment PATH, errno will be set to ENOENT. Exactly how you do this and what additional steps might be worth taking will depend on whether or not you forked, along with any additional requirements for your program.

I would suggest looking if the name you get from the user matches a file in the /usr/bin directory and if it does use the system function to run this program.
https://linux.die.net/man/3/system
#include <stdlib.h>
int system(const char *command);
i.e
FILE *file;
if (file = fopen(userinput, "r")){
fclose(file);
system(userinput);
}

Related

what is the difference between chdir(...) and system("cd ...")?

Was curious what the difference is in these two lines of code.
chdir ("..");
And
system ("cd ..");
Is there any difference other than call the system library function, which then calls chdir? At least, that's what I assume happens based on what I have found on the internet. Thanks.
The first changes the current working directory of the current process. The second invokes a shell and executes the command in it, which changes its directory; the process's working directory is unchanged. The second is almost never what you want.

how to buffer and delay printf() output?

I wrote a C program and in the program there are many printf() which output log information to stdout. Now I want to use multiple processes to run the program simultaneously with different arguments. And I want to redirect the output from stdout to a log file using >.
But multiple processes are running at the same time, their log information output overlap with each other, which can be confusing for future analysis.
one solution is: considering that different processes will exit at different time,modify the C program, so each log information is temporarily written into a temporal file. When the C program is about to exit. Read from the temporal file and write the content to stdout, this requires a lot of modification.
My idea is: I hope in the C program, all the printf() output can be buffered, the outputs put into stdout/redirection only when the process exits.
is it possible or not?
thanks!
This is not really possible, unless you are sure that the output is reasonably bounded (e.g. the total output is less than a few megabytes), otherwise use a logging mechanism which send to some central logger (like syslog).
On Linux and most Posix systems, the simplest way to do logging would be to use syslog(3) which is designed for logging (and is able to deal with different processes). I think this is the preferable approach.
With GNU libc, you could consider using open_memstream(3) -to write to memory, and here you need to be sure the total output is bounded- and use atexit(3) to have the memory stream written at the exit of the program into some file; you probably want to use some locking mechanism like flock(2) etc...
As commented by J.Holetzeck the simplest way is to redirect output into different files (perhaps using freopen(3), or simply in the invoking shell), and later merge these files.
I'm guessing you use Linux, or some Posix system. For Windows, I have no idea.

Simple Linux Shell. stop command

I am trying to implement a simple shell in linux and one of the features it should have is to enable to user to press <ctrl+D> and make it stop whatever it is doing - Basicly exactly what <ctrl+C> does in Bash.
Now I was wondering on the easiest way to do this, and I was thinking of some kind of key listener which would make the current task stop. Now the only way I could think of doing this would be to have a separate thread which would force stop and return the main thread to the base state, where it can take new input.
A separate thread would be the only way to "constantly" listen for the correct keypress.
I was hoping for some thoughts on this and possibly a better way to go about it.
[Edit]
I am trying to make a simple shell which can execute external programs, print/change directory, print/set path, print command history, invoke commands from history and print/set/remove command aliases. The CTRL-D is meant to be the equivalent of the CTRL-C in Bash, which allows the user to immediately exit a currently running program, not to exit the shell itself. [/Edit]
Why don't you just handle Ctrl-C?
Here is just one of many SO disussions on trapping the signal: Catch Ctrl-C in C
Ctrl-D generally represents EOF on standard input. You shouldn't mess with it.
If you want the Control-D character to generate an interrupt for you, then:
You need to map the EOF character to something other than Control-D.
You need to map the interrupt character to Control-D.
You do this in POSIX with the <termios.h> header and the functions:
tcgetattr()
tcsetattr()
You'd retrieve the current attributes in a struct termios using tcgetattr(). You'd make a copy of the structure, and modify (for sake of argument) the copy, changing the elements of the c_cc array indexed by VINTR and VEOF (plus any other changes you want to make), and then setting the new attributes using tcsetattr(). You'd also arrange to ensure that you restore the original terminal settings (by another call to tcsetattr() using the original set of attributes retrieved with tcgetattr()) before your shell exits. This might be done by a handler registered with atexit(), or by other mechanisms. You should endeavour to reset the terminal attributes under all circumstances. You can't do anything about a SIGKILL killing you.
While you're testing this, make a little script for yourself:
echo stty $(stty -g) > sane
chmod u+x sane
That records the current (presumably sane) terminal settings in a form that is designed for stty to read reliably. If (when) you have problems with your shell, you can use Control-JsaneControl-J to run the script and reset your terminal back to the known sane settings. This is also useful if you're developing programs that use the curses library.
Unless my comment on the other answer is incorrect, I think what you should do is:
if (!fgets(input, sizeof(input), stdin) == NULL)
{
... do cleanup here ...
exit(0);
}
or something equivalent to that.

Program restart self on update

I checked everywhere so I am hopefully not repeating a question.
I want to add a portable update feature to some C code I am writing. The program may not be in any specific location, and I would prefer to keep it to a single binary (No dynamic library loading)
Then after the update is complete, I want the program to be able to restart (not a loop, actually reload from the HDD)
Is there any way to do this in C on Linux?
If you know where the program is saved on disk, then you can exec() the program:
char args[] = { "/opt/somewhere/bin/program", 0 };
execv(args[0], args);
fprintf(stderr, "Failed to reexecute %s\n", args[0]);
exit(1);
If you don't know where the program is on disk, either use execvp() to search for it on $PATH, or find out. On Linux, use the /proc file system — and /proc/self/exe specifically; it is a symlink to the executable, so you would need to use readlink() to get the value. Beware: readlink() does not null terminate the string it reads.
If you want, you can arrange to pass an argument which indicates to the new process that it is being restarted after update; the bare minimum argument list I provided can be as complex as you need (a list of the files currently open for edit, perhaps, or any other appropriate information and options).
Also, don't forget to clean up before reexecuting — cleanly close any open files, for example. Remember, open file descriptors are inherited by the executed process (unless you mark them for closure on exec with FD_CLOEXEC or O_CLOEXEC), but the new process won't know what they're for unless you tell it (in the argument list) so it won't be able to use them. They'll just be cluttering up the process without helping in the least.
Yes, you need to call the proper exec() function. There might be some complications, it can be troublesome to find the absolute path name. You need to:
Store the current directory in main().
Store the argc and (all) argv[] values from main().
Since calling exec() replaces the current process, that should be all you need to do in order to restart yourself. You might also need to take care to close any opened files, since they might otherwise be "inherited" back to yourself, which is seldom what you want.

C run external program and get the result

In C, how should I execute external program and get its results as if it was ran in the console?
if there is an executable called dummy, and it displays 4 digit number in command prompt when executed, I want to know how to run that executable and get the 4 digit number that it had generated. In C.
popen() handles this quite nicely. For instance if you want to call something and read the results line by line:
char buffer[140];
FILE *in;
extern FILE *popen();
if(! (in = popen(somecommand, "r"""))){
exit(1);
}
while(fgets(buff, sizeof(buff), in) != NULL){
//buff is now the output of your command, line by line, do with it what you will
}
pclose(in);
This has worked for me before, hopefully it's helpful. Make sure to include stdio in order to use this.
You can use popen() on UNIX.
This is not actually something ISO C can do on its own (by that I mean the standard itself doesn't provide this capability) - possibly the most portable solution is to simply run the program, redirecting its standard output to a file, like:
system ("myprog >myprog.out");
then use the standard ISO C fopen/fread/fclose to read that output into a variable.
This is not necessarily the best solution since that may depend on the underlying environment (and even the ability to redirect output is platform-specific) but I thought I'd add it for completeness.
There is popen() on unix as mentioned before, which gives you a FILE* to read from.
Alternatively on unix, you can use a combination of pipe(), fork(), exec(), select(), and read(), and wait() to accomplish the task in a more generalized/flexible way.
The popen library call invokes fork and pipe under the hood to do its work. Using it, you're limited to simply reading whatever the process dumps to stdout (which you could use the underlying shell to redirect). Using the lower-level functions you can do pretty much whatever you want, including reading stderr and writing stdin.
On windows, see calls like CreatePipe() and CreateProcess(), with the IO members of STARTUPINFO set to your pipes. You can get a file descriptor to do read()'s using _open_ofshandle() with the process handle. Depending on the app, you may need to read multi-threaded, or it may be okay to block.

Resources