I want to manipulate Stdin and then Std*. But I am getting the following errors,
$ gcc testFd.c
testFd.c:9: error: initializer element is not constant
testFd.c:9: warning: data definition has no type or storage class
testFd.c:10: error: redefinition of `fd'
testFd.c:9: error: `fd' previously defined here
testFd.c:10: error: `mode' undeclared here (not in a function)
testFd.c:10: error: initializer element is not constant
testFd.c:10: warning: data definition has no type or storage class
testFd.c:12: error: syntax error before string constant
The program is shown below.
#include <stdio.h>
#include <sys/ioctl.h>
int STDIN_FILENO = 1;
// I want to access typed
// Shell commands, dunno about the value:
unsigned long F_DUPFD;
fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
fd = open("/dev/fd/0", mode);
printf("STDIN = %s", fd);
Updated Errors: just trying to get an example program about file descriptors to work in C, pretty lost with the err report
#include <stdio.h>
#include <sys/ioctl.h>
int main (void) {
int STDIN_FILENO;
// I want to access typed
// Shell commands, dunno about the value:
unsigned long F_DUPFD;
int fd;
const char mode = 'r';
fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
/* also, did you mean `fopen'? */
fd = fopen("/dev/fd/0", mode);
printf("STDIN = %s", fd);
return 0;
}
The program execution is shown below.
$ gcc testFd.c
testFd.c: In function `main':
testFd.c:14: warning: passing arg 2 of `fopen' makes pointer from integer without a cast
testFd.c:14: warning: assignment makes integer from pointer without a cast
Try using a main method:
#include <stdio.h>
#include <sys/ioctl.h>
int main (void) {
int STDIN_FILENO = 1;
// I want to access typed
// Shell commands, dunno about the value:
unsigned long F_DUPFD;
/* also, declare the type of your variable "fd" */
int fd;
fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
/* also, did you mean `fopen'? */
fd = open("/dev/fd/0", mode);
printf("STDIN = %s", fd);
return 0;
}
You forgot your main() function!!
Where's your definition of main()?
Quite apart from the fact that you don't have a main() function, your entire approach is wrong. STDIN_FILENO is a constant; assigning to it doesn't make any sense.
Try explaining what you actually want to do, with some detail, and we will be able to suggest how to go about it.
Related
Found this code, it needed to stop throttling the CPU to 20% in Dell laptops, which occurs due to the power adapter failing to be recognized by the computer.
Tried to compile on Kubuntu and got this:
warning: implicit declaration of function ‘asprintf’; did you mean ‘vasprintf’? [-Wimplicit-function-declaration]
47 | if (asprintf(&concat_cmd, "%s %i", cmd, *reg_value) == -1)
| ^~~~~~~~
| vasprintf
I don’t understand why it is happening. I read that asprintf is part of the libiberty-dev. The library is installed but everything does not work. Also I added
#include <libiberty/libiberty.h>
and got the same - implicit declaration of function ‘asprintf’
tell me what to do with it?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <libiberty/libiberty.h>
#define BUFSIZE (64)
int get_msr_value(uint64_t *reg_value) {
const char *cmd = "rdmsr -u 0x1FC";
char cmd_buf[BUFSIZE];
FILE *fp;
if ((fp = popen(cmd, "r")) == NULL) {
printf("Error opening pipe!\n");
return -1;
}
cmd_buf[strcspn(fgets(cmd_buf, BUFSIZE, fp), "\n")] = 0;
*reg_value = atoi(cmd_buf);
if (pclose(fp)) {
printf("Command not found or exited with error status\n");
return -1;
}
return 0;
}
int main(void) {
const char *cmd = "wrmsr -a 0x1FC";
char *concat_cmd;
int ret;
uint64_t *reg_value = &(uint64_t){ 0 };
if ((ret = get_msr_value(reg_value))) {
return ret;
}
printf("Old register value: %lu\n", *reg_value);
*reg_value = *reg_value & 0xFFFFFFFE; // clear bit 0
printf("New register value: %lu\n", *reg_value);
if (asprintf(&concat_cmd, "%s %i", cmd, *reg_value) == -1)
return -1;
printf("Executing: %s\n", concat_cmd);
system(concat_cmd);
free(concat_cmd);
return 0;
}
asprintf is part of stdio.h, but you need to add #define _GNU_SOURCE at the top of your file and use -std=gnu99 when compiling.
The function asprintf() is not yet part of the C Standard. It is available in the GNU libc and most likely supported on your system since it uses this C library, with a declaration in <stdio.h>.
You might need to define __GNU_SOURCE or __USE_GNU before including <stdio.h> for this declaration to be parsed by the compiler. Run man asprintf to see which feature macro to use or look inside the file /usr/include/stdio.h on your system.
Either modify the source code or add a -D__GNU_SOURCE command line argument in your CFLAGS in the Makefile.
So the problem is the following. The project needs to intercept all file IO
operations, like open() and close(). I am trying to add printf() before calling the corresponding open() or close(). I am not supposed to rewrite the source code by changing open() or close() to myOpen() or myClose() for example. I have been trying to use LD_PRELOAD environment variable. But the indefinite loop problem came up. My problem is like this one.
int open(char * path,int flags,int mode)
{
// print file name
printf("open :%s\n",path);
return __open(path,flags,mode);
}
Yes, you want LD_PRELOAD.
You need to create a shared library (.so) that has code for all functions that you want to intercept. And, you want to set LD_PRELOAD to use that shared library
Here is some sample code for the open function. You'll need to do something similar for each function you want to intercept:
#define _GNU_SOURCE
#include <dlfcn.h>
int
open(const char *file,int flags,int mode)
{
static int (*real_open)(const char *file,int flags,int mode) = NULL;
int fd;
if (real_open == NULL)
real_open = dlsym(RTLD_NEXT,"open");
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
I believe RTLD_NEXT is easiest and may be sufficient. Otherwise, you could add a constructor that does dlopen once on libc
UPDATE:
I am not familiar with C and I got the following problems with gcc. "error: 'NULL' undeclared (first use in this function)",
This is defined by several #include files, so try #include <stdio.h>. You'll need that if you want to call printf.
"error: 'RTLD_NEXT' undeclared (first use in this function)",
That is defined by doing #include <dlfcn.h> [as shown in my example]
and "symbol lookup error: ./hack_stackoverflow.so: undefined symbol: dlsym".
From man dlsym, it says: Link with -ldl So, add -ldl to the line that builds your .so.
Also, you have to be careful to prevent infinite recursion if the "special stuff" does something that loops back on your intercept function.
Notably, you want to call printf. If you intercept the write syscall, bad things may happen.
So, you need to keep track of when you're already in one of your intercept functions and not do anything special if already there. See the in_self variable.
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
ssize_t
write(int fd,const void *buf,size_t len)
{
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
static int in_self = 0;
ssize_t err;
if (real_write == NULL)
real_write = dlsym(RTLD_NEXT,"write");
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
err = real_write(fd,buf,len);
if (in_self == 1)
printf("mywrite: fd=%d buf=%p err=%ld\n",fd,buf,err);
--in_self;
return err;
}
The above works okay for single threaded programs/environments, but if you're intercepting an arbitrary one, it could be multithreaded.
So, we'd have to initialize all the real_* pointers in a constructor. This is a function with a special attribute that tells the dynamic loader to call the function ASAP automatically.
And, we have to put in_self into thread local storage. We do this by adding the __thread attribute.
You may need to link with -lpthread as well as -ldl for the multithreaded version.
Edit: We also have to preserve the correct errno value
Putting it all together:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
static int (*real_open)(const char *file,int flags,int mode) = NULL;
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
__attribute__((constructor))
void
my_lib_init(void)
{
real_open = dlsym(RTLD_NEXT,"open");
real_write = dlsym(RTLD_NEXT,"write");
}
int
open(const char *file,int flags,int mode)
{
int fd;
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
ssize_t
write(int fd,const void *buf,size_t len)
{
static int __thread in_self = 0;
int sverr;
ssize_t ret;
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
ret = real_write(fd,buf,len);
// preserve errno value for actual syscall -- otherwise, errno may
// be set by the following printf and _caller_ will get the _wrong_
// errno value
sverr = errno;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p ret=%ld\n",fd,buf,ret);
--in_self;
// restore correct errno value for write syscall
errno = sverr;
return ret;
}
For a homework assignment, I have to modify the linux kernel.
I am working on a virtual machine, and I added a system call to the kernel, which I called get_unique_id. Here is the code for get_unique_id.c :
#include <linux/linkage.h>
#include <asm/uaccess.h>
asmlinkage long sys_get_unique_id(int * uuid)
{
// static because we want its state to persist between calls
static int uid = 0;
++uid;
// assign new uid value to user-provided mem location
// returns non-zero if success or -EFAULT otherwise
int ret = put_user(uid, uuid);
return ret;
}
I also added this line to syscalls.h :
asmlinkage long sys_get_unique_id(int * uuid);
This line to syscall_32.tbl :
383 i386 get_unique_id sys_get_unique_id
And finally this line to syscall_64.tbl :
548 common get_unique_id sys_get_unique_id
After recompiling and reloading the kernel, I wrote a little C program to test my system call, here is the code for the C test file :
// get_unique_id_test.c
#include <stdio.h>
#include <limits.h>
#include "syscalls_test.h"
int main(void)
{
// initialize the ints we want
int id1;
int id2;
// check the id's are unique and that no error occured
for (int i = INT_MIN; i < INT_MAX - 1; i += 2) {
long ret1 = get_unique_id(&id1);
long ret2 = get_unique_id(&id2);
if (ret1 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret1);
if (ret2 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret2);
if (id2 != id1 + 1)
printf("ERROR: successive id's did not increment properly: id1 = %d, id2 = %d\n", id1, id2);
}
return 0;
}
And its header file :
// syscalls_test.h
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define __NR_get_unique_id 383
inline long get_unique_id(int * uuid)
{
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
}
Unfortunately, while trying to compile the C test file with the following command : gcc -std=c99 get_unique_id_test.c -o get_unique_id_test, I get the following error :
In file included from get_unique_id_test.c:4:0:
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
/tmp/cc1euZ3r.o: In function `main':
get_unique_id_test.c:(.text+0x22): undefined reference to `get_unique_id'
get_unique_id_test.c:(.text+0x34): undefined reference to `get_unique_id'
collect2: error: ld returned 1 exit status
It appears gcc cannot find the function get_unique_id(int * uuid), which is declared in syscalls_test.h, and the syscall function, which should be declared, I believe, in syscall.h, right ?
I don't understand why this happens. Does anybody have an idea ?
EDIT : my problems were solved using a3f's solution (see below) PLUS moving the #include "syscalls_test.h" at the very top of the file, as he said in the comments. Thank you very much.
#define _GNU_SOURCE before including unistd.h or any other header as syscall(2) is not POSIX.
Use static inline instead of plain inline. Plain inline supplies an inline definition, but the compiler is free to ignore it and use the external definition instead, which you aren't providing.
Try the following one:
#include <unistd.h>
I have this program that is supposed to mmap a file in read-write mode and be able to edit its contents. Also the file this is written for is about 40-50 GB, so I need mmap64. The problem is, while mmap64 does not return an error, the address it returns is not accessible.
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>
typedef unsigned long long u64;
void access_test(u64 p, u64 sz)
{
u64 i;
char tmp;
for (i=0; i<sz; i++) {
tmp = *(char*)(p+i);
}
}
int main(int argc, char *argv[])
{
int fd;
long long int sz, p;
struct stat buf;
fd = open(argv[1], O_RDWR, 0x0666);
if (fd == -1) {
perror("open");
return 1;
}
fstat64(fd, &buf);
sz = buf.st_size;
printf("File size: 0x%016llx\n", sz);
p = mmap64 (0, buf.st_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
if (p == -1) {
perror ("mmap");
return 1;
}
access_test(p,sz);
if (close (fd) == -1) {
perror ("close");
return 1;
}
if (munmap ((void*)p, buf.st_size) == -1) {
perror ("munmap");
return 1;
}
return 0;
}
The result of this is on a small file:
$ ./testmmap minicom.log
File size: 0x0000000000000023
[1] 8282 segmentation fault (core dumped) ./testmmap minicom.log
The same goes for the big one.
Always enable warnings when you compile
Here is the result with warnings enabled:
$ gcc mmp.c -Wall -g
mmp.c: In function ‘access_test’:
mmp.c:18:10: warning: variable ‘tmp’ set but not used [-Wunused-but-set-variable]
char tmp;
^
mmp.c: In function ‘main’:
mmp.c:36:5: warning: implicit declaration of function ‘fstat64’ [-Wimplicit-function-declaration]
fstat64(fd, &buf);
^
mmp.c:40:5: warning: implicit declaration of function ‘mmap64’ [-Wimplicit-function-declaration]
p = mmap64 (0, buf.st_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
The last two warnings here are extremely important. They say there is no prototype for mmap64. C therefore gives you a default prototype, and it is wrong, at least for the mmap64() call (since the prototype will return an int, which cannot represent a pointer on a 64-bit Linux host)
The argument to fstat64() is a struct stat64 too BTW, which is another issue.
Make the specific 64-bit functions available
If you want to make the fstat64()/mmap64() function available, you need to compile the code with the _LARGEFILE and LARGEFILE64_SOURCE #define, see information here, so you should compile this as e.g:
gcc -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE mmp.c -Wall -g
Or use #define _FILE_OFFSET_BITS=64
There is however no need to do this. Just call the normal fstat() and mmap() and #define _FILE_OFFSET_BITS=64 when compiling. e.g.:
gcc -D_FILE_OFFSET_BITS=64 mmp.c -Wall -g
This will enable support for large files, and e.g. translate the mmap() call to mmap64() if it is needed (e.g. if you're on a 32-bit host).
If you are trying to mmap() an 50 GB file, you anyway need to be on a 64-bit host, and on a 64-bit Linux host there's no need for any of this - mmap() and fstat() handles large files without any need to do anything.
Use pointers
The next issue is you're assigning the return value of mmap() to an integer. This might happen to work, but the code does look odd because of it. If you want to treat the thing as a char *, assign it to a char *. Don't play tricks with casting pointers around to a 64-bit integer type.
E.g. your access function should be:
void access_test(char *p, u64 sz)
{
u64 i;
char tmp;
for (i=0; i<sz; i++) {
tmp = p[i];
}
}
And p should be declared as char *p; in main(), or use uint8_t *p; if you intend to treat the data as binary data.
Mockup of my production code:
/* version 1 */
#include <stdio.h>
FILE** fout = &stdout;
int main() {
fprintf( *fout, "hello\n" );
}
Works fine under gcc, but reportedly fails to compile under mingw (lvalue required as unary '&' operand).
I have seen Is setting a FILE* equal to stdout portable?; I understand that
/* version 2 */
#include <stdio.h>
int main() {
FILE* fout = stdout;
fprintf( fout, "hello\n" );
}
would be perfectly valid. However, I need to preset a global variable. Unfortunately,
/* version 3 */
#include <stdio.h>
FILE* fout = stdout;
int main() {
fprintf( fout, "hello\n" );
}
is not suitable to replace version 1; it does not even compile under gcc (line 2: initializer element is not constant).
Any idea how to get stdout into a variable that is initialized before main() starts?
In Linux (glibc), stdout is defined like this:
extern struct _IO_FILE *stdout;
So, you can do whatever you need with that.
However, on MinGW, stdout is defined like this, in stdio.h:
#define stdout (&_iob[STDOUT_FILENO])
Alas, that's not something you can take the address of, and, as you discovered, it's not something you can use in a global initializer. :-(
The root of the problem is that the C standard says that these should be macros, which means any portable program should make no assumptions about what's inside. So, I'm afraid, there is no easy way to avoid doing reading stdout programmatically. This sort of thing is why many libraries require a lib_initialize() function that must be called before anything else.
C++ does permit constructors for global variables, and these are automatically called before main, even for libraries. It is possible, with gcc, to hack a C program to do the same, but that's an evil trick and I can't remember how to do it off the top of my head.
I'd just do this:
#include <stdio.h>
FILE* fout = NULL;
int my_library_function() {
if (!fout)
fout = stdout;
fprintf( fout, "hello\n" );
}
That isn't a big efficiency problem: you'd have to load fout anyway, and a compare with zero is pretty cheap.
According to the C standard (7.21.1), stdout is a macro which is an expression of type "pointer to FILE". It is not necessarily a global variable. It is not portable C to take its address --- it works in gcc but not in mingw, as you saw.
Use the second version of your code --- this is portable.
The third would be OK too if you moved the initialization of fout inside main:
/* version 3 */
#include <stdio.h>
FILE* fout;
int main() {
fout = stdout;
fprintf( fout, "hello\n" );
}
This initialization cannot be combined with the declaration of fout, as stdout is not (at least, not necessarily) a constant expression.
If you want to have a FILE ** pointer, use:
/* version 4 */
#include <stdio.h>
FILE* mystdout;
FILE** fout = &mystdout;
int main() {
mystdout = stdout;
fprintf( *fout, "hello\n" );
}
but again the initialization of mystdout cannot be at its declaration, for the same reason.
I don't think that this is a very good idea, as file descriptors are not generally portable. Also, it makes the implementation of library functions quite low-level, or you'll have a hard time synchronizing file descriptors and FILE pointers.
However, as #JoachimWuttke explicitly asked, here's what I had in mind in my previous comment:
/* version 5 */
#include <stdio.h>
#include <unistd.h>
int fdout = 1;
void use(FILE *fout)
{
fdout = fileno(fout);
}
void printing() {
const char msg[] = "hello\n";
write(fdout, msg, sizeof(msg)-1);
}
int main() {
printing(); // this one goes to stdout
FILE *f = fopen("output.txt", "wt");
use(f);
printing(); // this one goes to "output.txt"
printing(); // this one too
fclose(f);
use(stdout);
printing(); // this one goes to stdout too
return 0;
}