Reputation: 17
I'm trying to write a C program to soft-link 2 files on Unix. In Unix, this command would be:
ln -s oldfile newlink
So I wrote a code to create a char *
array of the arguments like so:
char *args[4];
args[0] = "ln";
args[1] = "-s";
args[2] = argv[2]; //argv[2] is the name of the old file
args[3] = argv[3]; //argv[3] is the name of the new soft link file
execvp(args[0], args);
But the -s flag is not read by the Linux processor. How can I rewrite this in a way that it will handle the -s flag? I tried to do it with execlp
as well:
execlp(args[0], args[0], args[1], args[2], args[3], NULL);
But that also does not work. What am I doing wrong in these lines?
EDIT: I have also attempted the symlink() command, but I don't think my version of linux supports it, unless I am wrong and there is a flaw in my code:
char *args[4];
args[0] = "symlink";
args[1] = argv[2];
args[2] = argv[3];
args[3] = NULL;
execvp(args[0], args);
Upvotes: -2
Views: 1631
Reputation: 1
write a C code to soft-link 2 files on linux
For that specific purpose, you don't need to start a /bin/ln
process in your C code. You should instead use the symlink(2) system call (which would be used by the ln
process); this is simpler and much faster. Don't forget to check its success. Notice that symlink
is a system call (that even old Linux kernels should have) available as a C function, not a command (so indeed you cannot run any command or executable in your shell). As documented, you need to symlink
#include <unistd.h>
in your C source file. Read also symlink(7).
symlink
system callFor example, to do the equivalent of ln -s ~/somefile /tmp
you would first compute the path (e.g. using snprintf(3)...) corresponding to ~/somefile
(by using getenv
...):
char* somefilepath = "somefile";
char oldpathbuf[256];
snprintf(oldpathbuf, sizeof(pathbuf), "%s/%s", getenv("HOME"), somefilepath);
/// missing detecting and handling of errors in above
(and I leave you to handle all the error cases, including lack of space for snprintf
, and they are important!)
Then you need to compute the path of the new link (you cannot use symlink
system call on directories):
char newpathbuf[256];
snprintf(newpathbuf, sizeof(newpathbuf), "/tmp/%s", somefilepath);
(again, handle the errors, and think what would happen if somefilepath
starts with ../
)
At last, do the system call but check against failure:
if (symlink(newpathbuf, oldpathbuf)) {
perror("symlink");
exit(EXIT_FAILURE);
}
/bin/ln
programIf you insist (wrongly IMHO) on using the execve(2) syscall on /bin/ln
or some exec(3) function (which would call execve
), be sure to explicitly add a NULL
pointer. BTW on success these exec
functions don't return, so you probably need to call fork(2) before and to use waitpid(2) after.
Be aware that execvp
uses the PATH
variable. So passing just ln
to it might run (if your user has a weird $PATH
setting) something else than /bin/ln
(that file path is specified in the Linux FHS and in POSIX) with some unexpected side-effect. But see environ(7).
the -s flag is not read by the Linux processor
There is no "Linux processor" involved. The -s
flag is handled by the /bin/ln
executable program (whose main
function gets the expanded program arguments, and which then calls the symlink
system call). You need to understand more the role of unix shells and what globbing is and how a command is expanded by the shell.
I recommend reading Advanced Linux Programming and the intro(2) and syscalls(2) man page.
You probably should read more about Operating Systems and understand the difference between commands and system calls and the role of any Unix shell. I recommend reading the freely available Operating Systems : Three Easy Pieces
Upvotes: 2