whats wrong with this code of reading with mmap? - c

I am trying to run this code, while I am ending with -
value: 1
value: 0.000000
My question is why the both results are different??
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
int main ()
{
int fd;
struct stat mystat;
void *pmap;
int i,integer;
double *values;
int32_t *mapped_baseA;
int32_t fdA;
fd = open("test.txt",O_RDWR); // a text file containing- 1 2 3 4 5
if(fd==-1)
{
perror("open");
exit(1);
}
if(fstat(fd,&mystat)<0)
{
perror("fstat");
close(fd);
exit(1);
}
pmap = mmap(0,mystat.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if(pmap==MAP_FAILED)
{
perror("mmap failed");
close(fd);
exit(1);
}
//strncpy(pmap,"That is my name",15);
sscanf (pmap, " %d", &integer);
printf("value: %d \n", integer);
//printing the values after scanning from string.
values = (double *) mmap(0,mystat.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
printf("value: %lf \n", values[1]);
//printing the values from pointer
munmap (pmap, mystat.st_size);
close(fd);
return 0;
}

Read carefully (and several times) mmap(2). Notice:
A file is mapped in multiples of the page size.
and in the ERRORS section
EINVAL We don't like addr, length, or offset (e.g., they are too
large, or not aligned on a page boundary).
Consider also using strace(1) on your executable.
Of course, a memory mapping is just giving a view (as raw sequence of bytes) of the mapped file into the process by modifying its virtual address space. It obviously won't do any conversion (you might use sscanf(3) or strtol(3) on parts of that view to make such a conversion from an UTF8 or ASCII string representation of a number into its machine representation).

Related

Reading data from the end of disk in C

I try to use crypto key for decrypting disk in Ubuntu 16 and I want read it from the end of disk just as raw data without creating any file for security reason, i.e. like dd does in way
sudo dd if=some_disk bs=1 skip=end_of_disk - keysize count=keysize
So, I wrote a test program
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
unsigned long long disksize(char *drivename)
{
int fd;
unsigned long long numblocks=0;
fd = open(drivename, O_RDONLY);
ioctl(fd, BLKGETSIZE64, &numblocks);
close(fd);
return numblocks;
}
int main(int argc, char **argv)
{
int fd;
FILE *device;
int keySize = 2048;
int count;
unsigned char *block;
unsigned long long endOfDisk=disksize(argv[1]);
unsigned long long startFrom = endOfDisk - keySize;
block = calloc(keySize, sizeof(char));
// fd=open(argv[1], O_RDWR | O_DIRECT);
device = fopen(argv[1], "r");
long res = fseek(device, startFrom, SEEK_SET);
perror("\nSeeking error:");
fread(block, 1, keySize, device);
fclose(device);
printf("\nDevice Size: %lld\n", endOfDisk);
printf("\nReading data starting from: %lld\n", startFrom);
for(count = 0; count < keySize; count++){
printf("%c", block[count]);
}
free(block);
}
It works good on small disks, say, on boot partition or USB stick with capacity of 1Gb, but when I try to get key from, say, 4Gb USB stick, I can't: program prints something beyond key area on disk and perror shows "Invalid argument" as result of fseek. It looks like fseek can't set pointer right and I don't understand why:
fdisk -l some_disk
shows exactly the same disk size as endOfDisk from given program.
P.S. As someone can see from a couple of rudiments, I tried lseek too with exactly the same result printing exactly the same info instead of stored on disk key.
ioctl(fd, BLKGETSIZE64, &numblocks) return size in 512-byte blocks, fseek() expect offset in bytes.
BTW, you can set pointer relative to the end of disk without knowing it's size:
fseek(device, -keySize, SEEK_END);

Getting empty output when reading from file using "mmap"

I have a problem considering the usage of mmap. I am trying to map a pci device to a virtual address and read its content. In the future I am planning to write values to it as well.
The problem is that I (seemingly) successfully mapped the device to virtual memory space. However when I read the content of that virtual address all values are zero, despite the file not being empty.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "../include/types.h"
#include "../include/pci.h"
#define PRINT_ERROR \
do { \
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1);\
} while(0)
#define MAP_SIZE 4069
#define MAP_MASK (MAP_SIZE - 1)
int main(int argc, char *argv[])
{
int pci_dev;
int *mmap_base;
int *content;
char file[] = {"/sys/bus/pci/devices/0000:04:00.0/resource"};
int i;
printf("File to be read from: %s\n", file);
pci_dev = open(file, O_RDONLY);
if (pci_dev < 0)
{
PRINT_ERROR;
}
mmap_base = mmap(NULL, MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANON, pci_dev, 0);
if (mmap_base == (void *)-1 || mmap_base == NULL)
{
PRINT_ERROR;
}
printf("Mapped on address %p of size %d Byte\n", mmap_base, (int)MAP_SIZE);
content = (int *)mmap_base;
for(i = 0; i < 1024; i++)
{
printf("%x", content[i]);
}
return 0;
}
Here's the content of the first line from the file "/sys/bus/pci/devices/0000:04:00.0/resource" that I am trying to access:
0x00000000cd000000 0x00000000cd07ffff 0x0000000000040200
However the output I get is:
File to be read from: /sys/bus/pci/devices/0000:04:00.0/resource
Mapped on address 0xb7705000 of size 4096 Byte
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
Am I doing something wrong? Every help is appreciated!
Actually you've got 2 mistakes:
Don't use MAP_ANON when you create a map for a real file on the file system, it's meant for IPC and requiring extra memory from OS e.g. while malloc().
When you remove the flag, the mmap() will likely return ENODEV, because linux sysfs doesn't support mmaping; So you have to use read()'s here.

How do i get ascii character from read?

in this program, I need to store the frequency of the ascii characters i read in an array (in order to print the most frequent). the problem is that what i get from read is not ascii (most probably some kind of address) so in the buf[] array i get out of bounds.
Can anybody tell help me with that?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#define MODEMDEVICE "/dev/ttyAMA0"
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
int main()
{
int fd,c, res=0,i;
struct termios oldtio,newtio;
int buf[128] ;
for (i=0;i<128;i++) buf[i]=0;
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcflush(fd, TCIFLUSH);
while (STOP==FALSE) { /* loop until we have a terminating condition */
int r=read(fd,&c,1);
write(1,&c,1);
if (c=='\n') {
for(i=0;i<128;i++)
if (res < buf[i] )
res = buf[i];
printf("first char %d \n", res);
}
else {
buf[c]++;
}
}
}
int c creates a variable of probably 4 bytes. It is not initialized, thus it may contain any garbage.
Then the system call
read(fd,&c,1)
changes one of these bytes, probably the highest or lowest, while leaving the others unchanged. Now you have a combination of 3 bytes of random garbage plus the one byte fresh from fd, placed somewhere in c.
And then you try to get sense out of that combination.
Things might work much better if you define c as char:
char c;

Is there a way to mmap a stdin?

I have a following problem:
My job is to write a program that takes unsigned integer numbers that are passed to it through stdin and print out only the numbers that have more than 2 bits set to one. How should I do it efficiently? I did a version of a program where I read the numbers from a file using mmap, and it's quite quick. I read it like a very big *char buffer and using strtol I 'scrub' out each number and do my check and whatnot.
Is there a way to operate on a string passed through stdin the same way? I though about buffering using fread, but there is a problem, where the buffer cuts off the number (meaning if i pass "1024 35" and I have a 6 byte buffer I will get "1024 3"), and I shudder to think how to get around that.
Source:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h> /* mmap() is defined in this header */
#include <fcntl.h>
#include<string.h>
#include"apue.h"
int main (int argc, char *argv[])
{
int fdin, fdout;
char *src, *dst;
struct stat statbuf;
/* open the input file */
if ((fdin = open (argv[1], O_RDONLY)) < 0)
{printf("can't open %s for reading", argv[1]);return 1;}
/* find size of input file */
if (fstat (fdin,&statbuf) < 0)
{printf("fstat error");return 1;}
/* mmap the input file */
if ((src = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0))
== (caddr_t) -1)
{printf("mmap error for input");return 1;}
char* beg=src;
long x;
char* end=&src[statbuf.st_size-1];
while(src<end)
{
beg=src;
x = strtol (src,&src,10);
if(!((x != 0) && ((x & (~x + 1)) == x)))
fwrite(beg, 1, (int)(src-beg), stdout);
}
return 0;
}
http://pastebin.com/EVhG3x79
I think the expected solution is how to count the ones and not how to read from stdin.
int count_ones(int n);
means the question is how to implement the count_ones efficiently.
and your main just should look like this:
int main()
{
int x;
cin>>x;
if( count_ones(x)>2){
cout<<x<<endl;
}
return 0;
}
I think the expected answer is:
use array size 256
for each byte(=unsigned char) put in the array in its place the count of ones (can be: from 0 to 8)
split each number to its bytes and sum the ones on each of the bytes.
return the result

Writing struct to mapped memory file (mmap)

I have a problem to write struct into a mapped memory file.
I have two file namely mmap.write.c and mmap.read.c, and in these files, I'm writing an integer to a file and reading it from file.
When I want to write struct and read it, I could not think about that since in line 32 of mmap.write.c
sprintf((char*) file_memory, "%d\n", i);
and in line 25 of mmap.read.c
sscanf (file_memory, "%d", &integer);
There is no difference to write and read integer/double/float/char etc. since I can put pattern as second argument "%d" for integer. But what I will write here to indicate struct? That is my main problem.
The struct that I want to write and read:
#define CHANNELS 20
typedef dataholder struct {
int value[CHANNELS];
time_t time;
int hash;
}dataholder;
mmap.read.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
int main (int argc, char* const argv[])
{
int fd;
void* file_memory;
int integer;
/* Open the file. */
fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
printf("file opened\n");
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("memfile opened\n");
close (fd);
printf("file closed\n");
/* Read the integer, print it out, and double it. */
while(1) {
sscanf (file_memory, "%d", &integer);
printf ("value: %d\n", integer);
usleep(100000);
}
//sprintf ((char*) file_memory, "%d\n", 2 * integer);
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
mmap.write.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
int fd, i;
void* file_memory;
/* Seed the random number generator. */
srand (time (NULL));
/* Prepare a file large enough to hold an unsigned integer. */
fd = open (argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
//lseek (fd, FILE_LENGTH+1, SEEK_SET);
write (fd, "", 1);
//lseek (fd, 0, SEEK_SET);
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
close (fd);
/* Write a random integer to memory-mapped area. */
for(i=0; i<10000; i++) {
sprintf((char*) file_memory, "%d\n", i);
//goto a;
usleep(100000);
}
a:
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
Thanks a lot in advance.
First of all you have to keep track of where in the memory you want to write, second you have to remember that the mapped memory is just like any other pointer to memory. The last bit is important, as this means you can use normal array indexing to access the memory, or use functions such as memcpy to copy into the memory.
To write a structure, you have three choices:
Write the structure as-is, like in a binary file. This will mean you have to memcpy the structure to a specified position.
Write the structure, field-by-field, as text using e.g. sprintf to the correct position.
Treat the memory as one large string, and do e.g. sprintf of each field into a temporary buffer, then strcat to add it to the memory.
The simplest way is to just use a pointer:
dataholder *dh = file_memory;
/* now you can access dh->value, dh->time, dh->hash */
Since this struct doesn't contain any pointers, if you need to copy it in or out, you can just assign it, like:
dataholder dh_other = *dh;
or
*dh = dh_other;

Resources