When I'm trying to write to one of my pipes to communicate with a child process, it gets stuck. My first guess was that it was because its buffer was full, and something has to read from it, for it to continue, so I followed Increasing the maximum pipe size in linux instructions, and to my surprise, my maximum buffer size is 1048576. I'm trying to write 160000 bytes into my pipe. I don't understand why it's getting stuck.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <math.h>
#define SIZE 320000
#define FILENAME "Practical_Q_1numbers.txt"
extern long fun(long a, long b);
void write_numbers(int process_id,int* pipefds, long* numbers) {
long process_numbers[SIZE / 8];
memcpy(process_numbers, &numbers[SIZE / 8 * process_id], SIZE / 8 * sizeof(long));
printf("This gets printed\n");
// Pipe Limit
write(pipefds[1], process_numbers, SIZE / 8 * sizeof(long));
printf("This doesnt\n");
}
// Correct
long calculate(long* numbers, int left, int right) {
if(left == right){
return numbers[left];
}else if(left + 1 == right) {
return fun(numbers[left], numbers[right]);
}
int middle = (right + left) / 2;
long l_ans = calculate(numbers, left, middle);
long r_ans = calculate(numbers, middle + 1, right);
return fun(l_ans, r_ans);
}
void calculateHelper(int id, int* pipefds) {
long* ptr = (long*)malloc(SIZE / 8 * sizeof(long));
read(pipefds[0], ptr, SIZE / 8 * sizeof(long));
long res = calculate(ptr, 0, SIZE / 8 - 1);
// write(pipefds[1], &res, sizeof(res));
return;
}
int main() {
// Read the file as parent.
FILE *myFile;
myFile = fopen(FILENAME, "r");
long* ptr = (long*)malloc(SIZE * sizeof(long));
// Reads correctly
for(int i = 0; i < SIZE; i++) {
fscanf(myFile, "%ld", &ptr[i]);
}
int pipefds[8][2];
for(int i = 0; i < 8; i++) {
pipe(pipefds[i]);
}
for(int i = 0; i < 1; i++) {
write_numbers(i,pipefds[i], ptr);
pid_t a = fork();
if(a == 0) {
// Child process
calculateHelper(i,pipefds[i]);
exit(0);
}
}
// Wait for your children to terminate
while(wait(NULL) > 0);
// long* finalContenders = (long*) malloc(8 * sizeof(long));
// for(int i = 0; i < 8; i++) {
// read(pipefds[i][0], &finalContenders[i], sizeof(long));
// }
// long ans = calculate(finalContenders, 0, 7);
// printf("%ld\n",ans);
}
Fun is a function responsible for calculating the GCD of 2 numbers.
Your problem is here:
for(int i = 0; i < 1; i++) {
write_numbers(i,pipefds[i], ptr);
pid_t a = fork();
if(a == 0) {
// Child process
calculateHelper(i,pipefds[i]);
exit(0);
}
You write the data to the pipe before there's a process to read from it. That's deadlock-prone no matter how large the maximum pipe buffer size might be.
This would be better:
for(int i = 0; i < 1; i++) {
pid_t a = fork();
if(a == -1) {
// handle error
}
else if(a == 0) {
// Child process
calculateHelper(i,pipefds[i]);
exit(0);
}
else {
write_numbers(i,pipefds[i], ptr);
}
You'd also be better off writing smaller chunks to the pipe no matter what. Right now, you don't handle partial write() results at all (bolding mine):
The write() function shall attempt to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes.
There's no portable guarantee on any call to write() that the entirety of your requested buffer will be written.
The easiest way to do that is to create a writeAllBytes() wrapper around write, such as:
#define CHUNK_SIZE ( 4 * 1024 )
ssize_t writeAllBytes( int fd, void *data, size_t bytes )
{
// need to do pointer arithmetic on the value so
// it can't be a void *
char *buf = data;
ssize_t totalWritten = -1;
while ( bytes > 0 )
{
size_t bytesToWrite = bytes;
if ( bytesToWrite > CHUNK_SIZE )
{
bytesToWrite = CHUNK_SIZE;
}
ssize_t bytesWritten = write( fd, buf, bytesToWrite );
if ( bytesWritten <= 0 )
{
break;
}
buf += bytesWritten;
totalWritten += bytesWritten;
bytes -= bytesWritten;
}
return( totalWritten );
}
Similarly, a corresponding readAllBytes() would also be appropriate.
Related
I can't seem to make partial write() work. It goes out of the memory and I don't know why.
int fd = open(path, O_RDONLY);
if(fd == -1) {error handling}
const size_t read_size = 100;
size_t size = read_size;
size_t offset = 0;
size_t res = 0;
char *buff = malloc(size+1);
int lines = 0;
int pos = 0;
while((res = read(fd, buff + offset, read_size)) > 0)
{
if(res == -1){error handling}
offset += res;
buff[offset] = '\0';
if (offset + read_size > size)
{
size *= 2;
buff = realloc(buff, size+1);
}
}
for(size_t i = 0;buff[i] != '\0'; i++) // counting the buff lines
{
if(buff[i] == '\n')
{
lines++;
}
}
size = read_size;
offset = 0;
res = 0;
if(lines < 10)
{
while((res = write(STDOUT_FILENO, buff+offset, read_size)) > 0)
{
offset += res;
}
}
buff[offset] = '\0';
else{another case where the position is found where the write() needs to start printing}
This is a part of a tail implementation in c. There is also another function which handles stdin and does the same thing (this one handles files).
This is what it might look like:
// Returns 0 on success.
// Returns -1 and sets errno on error.
int write_full(int fd, void *a_buf, size_t count) {
const char *buf = (char *)a_buf;
while ( count > 0 ) {
ssize_t chunk_size = write(fd, buf, count);
if ( chunk_size < 0 )
return -1;
buf += chunk_size;
count -= chunk_size;
}
return 0;
}
Testing is tricky. I've only been able to generate a partial write when using a non-blocking handle writing to a pipe with a blocked consumer.
But that results in error EAGAIN or EWOULDBLOCK so if we temporarily add code to immediately try again (which would be bad to do in practice), we can see the partial writes working.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Returns 0 on success.
// Returns -1 and sets errno on error.
int write_full(int fd, void *a_buf, size_t count) {
const char *buf = (char *)a_buf;
while ( count > 0 ) {
ssize_t chunk_size = write(fd, buf, count);
if ( chunk_size < 0 && ( errno == EAGAIN || errno == EWOULDBLOCK ) ) continue; // DEBUG
if ( chunk_size < 0 )
return -1;
fprintf(stderr, "Wrote %zd\n", chunk_size); // DEBUG
buf += chunk_size;
count -= chunk_size;
}
return 0;
}
int main(void) {
int fd = STDOUT_FILENO;
fcntl(fd, F_SETFL, O_NONBLOCK); // Make non-blocking
const size_t n = 100000;
char *buf = malloc(n);
if (!buf) {
perror("Can't allocate memory");
exit(1);
}
for (size_t i=n; i--; )
buf[i] = 'x';
if ( write_full(fd, buf, n) < 0 ) {
perror("Write error");
exit(1);
}
free(buf);
return 0;
}
$ gcc -Wall -Wextra -pedantic a.c -o a && ./a | perl -e'print while <>' >/dev/null
Wrote 65536
Wrote 8192
Wrote 8192
Wrote 16384
Wrote 1696
Perl takes longer to load than the C program allowing the 64 KiB pipe buffer to fill up. You can ensure this bad adding sleep 2; to the start of the Perl program.
Perl reads in 8 KiB chunks, and it takes longer to do so than it takes for the C program to write, so the C program is constantly running out of space in the pipe buffer.
im trying to run this on Linux, this program supposed to pass arrays of numbers with pipes, to the children, and each children calculate the gcd of the pairs. But I get "Segmentation fault(core dumped)" ERROR. I've checked the child's process, and right after the read() i tried to print string just for check and it doesn't work. The weird thing that the read not returns -1, which means it worked. is it possible to write char **arr; into a pipe? or is it to big for a pipe and this is why it crashes.
Thank you for any help.
BTW, the ./v2_child1 is fine, the problem comes before the execvp()
#include <stdarg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 100
#define FILE_NAME "numbers.txt"
char** readFromTextFile(char *fileName) {
FILE *f = fopen(fileName, "r");
if (f == NULL) {
printf("Error while opening file!");
return NULL;
}
char *line = (char*) malloc(MAX_LINE_LENGTH * sizeof(char));
char **pairs = (char**) malloc(50 * sizeof(char*));
int counter = 0;
while (!feof(f)) {
char *num1 = (char*) malloc(sizeof(char) * 2);
char *num2 = (char*) malloc(sizeof(char) * 2);
fgets(line, MAX_LINE_LENGTH, f);
sscanf(line, "%s %s", num1, num2);
pairs[counter] = num1;
pairs[counter + 1] = num2;
counter += 2;
}
pairs[counter] = NULL;
fclose(f);
return pairs;
}
int numOfPairs(char **arr) {
int count = 0;
while (arr[count] != NULL) {
count += 1;
}
if ((count % 2) != 0) {
printf("odd amount off numbers");
return -1;
} else {
return count / 2;
}
}
int main(int argc, char *argv[]) {
//read the pairs of numbers into array
char **numbers = readFromTextFile(FILE_NAME);
//returns the num of pairs to check
int num_pairs = numOfPairs(numbers);
//initialize the pipes
int write_pipe[2], read_pipe[2];
if (pipe(write_pipe) == -1 || pipe(read_pipe) == -1) {
fprintf(stderr, "Pipe operation failed!");
exit(0);
}
//child --> parent
int PARENT_READ = read_pipe[0]; // IN
int CHILD_WRITE = read_pipe[1]; // OUT
//parent --> child
int CHILD_READ = write_pipe[0];
int PARENT_WRITE = write_pipe[1];
pid_t status = fork(); // create child number 1
if (status < 0) { // error ocurred
fprintf(stderr, "Error with fork");
exit(0);
} else if (status > 0) { // parent go here
char **to_child1 = (char**) malloc(sizeof(char*) * (num_pairs / 2) * 2);
for (int i = 0; i < num_pairs / 2; ++i) {
to_child1[2 * i] = numbers[2 * i];
to_child1[2 * i + 1] = numbers[2 * i + 1];
}
if (close(CHILD_READ) == -1)
perror("problem while close CHILD_READ");
if (write(PARENT_WRITE, to_child1, sizeof(char*) * (num_pairs / 2) * 2)
== -1)
perror("problem while write to PARENT_WRITE");
if (close(PARENT_WRITE))
perror("problem while close PARENT_WRITE");
printf("wrote from parent to pipe\n\n");
} else { // child process
char **first_half = (char**) malloc(
sizeof(char*) * (num_pairs / 2) * 2);
printf("Hello form son 1\n");
if (close(PARENT_WRITE) == -1)
perror("Error while close");
read(CHILD_READ, first_half, sizeof(char*) * (num_pairs / 2) * 2);
printf("child got here"); // not printing this*
if (close(PARENT_READ) == -1) //read is unused
perror("Error while close");
if (dup2(CHILD_WRITE, STDOUT_FILENO) == -1) { //redirecting Stdout to pipe.
perror("dup2 error");
}
char *args[num_pairs / 2 + 1];
args[0] = "./v2_child1";
for (int i = 1; i < num_pairs / 2 + 1; ++i) {
args[i] = first_half[i];
}
execvp(args[0], args);
}
wait(NULL);
char **gcds = (char**) malloc(sizeof(char*) * (num_pairs / 2));
close(CHILD_WRITE);
read(PARENT_READ, gcds, sizeof(int));
for (int i = 0; i < num_pairs / 2; ++i) {
printf("The gcd of %d and %d is: %d - calculated from child 1\n",
atoi(numbers[i * 2]), atoi(numbers[i * 2 + 1]), atoi(gcds[i]));
}
/// another child to be created
}
to_child1 is an array of pointers. Pointer values are only meaningful within the process that created them. Writing a pointer into the pipe does not copy the data that it points to. So when the child process reads the pointers, it doesn't have the strings they point to.
Since all the strings are just 1 character, there's no need to use an array of pointers, just make an array of char, and write that to the pipe.
The problem I'm running into is that when the file tries to copy, it only copies part of the file and the other part is a bunch of unreadable characters. This is for an academic assignment that wants us to use barrier synchronization so we need to use open, write, and read.
I've reworked the thread function many times but if it's the problem I can change it again, I haven't changed the for loop in main at all so even that might be the problem but I don't know what it could be. Lastly, I don't really know what to do with the barrier; my professor was very vague and I can't really ask him questions, maybe the barrier is the part that I'm truly missing.
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
typedef struct args {
int fd;
int copy;
long int start;
long int size;
}threadarg;
int barrier = 0;
int main(int argc, char *argv[])
{
void usage(char *progname);
int chkdst(char **argv);
void die(char *why);
long int filesize(char *srcpath);
void buildpath(char *src, char *dst, char **dstpath);
int isvalid(char *path, char *dst);
void *dowork(void *arg);
if (argc < 4) usage("a8");
int workers, i;
char *check;
workers = strtol(argv[3], &check, 10);
if (!check) usage("a8");
else if (!chkdst(&argv[2])) die ("DST not valid!");
long int size = filesize(argv[1]);
if (size == -1) die ("Could not find file size");
char *dstpath; buildpath(argv[1], argv[2], &dstpath);
if (!isvalid(argv[1], dstpath)) die ("scr not valid!");
long int chunksize = size / workers;
long int remainder = size % workers;
int fd = open(argv[1], O_RDONLY);
int copy = open(dstpath, O_CREAT | O_RDWR, 0644);
if (fd < 0 || copy < 0) die("Fail to access or create files");
barrier = workers;
threadarg threadargs[workers];
pthread_t threads[workers];
for (i = 0; i < workers; i++)
{
threadargs[i].fd = fd;
threadargs[i].copy = copy;
threadargs[i].start = i * chunksize;
if (i == workers - 1)
threadargs[i].size = chunksize + remainder;
else
threadargs[i].size = chunksize;
if (pthread_create(&threads[i], NULL, dowork, (void *) &threadargs[i]))
die("Thread Creation Failure");
}
for (i = 0; i < workers; i++)
pthread_join(threads[i], NULL);
}
void usage(char *progname)
{
fprintf(stderr, "./%s srcpath dstpath workercount\n", progname);
exit(0);
}
void die(char *why)
{
fprintf(stderr, "Program Killed...\nReason: %s\n", why);
exit(1);
}
long int filesize(char *srcpath)
{
struct stat st;
if(stat(srcpath, &st) != 0) return 0;
return st.st_size;
}
/*
void domd5(char *path)
{
}
*/
void *dowork(void *arg)
{
threadarg *args = (threadarg *)arg;
int fd = args->fd,
copy = args->copy, rd;
long int start = args->start,
size = args->size;
char bufs[2048], *remains;
lseek(fd, start, SEEK_SET);
lseek(copy, start, SEEK_SET);
printf("%d thread with offset %ldKB, reached barrier\n", (int) pthread_self(), start);
barrier--;
while (barrier > 0);
long int count = 0, remainder = 0, i;
for (i = 0; i < size; i += 2048)
{
if (i + 2048 > size)
{
remainder = size - count;
remains = malloc(remainder * sizeof(char));
rd = read (fd, remains, sizeof(remains));
if (write(copy, remains, rd) != rd)
die("Error accessing files during copy");
count += remainder;
}
else
{
rd = read(fd, bufs, sizeof(bufs));
if (write(copy, bufs, rd) != rd)
die("Error accessing files during copy");
count += 2048;
}
}
pthread_exit(NULL);
}
/* Takes a single pointer, *argv, and passes it to isdir()
to check if the directory exists. If isdir returns a 1 a
1 is returned from this module. Otherwise, an error message
is printed and a 0 is returned.
Calls isdir().
Called by main().
*/
int chkdst(char **argv)
{
int isdir(char *path);
if (isdir(*argv)) return 1;
return 0;
}
/* Uses the Stat struct to construct a struct, sbuf,
and uses stat() to obtain information from the file and
write it to sbuf. Uses S_ISDIR() on sbuf.st_mode to see
the mode of the file. A 1 is returned if the file is a
directory otherwise a 0 is returned.
Called by isvalid().
*/
int isdir(char *path)
{
struct stat sbuf;
if (stat(path, &sbuf)) return 0;
return S_ISDIR(sbuf.st_mode);
}
/* Uses the Stat struct to construct a struct, sbuf,
and uses stat() to obtain information from the file and
write it to sbuf. Uses S_ISREG on sbuf.st_mode to see if
the file is regular. A 1 is returned if the S_ISREG is true
otherwise a 0 is returned.
Called by isvalid().
*/
int isregular(char *path)
{
struct stat sbuf;
if (stat(path, &sbuf)) return 0;
return S_ISREG(sbuf.st_mode);
}
/* Checks if the source path is a directory first, then if its
a regular file return 0 if it is dir and if it isn't a regular
file, then checks if the destionation path was created or if
the file exist at the destination if either return 0, if none
of these return 1.
Calls isdir() and isregular().
Called by copyfiles().
*/
int isvalid(char *path, char *dst)
{
if (isdir(path))
{
return 0;
}
else if (!isregular(path))
{
return 0;
}
else if (dst == NULL)
{
return 0;
}
else if (isregular(dst))
{
return 0;
}
return 1;
}
/* Builds destination-path using strrchr() function from library,
dstpath is null on error and defined otherwise. The src file has
its original destination removed and replaced with the new one if
it has a original destination on it otherwise it is just added to
the end of the existing name of the file.
Called by copyfiles().
*/
void buildpath(char *src, char *dst, char **dstpath)
{
char *ptr;
int n;
ptr = strrchr(src, '/');
if (ptr) n = strlen(dst) + strlen(ptr) + 2;
else n = strlen(dst) + strlen(src) + 2;
*dstpath = malloc(n);
if (!dstpath) return;
if (ptr)
{
strcpy(*dstpath, dst);
strcat(*dstpath, ptr);
}
else
{
strcpy(*dstpath, dst);
strcat(*dstpath, "/");
strcat(*dstpath, src);
}
}
I am trying to read a file with aio.h byte by byte using aio_read with a number of threads. But I don't know if I am on the right track since there are not so many stuff to read on the Internet.
I have just created a worker function to pass it to my threads. And also as an argument to pass to the thread, I created a struct called thread_arguments and I pass a few necessary arguments in it, which will be needed for aiocb such as offset, file_path to open, buffer size, and priority.
I can read a file with one thread from start to end successfully. But when it comes to reading a file as chunks from within a few threads, I couldn't make it. And I am not even sure if I can do that with aio->reqprio without using semaphores or mutexes. (Trying to open a file from within a few threads at the same time?)
How can I read a few number of bytes from within a few threads asynchronously?
Let's say the file contains "foobarquax" and we have three threads using aio library.
Then first one should read "foo",
the second should read "bar" and
the last one should read "quax" asynchronously.
You can see screenshots of issues regarding running it with multiple threads on here
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <aio.h>
#include <string.h>
#include <fcntl.h> // open -> file descriptor O_RDONLY, O_WRONLY, O_RDWR
#include <errno.h>
#include <unistd.h>
typedef struct thread_args {
char *source_path;
char *destination_path;
long int buffer_size;
long int buffer_size_last; // buffer size for the last thread in case there is a remainder.
long int offset;
int priority;
} t_args;
void *worker(void *thread_args) {
t_args *arguments = (t_args *) thread_args;
struct aiocb *aiocbRead;
aiocbRead = calloc(1, sizeof(struct aiocb));
aiocbRead->aio_fildes = open(arguments->source_path, O_RDONLY);
if (aiocbRead->aio_fildes == -1) {
printf("Error");
}
printf("opened on descriptor %d\n", aiocbRead->aio_fildes);
aiocbRead->aio_buf = malloc(sizeof(arguments->buffer_size));
aiocbRead->aio_offset = arguments->offset;
aiocbRead->aio_nbytes = (size_t) arguments->buffer_size;
aiocbRead->aio_reqprio = arguments->priority;
int s = aio_read(aiocbRead);
if (s == -1) {
printf("There was an error");
}
while (aio_error(aiocbRead) == EINPROGRESS) {}
printf("Bytes read %ld", aio_return(aiocbRead));
close(aiocbRead->aio_fildes);
for (int i = 0; i < arguments->buffer_size ; ++i) {
printf("%c\n", (*((char *) aiocbRead->aio_buf + i)));
}
}
// Returns a random alphabetic character
char getrandomChar() {
int letterTypeFlag = (rand() % 2);
if (letterTypeFlag)
return (char) ('a' + (rand() % 26));
else
return (char) ('A' + (rand() % 26));
}
void createRandomFile(char *source, int numberofBytes) {
FILE *fp = fopen(source, "w");
for (int i = 0; i < numberofBytes; i++) {
fprintf(fp, "%c", getrandomChar());
}
fclose(fp);
}
int main(int argc, char *argv[]) {
char *source_path = argv[1];
char *destination_path = argv[2];
long int nthreads = strtol(argv[3], NULL, 10);
// Set the seed.
srand(time(NULL));
// Get random number of bytes to write to create the random file.
int numberofBytes = 10 + (rand() % 100000001);
// Create a random filled file at the source path.
createRandomFile(source_path, 100);
// Calculate the payload for each thread.
long int payload = 100 / nthreads;
long int payloadLast = payload + 100 % nthreads;
// Create a thread argument to pass to pthread.
t_args *thread_arguments = (t_args *) malloc(nthreads * sizeof(t_args));
for (int l = 0; l < nthreads; ++l) {
// Set arguments in the struct.
(&thread_arguments)[l]->source_path = source_path;
(&thread_arguments)[l]->destination_path = destination_path;
(&thread_arguments)[l]->buffer_size = payload;
(&thread_arguments)[l]->buffer_size_last = payloadLast;
(&thread_arguments)[l]->offset = l * payload;
(&thread_arguments)[l]->priority = l;
}
pthread_t tID[nthreads];
// Create pthreads.
for (int i = 0; i < nthreads; ++i) {
pthread_create(&tID[i], NULL, worker, (void *) &thread_arguments[i]);
}
// Wait for pthreads to be done.
for (int j = 0; j < nthreads; ++j) {
pthread_join(tID[j], NULL);
}
free(thread_arguments);
return 0;
}
This code is reading succesfully if I just call it from one thread but doesn't work if I use it for more than one threads which is what I want.
I am trying to print a partition table using C programming language, everything seems to work fine: Opening and reading, but I don't understand why it is printing garbage values.
Here is the code:
struct partition
{
unsigned char drive;
unsigned char chs_begin[3];
unsigned char sys_type;
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
int main()
{
int gc = 0, i = 1, nr = 0, pos = -1, nw = 0;
int fd =0;
char buf[512] ;
struct partition *sp;
printf("Ok ");
if ( (fd = open("/dev/sda", O_RDONLY | O_SYNC )) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d \n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
close(fd);
printf("Size of buf = %d\n and number of bytes read are %d ", sizeof(buf), nr);
if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n %d bytes are just been written on stdout\n", nw,"this can also be printed\n");
printf("\n\t\t*************Partition Table****************\n\n");
for (i=0 ; i<4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
putchar(sp -> drive);
}
return 0;
}
It is printing garbage instead of partition table.
I might have some basic understanding issues but I searched with Google for a long time but it did not really help. I also saw the source code of fdisk but it is beyond my understanding at this point. Could anyone please guide me? I am not expecting someone to clear my mistake and give me the working code. Just a sentence or two - or any link.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct partition
{
unsigned char boot_flag; /* 0 = Not active, 0x80 = Active */
unsigned char chs_begin[3];
unsigned char sys_type; /* For example : 82 --> Linux swap, 83 --> Linux native partition, ... */
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
void string_in_hex(void *in_string, int in_string_size);
void dump_partition(struct partition *part, int partition_number);
void dump_partition(struct partition *part, int partition_number)
{
printf("Partition /dev/sda%d\n", partition_number + 1);
printf("boot_flag = %02X\n", part->boot_flag);
printf("chs_begin = ");
string_in_hex(part->chs_begin, 3);
printf("sys_type = %02X\n", part->sys_type);
printf("chs_end = ");
string_in_hex(part->chs_end, 3);
printf("start_sector = ");
string_in_hex(part->start_sector, 4);
printf("nr_sector = ");
string_in_hex(part->nr_sector, 4);
}
void string_in_hex(void *in_string, int in_string_size)
{
int i;
int k = 0;
for (i = 0; i < in_string_size; i++)
{
printf("%02x ", ((char *)in_string)[i]& 0xFF);
k = k + 1;
if (k == 16)
{
printf("\n");
k = 0;
}
}
printf("\n");
}
int main(int argc, char **argv)
{
int /*gc = 0,*/ i = 1, nr = 0, pos = -1/*, nw = 0*/;
int fd = 0;
char buf[512] ;
struct partition *sp;
int ret = 0;
printf("Ok ");
if ((fd = open("/dev/sda", O_RDONLY | O_SYNC)) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d\n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
ret = close(fd);
if (ret == -1)
{
perror("close");
exit(1);
}
/* Dump the MBR buffer, you can compare it on your system with the output of the command:
* hexdump -n 512 -C /dev/sda
*/
string_in_hex(buf, 512);
printf("Size of buf = %d - and number of bytes read are %d\n", sizeof(buf), nr);
/*if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n%d bytes are just been written on stdout\nthis can also be printed\n", nw);
*/
//printf("\n\t\t*************Partition Table****************\n\n");
printf("\n\t\t*************THE 4 MAIN PARTITIONS****************\n\n");
/* Dump main partitions (4 partitions) */
/* Note : the 4 partitions you are trying to dump are not necessarily existing! */
for (i = 0 ; i < 4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
//putchar(sp->boot_flag);
dump_partition(sp, i);
}
return 0;
}