I am writing a C program in Linux. Commands like execv() require a path in the form of a C string. Is there a command that will return the current path in the form of a C-style string?
getcwd():
SYNOPSIS
#include <unistd.h>
char *getcwd(char *buf, size_t size);
DESCRIPTION
The getcwd() function shall place an absolute pathname of the current working directory in the array pointed to by buf, and return buf. The pathname copied to the array shall contain no components that are symbolic links. The size argument is the size in bytes of the character array pointed to by the buf argument. If buf is a null pointer, the behavior of getcwd() is unspecified.
RETURN VALUE
Upon successful completion, getcwd() shall return the buf argument. Otherwise, getcwd() shall return a null pointer and set errno to indicate the error. The contents of the array pointed to by buf are then undefined....
The path argument to execv() is the path to the application you wish to execute, not the current working directory (which will be returned by getcwd()) or the shell search path (which will be returned by getenv("PATH")).
Depending on what you're doing, you may get more mileage out of the system() function in the C library rather than the lower-level exec() family.
This is not ANSI C:
#include <unistd.h>
char path[MAXPATHLEN];
getcwd(path, MAXPATHLEN);
printf("pwd -> %s\n", path);
If the path can be a relative path, you should be able to use '.' or './' as the path. I'm not sure if it will work, but you could try it.
You need to grab the environment variable PWD (present working directory).
I'm not sure what the library it is in, but it is a standard Linux header.
I was thinking of getenv() which would help if you also need to run system commands and need the various bin paths located in PATH.
Related
Does the function scandir handle relative paths?
In other words, are the following two pieces of code equivalent?
int NUM = scandir("/home/hello/wait/../pqr/../../hello", &LIST, 0, alphasort);
int NUM = scandir("/home/hello", &LIST, 0, alphasort);
If not, is there some simple buit-in function to convert /home/hello/wait/../pqr/../../hello to /home/hello?
Does the function scandir handle relative paths?
I believe the answer is yes. From posix scandir we know only that:
The scandir() function shall scan the directory dir, [...]
From posix definitions:
3.129 Directory
A file that contains directory entries. No two directory entries in the same directory have the same name
The argument to scandir is char *, so it's a string. And from posix definitions we know that:
3.271 Pathname
A string that is used to identify a file. [...]
Another section named 4.13 Pathname Resolution delves on how pathname is resolved, and tells us that:
If the pathname does not begin with a <slash>, the predecessor of the first filename of the pathname shall be taken to be either the current working directory of the process [...] (such pathnames are referred to as "relative pathnames").
So because scandir takes a pathname to a directory and because of how a pathname is resolved, yes, you can give relative paths to scandir.
In other words
It's not an "other word" - both pathnames you showed are absolute, not relative. Using dot-dot in a pathname doesn't make the pathname relative.
are the following two pieces of code equivalent?
Yes.
is there some simple buit-in function to convert /home/hello/wait/../pqr/../../hello to /home/hello?
There is no "builtin function" to canonicalize a pathname in any compiler I am aware of. There exists a completely normal function provided from POSIX for that purpose and is called realpath(). GNU library may allocated the returned string dynamically and it also has canonicalize_file_name.
I'm trying to use CreateProcess to start a child process, however I keep getting error 2, which, according to the documentation is file not found.
My code looks like this:
if (!(CreateProcess(LPCTSTR("test.exe") ,NULL ,NULL,NULL,FALSE ,0 ,NULL ,NULL ,&producer_si
,&producer)))
{
printf("Create process failed!(%d)\n", GetLastError());
}
Where test.exe is an executable program which I created earlier. The child process is very simple, with the code looking like this:
void _tmain (int argc, TCHAR* argv[])
{
printf("%s\n", "hello!");
}
test.exe is also found in the same folder as the parent process. I'm not understanding why I'm always getting an error code of 2.
Error 2 is ERROR_FILE_NOT_FOUND. As others have told you, you are relying on a relative path when you need to use an absolute path instead.
Also, LPCTSTR("test.exe") is not valid code. If UNICODE is defined, CreateFile() maps to CreateFileW(), and LPCTSTR maps to LPCWSTR ie const wchar_t*. You cannot typecast a char* to a wchar_t* and end up with meaningful data. If you want to use TCHAR-sensitive literals, use the TEXT() macro instead, eg:
if (!CreateProcess(TEXT("full path to\\test.exe"), ...))
Otherwise, forget using TCHAR and just write Ansi-specific or Unicode-specific code instead, depending on your needs:
if (!CreateProcessA("full path to\\test.exe", ...))
if (!CreateProcessW(L"full path to\\test.exe", ...))
test.exe is never being looked up in the directory that the calling exe lives in. It is being looked up in the current directory which is a per-process path variable. Maybe the current directory is not pointed to where test.exe lives. You should also never rely on that because it can change arbitrarily (for example by using the file dialogs, or when the parent process changes it).
The CreateProcess function is very sensitive when it comes to file names, at least in my opinion.
When you specify your exe like that you actually specify it according to the current directory which may not be the same as the directory your main exe is in, which explains the file not found.
One way around is to simply get your current exe's directory with GetModulePath stip away the exe name from that and there you have the same directory, or simply use an absolute path.
According to the CreateProcess documentation the first parameter can be NULL :
The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string.
At least for me it seemed that if you just specify the command line only it works far better than with the application name, and also within the application name you can't handle the commandline.
With QT the MSDN function TEXT() it doesn't work: QTCreator's compiler return:
'Lvar' undeclared (first use in this function)
where var is input of Text(), because of QT whose enable UNICODE and because of that:
#ifdef UNICODE
/*
* NOTE: This tests UNICODE, which is different from the _UNICODE define
* used to differentiate standard C runtime calls.
*/
typedef WCHAR TCHAR;
typedef WCHAR _TCHAR;
/*
* __TEXT is a private macro whose specific use is to force the expansion of a
* macro passed as an argument to the macro TEXT. DO NOT use this
* macro within your programs. It's name and function could change without
* notice.
*/
#define __TEXT(q) L##q
#else
typedef CHAR TCHAR;
typedef CHAR _TCHAR;
#define __TEXT(q) q
#endif
#endif
in particular this passage:
#define __TEXT(q) L##q
in winnt.h included by windows.h
So, to solve this problem, we have to add this:
DEFINES -= UNICODE
in the .pro file of the QTCreator's project and it will work.
I am currently writing my own terminal in C.
I found out, that there is multiple variants of the exec() methode, that i can use.
Its simple occurance lead me to use execv():
int main(int argc , char* argv[]){
char* dir = getcwd(NULL, 0);
char* command[] = {"echo", "Hello", "World", "!!!", NULL};
execv(dir, command);
}
From my understanding this should work. It is compiling, but nothing happens.
The path argument to execv is supposed to be the path specification to the executable file you want to run, not just a directory as returned by getcwd. From the manpage:
The initial argument for these functions is the pathname of a file which is to be executed.
In other words, you're looking for something like:
execv ("/bin/echo", command);
The code you currently have is trying to run your current directory, something that's unlikely to end well, and something you may have noticed if you checked the return value from execv along with errno: nudge, nudge, wink, wink :-)
In terms of what to do for other programs, you simply substitute their full path name for /bin/echo.
You should also be aware that exec is a family of functions, each with slight variations.
Some allow environments to be passed, some automatically search the path for your executable (depending on the name given), and some use variable argument lists rather than arrays. If you want to use the automatic path searching, you would look into execvp rather than execv, then you don't have to worry about where the executable file is located.
I have a situation where I need to get a file name so that I can call the readlink() function. All I have is an integer that was originally stored as a file descriptor via an open() command. Problem is, I don't have access to the function where the open() command executed (if I did, then I wouldn't be posting this). The return value from open() was stored in a struct that I do have access to.
char buf[PATH_MAX];
char tempFD[2]; //file descriptor number of the temporary file created
tempFD[0] = fi->fh + '0';
tempFD[1] = '\0';
char parentFD[2]; //file descriptor number of the original file
parentFD[0] = (fi->fh - 1) + '0';
parentFD[1] = '\0';
if (readlink(tempFD, buf, sizeof(buf)) < 0) {
log_msg("\treadlink() error\n");
perror("readlink() error");
} else
log_msg("readlink() returned '%s' for '%s'\n", buf, tempFD);
This is part of the FUSE file system. The struct is called fi, and the file descriptor is stored in fh, which is of type uint64_t. Because of the way this program executes, I know that the two linked files have file descriptor numbers that are always 1 apart. At least that's my working assumption, which I am trying to verify with this code.
This compiles, but when I run it, my log file shows a readlink error every time. My file descriptors have the correct integer values stored in them, but it's not working.
Does anyone know how I can get the file name from these integer values? Thanks!
If it's acceptable that your code becomes non portable and is tied to being run on a somewhat modern version of Linux, then you can use /proc/<pid>/fd/<fd>. However, I would recommend against adding '0' to the fd as a means to get the string representing the number, because it uses the assumption that fd < 10.
However it would be best if you were able to just pick up the filename instead of relying on /proc. At the very least, you can replace calls to the library's function with a wrapper function using a linker flag. Example of usage is gcc program.c -Wl,-wrap,theFunctionToBeOverriden -o program, all calls to the library function will be linked against __wrap_theFunctionToBeOverriden; the original function is accessible under the name __real_theFunctionToBeOverriden. See this answer https://stackoverflow.com/a/617606/111160 for details.
But, back to the answer not involving linkage rerouting: you can do it something like
char fd_path[100];
snprintf("/proc/%d/fd/%d", sizeof(fd_path), getpid(), fi->fh);
You should now use this /proc/... path (it is a softlink) rather than using the path it links to.
You can call readlink to find the actual path in the filesystem. However, doing so introduces a security vulnerability and I suggest against using the path readlink returns.
When the file the descriptor points at is deleted,unlinked, then you can still access it through the /proc/... path. However, when you readlink on it, you get the original pathname (appended with a ' (deleted)' text).
If your file was /tmp/a.txt and it gets deleted, readlink on the /proc/... path returns /tmp/a.txt (deleted). If this path exists, you will be able to access it!, while you wanted to access a different file (/tmp/a.txt). An attacker may be able to provide hostile contents in the /tmp/a.txt (deleted) file.
On the other hand, if you just access the file through the /proc/... path, you will access the correct (unlinked but still alive) file, even if the path claims to be a link to something else.
I'm using opendir / readdir / closedir to reproduce a program similar to ls, it went pretty well until I tried to ls "/dev/" when it comes to "/dev/fd/" with the recursive options, it find more files than it actually exists, those are not hidden files (I mean '.' commencing files ).
The true ls give me :
"/dev/fd/ :"
"0 1 2 3"
Mine too.
But, the thing is that in gdb, it find 3 more files that are 4,5 and 6. I heard that gdb create his own environement so let's forget this.
When I try ls "/dev/fd/" -R the true ls stop immediately the listing while my program gives :
"/dev/fd/3:"
"/dev/fd/3/3/"
"/dev/fd/3/3/......../10"
stat return -1 after 40 files at least but the execution continues : segmentation fault.
In my computer, "/dev/fd/3/" and so are symbolic links, the macro "S_ISDIR" returns me 0 on the existing files but on the non existing files like : "/dev/fd/6/" it return 1...
I wanted to know why my program goes wrong while the true ls doesn't, I noticed that ls use stat64 in my computer but when I do it still goes wrong.. it also use fstat64, futex and others syscall that I don't know.
I can show you some sample of my codes or detail a bit more it's really hard to explain for me I'm sorry for that.
Thanks you.
PS : I don't get that statement in the readdir manpage : "The data returned by readdir may be overwritten by subsequent calls to readdir for the same directory stream"
PS : I don't get that statement in the readdir manpage : "The data
returned by readdir may be overwritten by subsequent calls to readdir
for the same directory stream"
What they are basically saying is that the function is not re-entrant, and that the pointer returned by readdir shouldn't simply be cached as a unique value, as the underlying data that is being pointed to will change the next time you call the readdir function. Basically they are allowing for implementations to either define statically allocated data that can be recycled by the function, or dynamic memory managed by the OS, so that the caller of readdir does not have to worry about managing the memory pointed to by the return value of readdir. For instance, for a sample function like:
int* my_sample_increment()
{
static int val = 0;
val++;
return &val;
}
if you were to-do something like
int* int_ptr_1 = my_sample_increment();
int* int_ptr_2 = my_sample_increment();
Then both int_ptr_1 and int_ptr_2 will point to the same value, and in this case it will be the value 1. Each pointer won't be pointing to a unique integer value.
So the same is true with readdir. You cannot simply call readdir and store the pointer being returned, expecting to use it at a later date without the data that is being pointed to being modified by any subsequent calls to readdir between the time you saved the pointer, and the time you use it. If you need such functionality, that is what the re-entrant version, readdir_r is for.