I need to find the name of a file using * in a C program. There is exactly 1 file in the specific folder that has the extension .UBX. I can do this in terminal but it doesn't work in C. Can anyone give me example code to do this?
//There is exactly 1 file that ends in .UBX
#define FILE_TO_SEND "/home/root/logs/*.UBX"
fd = open(FILE_TO_SEND, O_RDONLY);
This should do the trick:
#include <glob.h>
#include <stdlib.h>
#include <fcntl.h>
#define FILE_TO_SEND "/home/root/logs/*.UBX"
int
main (void)
{
glob_t globbuf;
glob(FILE_TO_SEND, 0, NULL, &globbuf);
if (globbuf.gl_pathc > 0)
{
int fd = open(globbuf.gl_pathv[0], O_RDONLY);
// ...
}
globfree(&globbuf);
return 0;
}
Related
Suppose I am asked to output an error if a certain file exist.
for example
I am asked to create a file called "del.txt", however, I have to check if such file exist first, and if it does I have to output an error of code 2.
So I know I have to use the O_EXCL to check if the file exist or not, and if it does I should give an error. however the error code is undefined, but I want to set it to 2.
Any idea how?
Here is my current code:
char *filename = "del.txt";
int n;
if((n = open(filename, O_EXCL) > 0){
perror(filename);
exit(1);
};
I am currently getting this:
del.txt: Undefined error: 0
The error check should be < 0, not > 0, the flags are missing an access mode (O_RDONLY/O_WRONLY/O_RDWR), and an O_CREAT needs to be used with O_EXCL (or else, POSIX says, the behavior is undefiend).
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
char const *filename = "del.txt";
int n;
if((n = open(filename, O_RDONLY|O_CREAT|O_EXCL) < 0)){
perror(filename);
exit(1);
};
}
I am trying to compile an simple application that uses the read-write hint, here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
errno = 0;
//uint64_t type = RWH_WRITE_LIFE_MEDIUM; <-- [!] not working
uint64_t type = 3;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
//fcntl(fp, F_SET_RW_HINT, &type); <-- [!] not working
fcntl(fp, (1024+12), &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
I've found that the RWH_WRITE_LIFE_MEDIUM is defined at include/uapi/linux/fcntl.h, but I do not know what to do to be able to compile with this options.
Any ideas in how can I compile this without error?
EDIT 1:
Ok, I followed the instructions where I included the #include <linux/fcntl.h> and the #define _GNU_SOURCE and now I get this error:
$ gcc open_file_fcntl.c
In file included from /usr/include/fcntl.h:35:0,
from open_file_fcntl.c:7:
/usr/include/x86_64-linux-gnu/bits/fcntl.h:35:8: error: redefinition of ‘struct flock’
struct flock
^~~~~
In file included from /usr/include/x86_64-linux-gnu/asm/fcntl.h:1:0,
from /usr/include/linux/fcntl.h:5,
from open_file_fcntl.c:6:
/usr/include/asm-generic/fcntl.h:196:8: note: originally defined here
struct flock {
^~~~~
I am using kernel 5.0.0-23-generic, and gcc --version 7.4.0.
Also tested on a QEMU environment using kernel 4.14.78, and gcc --version 4.8.4.
The simplest solution is to define the _GNU_SOURCE macro before #include <fcntl.h>. As there may be other interactions, it is better to define it before any #include directives:
open_file_fcntl.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
errno = 0;
uint64_t type = RWH_WRITE_LIFE_MEDIUM;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
fcntl(fp, F_SET_RW_HINT, &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
Alternatively, the #define _GNU_SOURCE can be removed from the source code (open_file_fcntl.c above) and the macro defined on the compiler command line:
$ gcc -D_GNU_SOURCE open_file_fcntl.c
These are Linux-specific flags, so you need to either pass -D_GNU_SOURCE to the compiler or put #define _GNU_SOURCE at the top of your source file.
After following the other answer, I got a different problem, and for that, I could reach the final solution.
By checking both definitions of the struct flock in the above-mentioned locations, there is a #define that can be set at the application layer to avoid the redefinition, which is the #define HAVE_ARCH_STRUCT_FLOCK.
It must be added in between the fcntl.h includes.
Here is the complete code:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#define HAVE_ARCH_STRUCT_FLOCK
#include <linux/fcntl.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
uint64_t type = RWH_WRITE_LIFE_MEDIUM;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
fcntl(fp, F_SET_RW_HINT, &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
I'd like to use following Shell command in my c programm:
echo 1=150 > /dev/mydevice
If I'm right the syntax for echo is:
echo [option(s)] [string(s)]
So I came up with the following c code:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open("/dev/mydevice", O_RDWR);
write(fd, "1=150", 6);
return 0;
}
Is it even possible that way? Can you spot out the error(s)?
Is there a good option do debug a device write?
EDIT:
Thanks a million!!!
It was the Newline caracter. Now I was able to work out two solutions:
1)
int main()
{
int fd = open("/dev/mydevice", O_RDWR);
write(fd, "1=150\n", 6);
return 0;
}
2)
int main()
{
system("echo 1=150 > /dev/mydevice");
return 0;
}
Sorry I missed the "Answer-Button". I already put the answer as an edit to the question.
I am trying to map a kernel buffer in user space using mmap method in linux 3.10.10. But it is returning MAP_FAILED. Why it is failed to map the buffer.
Kernel module
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/init.h> /* Needed for the macros */
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
//#include <linux/malloc.h>
#include <linux/mm.h> /* mmap related stuff */
long long *buf1;
long long* buf;
static int driver_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_LOCKED|VM_SHARED;
int i = remap_pfn_range(vma, vma->vm_start,
virt_to_phys(buf) >> PAGE_SHIFT,
vma->vm_end-vma->vm_start, vma->vm_page_prot);
SetPageReserved(virt_to_page(buf));
printk("MMAP \n");
return 0;
}
struct file_operations proc_fops =
{
mmap:driver_mmap,
};
int init_module_test(void)
{
int i;
buf1 = kmalloc(4096, __GFP_COLD|GFP_DMA);
buf = ((int)buf1 + PAGE_SIZE -1) & PAGE_MASK;
printk("<1>Hello world1\n");
for (i = 0; i < 512; i++)
{
buf[i] = (long long) i + 1;
}
proc_create ("mmap_example",0,NULL, &proc_fops);
printk("<1>Hello world3\n");
printk("<1>BUF1 = 0x%08x\n BUF = 0x%08x\n", buf1,buf);
return 0;
}
void cleanup_module_test(void)
{
remove_proc_entry ("mmap_example", NULL);
kfree(buf1);
printk("Goodbye world\n");
}
module_init(init_module_test);
module_exit(cleanup_module_test);
Application code
#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
int main(void)
{
int fd, i;
long long *msg = NULL;
if ((fd = fopen("/proc/mmap_example", "r")) < 0)
{
printf("File not opened");
}
msg = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
if (msg == MAP_FAILED)
{
printf("MAP failed");
return 0;
}
for (i = 0; i < 512; i++)
printf("0x%llx,", msg[i]);
fclose(fd);
return 0;
}
I always end up seing "MAP failed".
Is there something wrong with my code?
The first problem is that you are attempting to use fopen to open a file and placing the return value in an integer, but fopen doesn't return an integer. It returns FILE *. This tells me you are ignoring compiler warnings and errors. That's a bad idea: they're produced for a reason.
The second problem is that you actually do need an integer file handle in order to provide it as an argument to mmap(2). For that, you should be calling open(2) (not fopen(3)).
There may well be additional problems with this code, but that's a start.
well, i can't comment so i post an answer that is not one, but i hope it will be still useful:
i'm not sure about the driver, but you can use the errno method (http://man7.org/linux/man-pages/man3/errno.3.html) on mmap to have a better answer on why it's failing:
add in your application code at the right place:
#include <errno.h>
printf("%i",errno);
or you could maybe use the following if you don't want to print the errno :
cpp -dM /usr/include/errno.h | grep 'define E' | sort -n -k 3
from How to know what the 'errno' means?
debugfs can't handle mmap
I know this is not your exact case, but it also makes mmap fail with MAP_FAILED, and it may help future Googlers: https://patchwork.kernel.org/patch/9252557/
And here is a fully working procfs example with an userland test.
Now I do have a hw question for everyone...I've been staring at this for a couple of days kind of tinkering and playing around but even with that I end up with a load of errors...
What I'm trying to do is take the program below and change it so that it takes an optional command line argument infile. If infile is given, then copy infile to standard output, otherwise copy standard input to standard output as before.
The trick about this is that the solution must use the original copy loop (lines 9-11) for both cases. One can only insert code, and not change any of the existing code. Any help would be great. Thanks.
/* $begin cpfile */
include "csapp.h"
int main(int argc, char **argv)
{
int n;
rio_t rio;
char buf[MAXLINE];
Rio_readinitb(&rio, STDIN_FILENO); //line 9
while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) //line 10
Rio_writen(STDOUT_FILENO, buf, n); //line 11
/* $end cpfile */
exit(0);
/* $begin cpfile */
}
/* $end cpfile */
C programs get command line arguments through the two arguments to main(), traditionally called argc and argv (for argument count and argument vector, respectively).
Arguments are not "named" anything, they're just strings.
A solution for you could look like this:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fileno;
/* ... your definitions should remain here, too */
if(argc > 1)
{
/* Assume first argument is filename, and open it. */
fileno = open(argv[1], O_RDONLY);
if(fileno < 0)
{
printf("Unable to open file, aborting\n");
return 1;
}
}
else
fileno = STDIN_FILENO;
/* ... your code goes here ... */
}
Then you'd of course need to change the call to Rio_readinitb() to use the fileno variable for the file descriptor.
If you literally can't change that line, for whatever reason ... I guess you can use the preprocessor to make the symbol evaluate to the new variable name:
#undef STDIN_FILENO
#define STDIN_FILENO fileno
This is of course not exactly pretty, but should work.
Make sure you put those preprocessor macros after the fileno = STDIN_FILENO; line.
You can insert dup2 before the lines 9 - 11 and it seems that you will not need change code on the lines 9 - 11. This is an example.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int file_handle;
int dup2_res;
if (argc == 2) {
file_handle = open(argv[1], O_RDONLY);
dup2_res = dup2 (file_handle, STDIN_FILENO);
}
char buffer[100];
ssize_t read_bytes = 1;
while (read_bytes)
{
read_bytes = read(STDIN_FILENO, &buffer, sizeof(buffer) );
buffer[read_bytes] = 0;
printf("%s", buffer);
}
close(file_handle);
return 0;
}
If STDIN_FILENO cannot be reassigned, it sounds like a task for freopen():
freopen(argv[1], "r", stdin);