The man page of open() shows open has two definitions.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
I was trying to make a wrap around open to add a backtrace for some debugging. The definition in fnctl.h shows it as a variable argument function
int open(const char *path, int oflag, ... );
But how can I know whether mode is present or not?
The mode argument is not needed for all open flags. For example, if opening an existing file for reading, there's no need to set the file mode flags. On the other hand, when creating a file, you need to include the mode.
See the documentation for open (or your local manual page) to see if you need to include the argument or not.
open() function -
int open (const char *filename, int flags[, mode_t mode])
mode is only used when file is created. No need when file is already present but it won't affect also in either way .
If flags include O_CREAT, there must be a third argument (mode). If not, or if the file already exists, the third argument (if supplied) will be ignored.
Since open is actually variadic, you can call it with any number of arguments (>2), but they will have no effect on the operation.
You will need to extract the mode argument using stdarg.h. The C variadic function feature does not provide any mechanism for a function to find out how many arguments it was called with, so all you can do is check the flag.
Related
Hi I'm on Linux WSL Debian and I've the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[]) {
int fd = open("file.dat", O_RDONLY | O_WRONLY);
write(fd, "ciao", strlen("ciao"));
close(fd);
}
Why don't works?
Many bugs:
Must include unistd.h for the declaration of write.
O_RDONLY and O_WRONLY (and O_RDWR) are mutually exclusive. If you want to open a file for read and write you have to use O_RDWR. Since you are not actually reading from the file, you should use O_WRONLY alone.
It is very rare to want to use O_WRONLY without O_CREAT and one (exactly one; these three are also mutually exclusive) of O_APPEND, O_EXCL, and O_TRUNC. Assuming that you do want O_CREAT, you must also supply a third argument, which should be the octal constant 0666 unless you have a specific reason to use some other value.
write(fd, "ciao", strlen("ciao")) should be write(fd, "ciao\n", strlen("ciao\n")) unless you have a specific reason to be creating a text file with an incomplete last line.
Because you are writing to a file, you need to check for errors on all three of the open, write, and close calls. (The fact that close can fail is a bug in its specification, but one that we are permanently stuck with. It's safe to ignore errors in close for files that were opened for reading, but not writing.)
Also some style corrections:
The code as shown only needs unistd.h, fcntl.h, and string.h; it should also be including stdio.h, because it should also be making calls to perror. None of the other headers should be included (unless this is cut down from a much larger program).
Declare main as int main(void) unless you are actually going to use argc and argv.
Don't use the C99 license to fall off the end of main; the last line of main should be return 0;.
For historical reasons, in C, the opening curly brace of a function definition should always be placed on a line by itself, even if all other opening curly braces are "cuddled" with their parent control flow construct.
You need the header <unistd.h> to get the declarations of write() and close(). The only other header you need is <fcntl.h> for open().
I've also kept <stdio.h> so I can use perror() if open() fails.
Since you're only writing to the file, you don't need O_RDONLY in the open modes. If you want to read and write, you should use O_RDWR instead. These three flags are mutually exclusive.
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
int fd=open("file.dat",O_WRONLY);
if (fd < 0) {
perror("open failed");
return 1;
}
write(fd,"ciao",strlen("ciao"));
close(fd);
}
Note that this will not create the file if it doesn't already exist. If you want that, you need to add the O_CREAT flag and another argument with the permissions that should be given to the file if it's created.
I want to implement a wrapper over the open system call, and I'm using the LD_PRELOAD trick to call my new open.
The problem is that open expects a variable number of arguments, and I cannot figure out how to call open with the same set of arguments, as open cannot take a va_list pointer as an argument(or I do not know of any such function).
How could I achieve this?
code so far:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
typedef int (*open_func_t)(const char*, int, ...)
int open(const char *pathname, int flags, ...){
// some custom code
// what args should I supply to dlsym?
return ((open_func_t)dlsym(RTLD_NEXT, "open"))(args);
}
I want to use open_excl(3) in order to open a file for exclusive writing.
I wrote:
#include <open.h>
int main(int c, char* v[]){
int fp = open_excl("my_file");
return 0;
}
Now:
gcc -Wall file.c -o out.a
And I get a fatal compiler error: open.h: No such file or directory
How come? do I have a broken path problem? Missing a link to a library?
Wrong version of gcc? I'm using 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
The open_excl is not a standard function; I don't have open.h on my Linux system. As the documentation on linux.die.net says:
open_excl opens the file filename for writing and returns the file handle. The file may not exist before the call to open_excl. The file will be created with mode 0600.
[...] open_excl relies on the O_EXCL flag to openĀ [...]
Thus you could achieve the same with
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);
By calling it as follows:
int fd = open(filename, O_EXCL|O_CREAT|O_WRONLY, 0600);
To wrap the file descriptor into FILE * use the fdopen function:
#include <stdio.h>
FILE *fp = fdopen(fd);
Whenever you include any header file, the compiler looks for the same in standard directory if angular brackets are used #include <open.h> and in project directory if quotes are used #include "open.h".
So you can first check if you have the open.h file in the standard directory (which probably is not the case), you can download and copy the header file in your local directory and use quotes include the same.
I am looking for a way to find the name of the executable file which runs it. meaning that if I have a file called program which runs something I would like to get its name.
Using __FILE__ does not suite me since I need the executable name not the C files name which contains the code.
I am wondering if there is a gcc macro which can help me or a built in function which I couldn't find.
EDIT:
Also using argv[0] is not appropriate since I need to call the function not only inside main.
And passing the argv[0] parameter to all the functions that might need this parameter also isnt acceptable since it will be used in the entire system (I need to hash by it).
int main(int argc,char* argv[])
{
printf("%s",argv[0]);
return 0;
}
The first argument(argv[0]) contains the name of the program which is being run.
The standard definition for main() in C is:
int main(int argc, char **argv)
argv[0] contains the name of the program as executed.
From main, pass argv[0] to wherever you might need the program's name.
Or if a lot of functions need it and you want to avoid passing it around too much, assign it to a global variable.
You asked for macros as a solution, but they are expanded at compile time. And since the name of the executable file can be changed after compilation, what you want cannot be determined at compile time, so macros are out of question.
Often remembering argv[0] from main will be quite sufficient.
If this is not the case -- for example if you're a shared library, or if you worry that your caller started you with a faked argv[0] (this is possible but unusual), you can, on POSIX-compliant systems with a mounted /proc, use readlink to resolve /proc/self/exe and get a path to the main binary of the running process:
#include <limits.h>
#include <unistd.h>
// Note that readlink does not null-terminate the result itself. This
// is important if the link target contains null bytes itself, I suppose,
// but it means that you have to take care that the null-terminator is
// placed yourself if you're going to use the file name as a string.
char buf[PATH_MAX] = { 0 };
readlink("/proc/self/exe", buf, PATH_MAX);
And on Windows, there is the GetModuleFileName function:
#include <windows.h>
TCHAR buf[MAX_PATH];
GetModuleFileName(NULL, buf, MAX_PATH);
The startup name is given via main()'s argv[0] and can be considered constant.
So why not make it available through out the program using a global reference to it.
progname.h
#ifndef PROGNAME_H
#define PROGNAME_H
extern char * progname;
#endif
main.c
#include "progname.h"
char * progname = NULL;
int main(int argc, char ** argv)
{
progname = argv[0];
...
}
Access it from any where like so
module1.c
#include <stdio.h>
#include "progname.h"
void f(void)
{
printf("progname='%s'\n", progname ?progname :"<not set>");
}
When I attempt to overwrite an existing file, I get a "permission denied" error.
I noticed that the file which is created has the "Read-only" attribute set. When I manually unset this I can then overwrite the file. Is there some flag I can pass to open() which will automatically unset this when I create a file?
Below is a bare bones example which illustrates the problem. The first run works, but the second produces the "permission denied" error.
Thanks,
Zach (New to MingW/Windows 7)
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char ** argv) {
int fid;
double data = 12.0;
if ( (fid = open("junk.data", O_WRONLY | O_CREAT | O_BINARY)) == -1 ) {
printf("ERROR opening.\n\terror is:%s\n", strerror(errno));
return 1;
}
write(fid, &data, sizeof(double));
close(fid);
return 0;
}
I tried both 0644 and S_IRUSR | S_IWUSR (with sys/stat.h included) and either works.
Make sure that you actually add it as third argument of open, instead as new term into the surrounding parentheses (as happened for me first, and compiles just fine)
open has a three-parameter variant:
int open(const char *pathname, int flags, mode_t mode);
That third parameter allows you to specify the mode bits on Unix-type systems, but should be enough to set minimal r/w permissions on windows. (Check out the man page for details.)