Why does symlink() always print symlink failed? - c

My code always prints symlink failed even when it creates the symlink, why does this happen?
I am writting all the core utils I use myself as I want the experince and don't like the implementations that exist, I am working on ln and honestly may just do soft links and skip hard links. Right now the program works, but always prints my error and I can't figure out why.
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
short i;
for (i = 1; i < argc; i++) {
if (symlink(argv[1], argv[2]) == -1)
printf("symlink failed");
else
symlink(argv[1], argv[2]);
}
}

You're looping over each argument to the program, but attempting to create a symlink from argv[2] to argv[1] on every iteration. The first one might succeed, but any further attempts will always fail because the link already exists.
You'll want to think carefully about how ln should behave when passed more than two arguments. The behavior of ln -s is more complex than simply calling symlink(); notably, it behaves differently when the last argument is a directory.

Related

Check if files exists (given by command line arguments)

I have to a do C program that uses the unix environment. I have already purchased the "Advancing Programming in the Unix Environment" book and it has helped out a lot so far. However, some of my questions have gone unanswered and I'm looking for some help.
I'm trying to write a program that can verify if the first and second arguments entered if a copy program exist. If the first argument does not exist, then an error message and exit must occur. If the second argument does exist, then an overwrite prompt must be displayed. I'm not exactly sure how to verify if a file already exists or not basically.
I have seen a few people saying that you can do (!-e) or something like that to verify the file existing/not existing.
If anyone could help me, I'd really appreciate it.
The access() function is designed to tell you if a file exists (or is readable, writeable or executable).
#include <unistd.h>
int result;
const char *filename = "/tmp/myfile";
result = access (filename, F_OK); // F_OK tests existence also (R_OK,W_OK,X_OK).
// for readable, writeable, executable
if ( result == 0 )
{
printf("%s exists!!\n",filename);
}
else
{
printf("ERROR: %s doesn't exist!\n",filename);
}
in your int main(int argc, char** argv) { block.
if (argc == 3) {
// then there were 3 arguments, the program name, and two parameters
} else if (argc == 2) {
// then prompt for the "second" argument, as the program name and one
// parameter exists
} else {
// just print out the usage, as we have a non-handled number of arguments
}
now if you want to verify that the file exists, that's different than verifying that the program argument exists. Basically attempt to open the file and read from it, but pay close attention to catching the integer error codes and checking them for errors. This will prevent your program from progressing into bits where those critical operations are assumed to have worked.
There is a common, yet misguided conception among new programmers when dealing with files in C. Basically, one really wants to make sure that a specific block of code works (the copying block in your case), so they check, check, and double-check conditions before the block is executed. Check if the file exists, check if it has correct permissions, check that it isn't a directory, etc. My recommendation is that you not do this.
Your copying block should be able to fail properly, just as properly as it should be able to succeed. If it fails, then typically you have all the information necessary to print out a meaningful error message. Should you check first and then act there will always be a small time gap between the check and action, and that time gap will eventually see the file removed or altered after the checks have passed, yet before it is read. Under such a scenario all of the pre-checking code failed to provide any benefit.
Code without benefit is just a nesting ground for future bugs and architectural problems. Don't waste your time writing code that has dubious (or no) benefit. When you suspect that some code you have written has little benefit, you need to restructure your code to put it in the right place. When you suspect that code someone else has written has little benefit, you need to first doubt your suspicions. It is trivially easy to not see the motivations behind a piece of code, and even more so when just starting out in a new language.
Good Luck!
--- code for the weary ---
#include <errorno.h>
#include <stdio.h>
#include <stdlib.h>
extern int errno;
int main(int argc, char** argv) {
// to hold our file descriptor
FILE *fp;
// reset any possible previously captured errors
errno = 0;
// open the file for reading
fp = fopen(argv[1], "r");
// check for an error condition
if ( fp == 0 && errno != 0 ) {
// print the error condition using the system error messages, with the
// additional message "Error occurred while opening file"
perror("Error occurred while opening file.\n");
// terminate the program with a non-successful status
exit(1);
}
}

Get return code from linux command in C program

I am basically trying to check if a particular file exists or not. For that I am using the test command of Unix.
sprintf(execbuf, "%s if test -r %s ; then true; else exit; fi;",
execbuf, st->file, NO_FILE);
It works fine, but I do not want to exit if the file is not here, rather it should return FAIL.
I am not able to figure out how to make the program return FAIL. I was thinking of using the exit code from the above command, but still I am not able to figure out how to use that exit code outside the Linux command in the program.
I'd recommend you rather just use the access() call, and not execute external shell commands to figure this out.
Just be aware that such cases are subject to race conditions - the file might exist when you call access() (or execute a shell command that determines whether the file exists), but it might be gone when you actually need it later on. If that's a problem for you, just open() the file, and use the file descriptor later on when you actually need it for I/O.
If you're not married to what your doing right now, then I'd suggest using stat:
#include <sys/stat.h>
#include <stdio.h>
int main (int argc, char** argv[])
{
struct stat sts;
if (stat(argv[1], &sts) == -1 && errno == ENOENT)
printf ("The file %s doesn't exist...\n", argv [1]);
else
printf("The file exists\n");
This will tell you if it exists or not. If you dont' want to pass it command line, parameter 1 is a const char*, so just pass it the file name.

linux how to patch this code

#include <WhatHere?>
#include <WhatHere?>
#include <WhatHere?>
int main(int argc, char **argv) {
char command[50] = "echo ";
strcat(command,argv[1]); // concatenate the input so that the final command is "echo <input>"
system(command); // call the system() function to print the input
return 0; // denote that the program has finished executing successfully
}
Can we get a remote access by running this code ? I know it is possible but please help me patch it up.
Assuming that you're worried about the potential buffer overflow, you could fix it like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv) {
char *command;
if (argc != 2) {
fprintf (stderr, "Wrong number of arguments\n");
return 1;
}
if ((command = malloc (strlen (argv[1]) + 6)) == NULL) {
fprintf (stderr, "Could not allocate memory\n");
return 1;
}
strcpy (command, "echo ");
strcat(command,argv[1]);
system(command);
free (command);
return 0;
}
This makes enough room for "echo " (5), argv[1] (string length) and the null terminator (1).
It's still potentially dangerous allowing user-specified stuff to be run but at least you won't get buffer overflows any more.
Paxdiablo gave a good solution to your buffer overflow problem, but that's really the least of your problems here. Your big issue is that you are blindly using input from the user without inspecting it first.
For example, running your program like:
./your_app "\"goodbye data\" && rm -rf /"
would end in disaster, even if you program had no buffer overflow problems. An attacker could just as easily pass in an entire shell script that did all sorts of nasty things, all they would have to do is re-write it to fit in a single line.
You need to inspect incoming user input before you pass it to system() and make sure that it looks like what you are expecting. Better yet, avoid using system() with user input entirely and instead use safer methods to do what you need (in your example, you can replace your call to system("echo ...") with printf()). If you absolutely must pass user input to system(), consider running your app in a restricted environment like a chroot jail to at least make it more difficult to do anything nasty.

Transfer files in C

How do I transfer files from one folder to another, where both folders are present in oracle home directory?
int main(int argc, char *argv[]){
char *home, *tmp2;
home = getenv("ORACLE_HOME");
temp2 = getenv("ORACLE_HOME");
strcat (home,"A");
strcat (tmp2,"B");
//transfer files from home to tmp2
}
strcat doesn't seem to work. Here, I see tmp2 pointer doesn't get updated correctly.
Edit: OS is a UNIX based machine. Code edited.
I require a binary file which does this copying, with the intention that the real code cannot be viewed. Hence I didn't consider using shell script as an option. The files in A are encrypted and then copied to B, decrypted in B and run. As the files are in perl, I intend to use system command to run them in the same C code.
Using the system(3) command is probably a good idea since you get the convenience of a shell interpreter to expand filenames (via *) but avoids the hassle of computing the exact length of buffer needed to print the command by using a fixed length buffer and ensuring it cannot overflow:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSZ 0xFFF
int main(void)
{
char * ohome = getenv("ORACLE_HOME"), cmd[BUFSZ];
char * fmt="/bin/mv %s/%s/* %s/%s";
int written = snprintf(cmd, BUFSZ, fmt, ohome, "A", ohome, "B"), ret;
if ((written < 0) || (written >= (BUFSZ-1))) {
/* ERROR: print error or ORACLE_HOME env var too long for BUFSZ. */
}
if ((ret = system(cmd)) == 0) {
/* OK, move succeeded. */
}
return 0;
}
As commenter Paul Kuliniewicz points out, unexpected results may ensue if your ORACLE_HOME contains spaces or other special characters which may be interpreted by the subshell in the "system" command. Using one of the execl or execv family will let you build the arguments without worrying about the shell interpreter doing it's own interpretation but at the expense of using wildcards.
First of all as pointed out before, this "security" of yours is completely useless. It is trivial to intercept the files being copied (there are plenty of tools to monitor file system changes and such), but that is another story.
This is how you could do it, for the first part. To do the actual copying, you'd have to either use system() or read the whole file and then write it again, which is kind of long for this kind of quick copy.
int main(int argc, char *argv[]){
char *home, *tmp2;
home = strdup(getenv("ORACLE_HOME"));
tmp2 = strdup(getenv("ORACLE_HOME"));
home = realloc(home, strlen(home)+strlen("A")+1);
tmp2 = realloc(tmp2, strlen(tmp2)+strlen("B")+1);
strcat (home,"A");
strcat (tmp2,"B");
}
By the way, if you could stand just moving the file, it would be much easier, you could just do:
rename(home,tmp2);
Not realted to what you are asking, but a comment on your code:
You probably won't be able to strcat to the results of a getenv, because getenv might (in some environments) return a pointer to read-only memory. Instead, make a new buffer and strcpy the results of the getenv into it, and then strcat the rest of the file name.
The quick-n-dirty way to do the transferring is to use the cp shell command to do the copying, but invoke it using the system command instead of using a shell script.
Or, have your C program create a shell script to do the copying, run the shell script, and then delete it.

Programmatically retrieving the absolute path of an OS X command-line app

On Linux, an application can easily get its absolute path by querying /proc/self/exe. On FreeBSD, it's more involved, since you have to build up a sysctl call:
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[1024];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
but it's still completely doable. Yet I cannot find a way to determine this on OS X for a command-line application. If you're running from within an app bundle, you can determine it by running [[NSBundle mainBundle] bundlePath], but because command-line applications are not in bundles, this doesn't help.
(Note: consulting argv[0] is not a reasonable answer, since, if launched from a symlink, argv[0] will be that symlink--not the ultimate path to the executable called. argv[0] can also lie if a dumb application uses an exec() call and forget to initialize argv properly, which I have seen in the wild.)
The function _NSGetExecutablePath will return a full path to the executable (GUI or not). The path may contain symbolic links, "..", etc. but the realpath function can be used to clean those up if needed. See man 3 dyld for more information.
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0)
printf("executable path is %s\n", path);
else
printf("buffer too small; need size %u\n", size);
The secret to this function is that the Darwin kernel puts the executable path on the process stack immediately after the envp array when it creates the process. The dynamic link editor dyld grabs this on initialization and keeps a pointer to it. This function uses that pointer.
I believe there is much more elegant solution, which actually works for any PID, and also returns the absolute path directly:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libproc.h>
int main (int argc, char* argv[])
{
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid();
ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
if ( ret <= 0 ) {
fprintf(stderr, "PID %d: proc_pidpath ();\n", pid);
fprintf(stderr, " %s\n", strerror(errno));
} else {
printf("proc %d: %s\n", pid, pathbuf);
}
return 0;
}
Looks like the answer is that you can't do it:
I'm trying to achieve something like
lsof's functionality and gather a
whole bunch of statistics and info
about running processes. If lsof
weren't so slow, I'd be happy sticking
with it.
If you reimplement lsof, you will find
that it's slow because it's doing a
lot of work.
I guess that's not really because lsof
is user-mode, it's more that it has to
scan through a task's address space
looking for things backed by an
external pager. Is there any quicker
way of doing this when I'm in the
kernel?
No. lsof is not stupid; it's doing
what it has to do. If you just want a
subset of its functionality, you might
want to consider starting with the
lsof source (which is available) and
trimming it down to meet your
requirements.
Out of curiosity, is p_textvp used at
all? It looks like it's set to the
parent's p_textvp in kern_fork (and
then getting released??) but it's not
getting touched in any of kern_exec's
routines.
p_textvp is not used. In Darwin, the
proc is not the root of the address
space; the task is. There is no
concept of "the vnode" for a task's
address space, as it is not
necessarily initially populated by
mapping one.
If exec were to populate p_textvp, it
would pander to the assumption that
all processes are backed by a vnode.
Then programmers would assume that it
was possible to get a path to the
vnode, and from there it is a short
jump to the assumption that the
current path to the vnode is the path
from which it was launched, and that
text processing on the string might
lead to the application bundle name...
all of which would be impossible to
guarantee without substantial penalty.
—Mike Smith, Darwin Drivers
mailing list
This is late, but [[NSBundle mainBundle] executablePath] works just fine for non-bundled, command-line programs.
There is no guaranteed way I think.
If argv[0] is a symlink then you could use readlink().
If command is executed through the $PATH then one could
try some of: search(getenv("PATH")), getenv("_"), dladdr()
Why not simply realpath(argv[0], actualpath);? True, realpath has some limits (documented in the manual page) but it handles symbolic links fine. Tested on FreeBSD and Linux
% ls -l foobar
lrwxr-xr-x 1 bortzmeyer bortzmeyer 22 Apr 29 07:39 foobar -> /tmp/get-real-name-exe
% ./foobar
My real path: /tmp/get-real-name-exe
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <sys/stat.h>
int
main(argc, argv)
int argc;
char **argv;
{
char actualpath[PATH_MAX + 1];
if (argc > 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(1);
}
realpath(argv[0], actualpath);
fprintf(stdout, "My real path: %s\n", actualpath);
exit(0);
}
If the program is launched via PATH, see pixelbeat's solution.
http://developer.apple.com/documentation/Carbon/Reference/Process_Manager/Reference/reference.html#//apple_ref/c/func/GetProcessBundleLocation
GetProcessBundleLocation seems to work.

Resources