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);
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 theln
process); this is simpler and much faster. Don't forget to check its success. Notice thatsymlink
is a system call (that even old Linux kernels should have) available as a C function, not a command (so indeed you cannot run anycommand or executable in your shell). As documented, you need tosymlink
#include <unistd.h>
in your C source file. Read also symlink(7).using the
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 usinggetenv
...):(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):(again, handle the errors, and think what would happen if
somefilepath
starts with../
)At last, do the system call but check against failure:
executing the
/bin/ln
programIf you insist (wrongly IMHO) on using the execve(2) syscall on
/bin/ln
or some exec(3) function (which would callexecve
), be sure to explicitly add aNULL
pointer. BTW on success theseexec
functions don't return, so you probably need to call fork(2) before and to use waitpid(2) after.Be aware that
execvp
uses thePATH
variable. So passing justln
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).There is no "Linux processor" involved. The
-s
flag is handled by the/bin/ln
executable program (whosemain
function gets the expanded program arguments, and which then calls thesymlink
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.useful references to read
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