why is copy_file_range() undefined with 4.15 Linux kernel? - linux

The manpage for copy_file_range() at
https://man7.org/linux/man-pages/man2/copy_file_range.2.html
says:
#define _GNU_SOURCE
#include <unistd.h>
ssize_t copy_file_range(
(...)
The copy_file_range() system call first appeared in Linux 4.5
but when I try to compile the user sample code that contains the above, I get
warning: implicit declaration of function ‘copy_file_range’(...)
In function ‘main':
(...)undefined reference to ‘copy_file_range'
and I have Linux 4.15 :
$uname -r
4.15.0-142-generic
NOTE: I don't want to use any user-mode version which may or may not be present in glibc. I want to use the kernel version which should be available according to the manpage and also to all the Googling I could find. I want to know why is it not available - is the documentation completely wrong? Is it missing some crucial requirement for compilation? Am I completely not understanding something basic?
Full data which I think is irrelevant:
Full sample code foobar.c from the documentation:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
int fd_in, fd_out;
struct stat stat;
off64_t len, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s <source> <destination>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd_in = open(argv[1], O_RDONLY);
if (fd_in == -1) {
perror("open (argv[1])");
exit(EXIT_FAILURE);
}
if (fstat(fd_in, &stat) == -1) {
perror("fstat");
exit(EXIT_FAILURE);
}
len = stat.st_size;
fd_out = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd_out == -1) {
perror("open (argv[2])");
exit(EXIT_FAILURE);
}
do {
ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0);
if (ret == -1) {
perror("copy_file_range");
exit(EXIT_FAILURE);
}
len -= ret;
} while (len > 0 && ret > 0);
close(fd_in);
close(fd_out);
exit(EXIT_SUCCESS);
}
Full errors:
$ gcc foobar.c
foobar.c: In function ‘main’:
foobar.c:40:19: warning: implicit declaration of function ‘copy_file_range’; did you mean ‘sync_file_range’? [-Wimplicit-function-declaration]
40 | ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0);
| ^~~~~~~~~~~~~~~
| sync_file_range
/tmp/ccfnzueg.o: In function `main':
foobar.c:(.text+0x127): undefined reference to `copy_file_range'
collect2: error: ld returned 1 exit status

Related

Why mmap throws error while using MAP_FIXED?

Using Ubuntu 16.04, kernel 4.17.4
I am trying the following code where I have defined a shared memory and mapped current process's address space to the shared memory. When I use MAP_FIXED in mmap() it shows:
mmap: Invalid argument
The code is as follows:
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define STORAGE_ID "/SHM_TEST"
#define STORAGE_SIZE 4096
int main(int argc, char *argv[])
{
int res, temp;
int fd;
int len;
pid_t pid;
void *addr;
char data[STORAGE_SIZE];
fd = shm_open(STORAGE_ID, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1)
{
perror("open");
return 10;
}
res = ftruncate(fd, STORAGE_SIZE);
if (res == -1)
{
perror("ftruncate");
return 20;
}
addr = mmap(NULL, STORAGE_SIZE, PROT_WRITE, MAP_FIXED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap");
return 30;
}
res = munmap(addr, STORAGE_SIZE);
if (res == -1)
{
perror("munmap");
return 40;
}
// shm_open cleanup
fd = shm_unlink(STORAGE_ID);
if (fd == -1)
{
perror("unlink");
return 100;
}
return 0;
}
The reason I am using MAP_FIXED is I will manually put an address instead of NULL (tried this and got same error). What do I need to do to use MAP_FIXED with mmap()?

ioctl() and file open mode

I wonder if I should open a file using mode O_RDONLY, O_WRONLY or O_RDWR before calling ioctl.
There are reading and writing ioctls. For example _IOC_DIR(VIDIOC_QUERYCAP) will return _IOC_READ.
So I thought when I am calling this ioctl I have to open the file O_RDONLY.
But surprisingly I can open the file with mode=0 and it's still working:
#include <stdio.h> // for printf()
#include <linux/videodev2.h> // for struct v4l2_capability
#include <fcntl.h> // for open()
#include <sys/ioctl.h> // for ioctl()
#include <unistd.h> // for close()
int main(int argc, char** argv)
{
int fd = open("/dev/video0", 0); // mode set to 0
if (fd == -1)
{
printf("open failed\n");
return 1;
}
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
{
printf("ioctl failed\n");
close(fd);
return 1;
}
printf("%s\n", cap.card);
return 0;
}
So my question is how to set the mode properly. Maybe someone got a link to an official documentation.

How to delete/release a named semaphore from linux command prompt?

I have a code as under.It crashes when accessing the semaphore and I have created "named semaphores" that I am unable to delete from command prompt after the crash. How can I delete them using a command prompt utility? The code is trying to create Rock,Paper,Scissors game that can be run from 2 producer(player) command prompts and one consumer (result) command prompt. I would also appreciate suggestions to fix/correct/improve the code.
//compiled by executing --> gcc -pthread logic.c -lrt
#include <stdio.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
//don't need an exec call just based on paramters run the processes
typedef struct sync_tools
{
int pid;
void* shm_ptr;
sem_t* sem_array[2];
} sync_tools;
void producer(void * ctx)
{
char choice;
sync_tools *ctxt=(sync_tools*)ctx;
while(1)
{
printf ("Enter the following for input \n");
printf ("R. Rock\n");
printf ("P. Paper\n");
printf ("S. Scissors\n");
scanf ("%c",&choice);
if (ctxt->pid==1)
{
printf ("Process1\n");
sem_wait(ctxt->sem_array[0]);
sprintf((char*) ctxt->shm_ptr, "%c\n", choice);
sem_post(ctxt->sem_array[0]);
printf ("Process1\n");
}
else
{
printf ("Process2\n");
sem_wait(ctxt->sem_array[1]);
sprintf((char*) (ctxt->shm_ptr+1), "%c\n", choice);
sem_post(ctxt->sem_array[1]);
}
}
}
//need 2 semphores for sync
void consumer(void *ctx)
{
sync_tools *ctxt=(sync_tools*)ctx;
char data[2]={0x00};
int flag=1;
while(1)
{
sem_wait(ctxt->sem_array[0]);
sem_wait(ctxt->sem_array[1]);
scanf ((char *) ctxt->shm_ptr, "%c", &data[0]);
scanf ((char *) (ctxt->shm_ptr+1), "%c", &data[1]);
switch(data[0])
{
case 'R':
case 'r':
if ((data[1] =='p')|| (data[1]=='P'));
flag=0;
break;
case'P':
case'p':
if ((data[1] =='s')|| (data[1]=='S'));
flag=0;
break;
case 's':
case'S':
if ((data[1] =='R')|| (data[1]=='R'));
flag=0;
break;
}
if (flag)
printf("Process 1 wins \n");
else
printf("Process 2 wins \n");
sem_post(ctxt->sem_array[0]);
sem_post(ctxt->sem_array[1]);
}
}
int main (int argc, char* argv[])
{
char choice;
int SIZE=4096;
char *name="SHM_WQ";
sync_tools cntxt={}; //initialize without memset
//calling sem_open as I want a named semaphore which is not locally available by copy like in forked processes.
cntxt.sem_array[0]= sem_open ("P1C", O_CREAT | O_EXCL, 0644, 1);
cntxt.sem_array[1]= sem_open ("P2C", O_CREAT | O_EXCL, 0644, 1);
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory object */
void* ptr;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0); //sys/mman.h
cntxt.shm_ptr=ptr;
//pass the shared memory and semaphores to all the threads and spawn them
if(strcmp(argv[1], "p1") == 0)
cntxt.pid=1;
else if (strcmp(argv[1], "p2") ==0)
cntxt.pid=2;
else if (strcmp(argv[1], "c") ==0)
cntxt.pid=3;//don't care
producer(&cntxt);
consumer(&cntxt);
}
Modified my code as under:
cntxt.sem_array[0] = sem_open("P1C", 0);
cntxt.sem_array[1] = sem_open("P2C", 0);
if (cntxt.sem_array[0] == NULL)
{
cntxt.sem_array[0]= sem_open ("P1C", O_CREAT | O_EXCL, 0644, 2);
}
if (cntxt.sem_array[1] == NULL)
{
cntxt.sem_array[1]= sem_open ("P2C", O_CREAT | O_EXCL, 0644, 2);
}
if ((cntxt.sem_array[0] == NULL) || (cntxt.sem_array[1] == NULL))
printf("SEM_OPEN ERROR");
Also as mentioned in the comment, created a small utility that takes semname and unlinks it from kernel.

Memory mapped files failing in ecryptfs directory

On a regular ubuntu machine, the following test succeeds unless I run it in my home directory, in which case it crashes with a bus error. All I can think of is that it's because the home directory is encrypted. (I find Private and .ecryptfs links there.)
// Make with g++ -mcmodel=large -fPIC -g -O0 -o checkmm checkmm.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#define TALLIES "tallies.bin"
#define NUM_TALLIES (550588000/sizeof(int))
typedef struct { int tallies[NUM_TALLIES]; } World;
World* world;
void loadWorld() {
int fd = open(TALLIES, O_RDWR | O_CREAT);
if (fd == -1) { printf("Can't open tallies file %s\n", TALLIES); exit(0); }
fallocate(fd, 0, 0, sizeof(World));
world = (World*) mmap(0, sizeof(World), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (world ==(World*) -1) { printf("Failed to map tallies file %s\n", TALLIES); exit(1); }
}
void unloadWorld() { munmap(world, sizeof(World)); }
void resetWorld() {
int i;
for (i=0;i<NUM_TALLIES;i++) world->tallies[i]=-1;
}
int main() {
loadWorld();
resetWorld();
unloadWorld();
}
Can anyone elucidate?
You should check the return codes for each system call. Particularly fallocate() and mmap().
fallocate() is supported on a handful of filesystems. You should use ftruncate() if fallocate() fails (with errno set to EOPNOTSUPP).

How to undo strip - i.e. add symbols back to stripped binary

I have a stripped binary and symbol-file. Is it possible to add the symbols back to binary and create an unstripped binary.
My use-case is using this binary w/ valgrind.
For those tools that do not support separate files for debug information, you can glue the debug sections back to the original binary.
You can do something along these lines, for example:
First build a small program that efficiently extracts an arbitrary chunk from a file
(note that dd will not do this efficiently as we'd have to use bs=1 to support an arbitrary offset and length, and objcopy -O binary does not copy sections that are not ALLOC, LOAD※)
cat <<EOF | gcc -xc -o ./mydd -
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <macros.h>
char buf[1024*1024];
int main(int argc, char** argv) {
char *fin, *fout;
int fdin, fdout;
off_t off;
size_t len;
ssize_t rd;
int status;
if (argc != 5) {
fprintf(stderr, "Usage: %s fin skip count fout\n", argv[0]);
return 1;
}
fin = argv[1];
off = strtoul(argv[2], NULL, 0);
len = strtoul(argv[3], NULL, 0);
fout = argv[4];
fdin = -1;
fdout = -1;
if ((fdin = open(fin, O_RDONLY)) < 0) {
status = errno;
perror(fin);
} else if ((fdout = open(fout, O_WRONLY|O_TRUNC|O_CREAT, 0660)) < 0) {
status = errno;
perror(fout);
} else if (lseek(fdin, off, SEEK_SET) == (off_t)-1) {
status = errno;
perror("Seeking input");
} else {
while (len > 0 && (rd = read(fdin, buf, min(len, sizeof(buf)))) > 0) {
if (write(fdout, buf, rd) != rd) {
/*don't bother with partial writes or EINTR/EAGAIN*/
status = errno;
perror(fin);
break;
}
len -= rd;
}
if (rd < 0) {
status = errno;
perror(fin);
}
}
if (fdin >= 0) close(fdin);
if (fdout >= 0) close(fdout);
return status;
}
EOF
Finally, extract the .debug sections and glue them to the stripped binary.
objcopy `
objdump -h program.dbg |
awk '$2~/^\.debug/' |
while read idx name size vma lma off algn ; do
echo "$name" >&2
echo " --add-section=$name=$name.raw"
./mydd program.dbg 0x$off 0x$size $name".raw"
done
` program program_with_dbg
elfutils comes with the tool eu-unstrip which can be used to merge symbol files with executables. The result can then be used in place of the stripped version.
Valgrind supports separate debug files, so you should use the answer here, and valgrind should work properly with the externalized debug file.

Resources