I'm currently trying to change the process name of a process so I can read the more easily with htop, top, .... I want to LD_PRELOAD this code into another process so it gets renamed by an environemt variable.
I found a lot of stuff in the internet, but nothing works:
prctl(PR_SET_NAME, "Test");
This does not work because htop is not honoring the name.
Nginx setproctitle (Link) doesn't work as well, because it strips the parameters (which are needed by the process).
I tried everything I found and now I'm out of ideas.
Is this even possible in linux? And how?
Just run your program by shell script or your program through exec and pass desired name as argv[0]:
#/bin/bash
exec -a fancy_name a.out ...
or C/C++:
execl( "./a.out", "fancy_name", ... );
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define NEW_NAME "hello_world"
int main(int argc, char **argv) {
if(strcmp(argv[0], NEW_NAME)) {
argv[0] = NEW_NAME;
execv("/proc/self/exe", argv);
fputs("exec failed", stderr);
return 1;
}
while(1) // so it goes to the top
;
}
Related
I have two files in the same directory.
directory/
| a.c
| b.c
a.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
pid_t pid;
int status;
int wret;
if ((pid = fork()) < 0)
printf("error");
else if(pid == 0)
{
printf("%s", argv[1]);
execv(argv[1], &argv[1]);
}
else
{
/* respawn */
if ((wret = wait(&status)) != -1)
execv(argv[1], &argv[1]);
}
return 0;
}
b.c is just a simple program that print "hello".
I want to run ./a b from the command line to make the a program call exexXX to execute the b program.
I don't understand why if I use execv I can write just ./a b in the command line, instead if I use execvp I have to write ./a ./b.
The man exec page is not clear because it reports
"The initial argument for these functions is the name of a file that
is to be executed."
Thanks
If the program name argument contains no slashes, the execvp() function looks for the program to execute in the directories listed on your PATH environment variable. If you don't have . (the current directory) on your PATH and you aren't in one of the directories listed on your path, a plain name like b will not be executed, even if b is in the current directory. If the name contains a slash, it can be relative (./b) or absolute (/home/someone/src/programs/b) and it will be interpreted as a file name to be executed without consulting the PATH environment variable.
By contrast, execv() treats a plain b in the program name argument as ./b — the name of the file in the current directory and executes it if it is present, and fails if it is located somewhere else.
At one time, there was a comment that asked:
Are you saying if you have an executable b in . and you do execv("b", b_args), it will get executed?
On a normal Unix box, yes.
Code b.c:
#include <stdio.h>
int main(void)
{
puts("Hello");
return 0;
}
Code a.c:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char *argv[] = { "b", 0 };
execv(argv[0], argv);
fprintf(stderr, "failed to execute '%s'\n", argv[0]);
return 1;
}
Running these:
$ (PATH=$(clnpath "$PATH" ".:$PWD"); echopath PATH; ./a)
/Users/jleffler/bin
/opt/informix/12.10.FC6/bin
/Users/jleffler/oss/bin
/Users/jleffler/oss/rcs/bin
/usr/local/mysql/bin
/opt/gcc/v7.3.0/bin
/Users/jleffler/perl/v5.24.0/bin
/usr/local/bin
/usr/bin
/bin
/opt/gnu/bin
/usr/sbin
/sbin
Hello
$
The clnpath script modifies the string provided as its first argument ("$PATH") by removing any occurrences of any of the directory names listed in its second path-like argument (".:$PWD") — it's how I edit my PATH on the fly when I need to. The echopath script echoes the directories on PATH (or any other path-like variable, or it will process the result of expanding a pathlike variable, such as "$PATH"), one per line — the output shows that neither . nor /Users/jleffler/soq (which is where I run the program) is on $PATH in the sub-shell. The ./a runs the code from a.c (it would not be executed without that ./ in front), which in turn runs the code from b.c, which produces the Hello. (If there is some system where this does not work, please identify it.)
I could also arrange for b.c to be:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
puts("Hello");
const char *env = "PATH";
char *val = getenv(env);
if (val == 0)
val = "<nothing>";
printf("%s=%s\n", env, val);
return 0;
}
which would print the value of $PATH directly from the executable (to verify that neither . nor the value of the current working directory is listed).
How do I get the absolute path to the directory of the currently executing command in C? I'm looking for something similar to the command dirname "$(readlink -f "$0")" in a shell script. For instance, if the C binary is /home/august/foo/bar and it's executed as foo/bar I want to get the result /home/august/foo.
Maybe try POSIX realpath() with argv[0]; something like the following (works on my machine):
#include <limits.h> /* PATH_MAX */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char buf[PATH_MAX];
char *res = realpath(argv[0], buf);
(void)argc; /* make compiler happy */
if (res) {
printf("Binary is at %s.\n", buf);
} else {
perror("realpath");
exit(EXIT_FAILURE);
}
return 0;
}
One alternative to argv[0] and realpath(3) on Linux is to use /proc/self/exe, which is a symbolic link pointing to the executable. You can use readlink(2) to get the pathname from it. See proc(5) for more information.
argv[0] is allowed to be NULL by the way (though this usually wouldn't happen in practice). It is also not guaranteed to contain the path used to run the command, though it will when starting programs from the shell.
I have come to the conclusion that there is no portable way for a commpiled executable to get the path to its directory. The obvious alternative is to pass an environment variable to the executable telling it where it is located.
I wrote the following code but I always get the output: "ERROR!" (the execv function not scheduled to return)
What am I doing wrong???
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include "LineParser.h"
#define LOCATION_LEN 200
char* getL(void);
int main(int argc,char *argv[])
{
char *loc = getL();
char *args[] = {loc,"ls",NULL};
int i;
execv(args[0],args);
printf("ERROR!");
free(loc);
}
char* getL(void)
{
char *buff = (char**)malloc(sizeof(char)*LOCATION_LEN);
getcwd(buff,LOCATION_LEN);
return buff;
}
Read documentation of execv(3) and of execve(2) and of perror(3). At the very least, you should code
int main(int argc, char *argv[]) {
char *loc = getL();
char *args[] = { loc, "ls", NULL };
int i;
execv(args[0], args);
perror("execv");
free(loc);
}
You should compile with gcc -Wall -g then use the gdb debugger.
Your usage of execv is obviously wrong (you need a full path, e.g. "/bin/ls", and the order of arguments is wrong). You probably want exevcp(3) and you should in fact code at least:
char *args = { "ls", loc, NULL };
execvp("ls", args);
perror("execvp")
If you insist on using specifically execv(3) you could try
char *args = { "ls", loc, NULL };
execv("/bin/ls", args);
perror("execv")
I don't understand what your code is supposed to do. You might be interested by glob(7) & glob(3).
You probably should read Advanced Linux Programming. It seems that there are several concepts that you don't understand well enough. I guess that strace(1) could be useful to you (at least by running strace ls *.c to understand what is happening).
Maybe your getL is exactly what the GNU function get_current_dir_name(3) is doing, but then the (char**) cast inside it is grossly wrong. And you should better clear the buffer buff using memset(3) before calling getcwd(2) (and you should test against failure of ̀ mallocand ofgetcwd`)
Perhaps you want opendir(3), readdir(3), asprintf(3), stat(2); with all these, you could even avoid running ls
If you are coding some shell, you should strace some existing shell, and after having read all the references I am giving here, study the source code of free software shells like sash and GNU bash
You are not passing the correct arguments to execv. The first argument must be a path to the executable you wish to run but you are passing the path to the current working directory.
Update getL to return the full path to ls.
I am trying to create simple program which will run shell commands from arguments, for example
./run date +"%r"
07:56:05 PM
but I cant figure how. I try this, but it not working. I am pretty confused and absolutely cant figure how exec works..
#include <unistd.h>
#include <stdio.h>
int main (int argc, char *argv[]){
execlp("bash","bash", "argv[1]", (char*)0);
return 0;
}
You probably meant (note the lack of quotes around argv[1]):
execlp("bash", "myprogram", argv[1], NULL);
Note that I assume here that myprogram is a shell script. In case it's a binary, you should remove the preceding "bash" parameter.
One good troubleshooting technique could be replacing bash with echo to confirm the command line.
I've been using a combination of fork() and exec() to execute some external command on linux, however, the code seems to fail whenever I try to execute /usr/bin/firefox which is a symbolic link to a real binary.
Does anyone know how to solve this problem? I've tested with other programs (which really are executable binaries and not symlinks to them) and it works.
Here's the code from the program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv) {
pid_t pid;
// this was the old line:
// char *parmList[] = {"", "index.html", NULL};
// and this is the one that solves the problem:
char *parmList[] = {"firefox", "index.html", NULL};
int a;
if ((pid = fork()) == -1)
perror("fork failed");
if (pid == 0) {
a = execvp("/usr/bin/firefox", parmList);
fprintf(stdout, "execvp() returned %d\n", a);
fprintf(stdout, "errno: %s (%d).\n", strerror(errno), errno);
}
else {
waitpid(pid, 0, 0);
}
return 0;
}
Edit: I updated the code to include the answer and changed the topic's title because the problem really didn't seem to be due to symbolic links at all. Thanks everyone.
You might want to add some code right after the execvp to output some diagnostic (i.e. check errno, print something meaningful ;)).
You could also try to analyze it w/o source modification using strace or gdb for that matter.
See also: execve.
Update as follow-up from the comments
Firefox is not happy with argv[0] being empty, which is what argList looked like, unfortunately.
Lessons learned: Be thoroughly aware of what you pass as argv to the program you execute. :)
Does Firefox insist on having a non-empty argv[0]? You should normally pass the name of the command (either just "firefox" or "/usr/bin/firefox") to the command, but you are not doing so.
[...going to check the deeper comments above - and it seems this is the correct diagnosis, but 21 minutes or so late...]