C - Two processes reading the same file - c

I have a function that reads a file and returns an integer. There are two processes that use this same function and I am getting a segmentation fault.
Read function:
int getNumberFromFile() {
FILE* fp;
char* line;
fp = fopen(fileName, "rb");
fgets (line, 10, fp);
fclose(fp);
return atoi(line);
}
function Usage:
pid_t pid = fork();
if (pid == 0) {
struct process p1;
p1.processId = getpid();
printf("N: %d, PID: %d", getNumberFromFile(), p1.processId);
}
else if (pid > 0 ) {
struct process p2;
p2.processId = getpid();
printf("N: %d, PID: %d", getNumberFromFile(), p2.processId);
}
else {
printf("Error: Could not create process\n");
}
Is it not possible for two different processes to read the same file at the same time? If not how would I give one process the precedence so that other function can perform the read function afterwards?

Your issue has nothing to do with threads.
char* line;
fgets (line, 10, fp);
You are writing to uninitialized memory.

You need to allocate some storage behind the "line" pointer. Just change the declaration to char line[10].
Ps. There are no problems reading a file from multiple processes.

Your problem will occur whether you have one or two processes using the function; the function is faulty. You've not allocated any space to read the line into:
int getNumberFromFile()
{
FILE* fp;
char* line; // Uninitialized pointer
fp = fopen(fileName, "rb"); // Unchecked - errors possible
fgets(line, 10, fp); // Unchecked - and bad news if fopen() failed
fclose(fp); // Bad news if fopen() failed
return atoi(line);
}
You seem to want:
int getNumberFromFile(const char *fileName)
{
FILE *fp = fopen(fileName, "rb");
int rv = 0;
if (fp != 0)
{
char line[10];
if (fgets(line, sizeof(line), fp) != 0)
rv = atoi(line);
fclose(fp);
}
return rv;
}
This doesn't use uninitialized variables or null pointers, both of which can cause crashes.

Related

How to read until EOF from STDOUT in C?

#1: I do not know the size of output produced by stdout, given a command.
#2: I don't want to use char array like
char buffer[1024];
as it will result in memory shortage or wastage.
#3: If I use character pointer like
char *buffer;
I will have to allocate allocate memory for it like
buffer = (char *)malloc(1024 * sizeof(char));
#4: If I use getc() within while loop like
char *buf, c;
int i=0, j=1;
int pipefd[2];
int stdout_bk;
code[message_read] = '\0';
stdout_bk = dup(fileno(stdout));
pipe(pipefd);
dup2(pipefd[1], STDOUT_FILENO);
system(code);
close(pipefd[1]);
dup2(stdout_bk, STDOUT_FILENO);
buf = (char*)malloc(sizeof(char));
while(c!=End_Of_File) // What should I replace End_Of_File with?
{
c = getc(pipefd[0]);
buf = (char*)realloc(buf, j * sizeof(char));
buf[i] = c;
i++;
j++;
}
I do not know what is the End_Of_file for the stdout data.
P.S.: the program runs a command, e.g., system("setarch x86_64 -R dd if=/proc/self/maps | grep bin/dd") or system("ls -al") and I need to get the STDOUT. For that I have used dup2 and need to pipe the output to a buffer.
NOTE: the output can be of variable length.
There are many issues with your code:
c must be defined with type int
getc() cannot take a system handle as an argument, you must wrap that in a FILE* with fdopen().
End_Of_File for data returned by getc() is simply EOF and c must have type int for end of file testing to be reliable.
reallocating the array one byte at a time is inefficient and might be more wasteful than reallocating by chunks
more importantly you might want to allocate one extra byte for a null terminator if you intend to use this buffer as a C string.
the output of the system() command will be limited to the size of the system pipe buffers, usually around 5KB, so your program will get stuck for any larger output.
it is much simpler to use popen() for your purpose.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
int main() {
char code[] = "ls -lR";
char *buf = NULL;
int c;
int i = 0;
FILE *fp;
fp = popen(code, "r");
if (fp == NULL) {
fprintf(stderr, "popen error\n");
return 1;
}
while ((c = getc(fp)) != EOF) {
buf = (char *)realloc(buf, i + 2);
if (buf == NULL) {
fprintf(stderr, "out of memory\n");
pclose(fp);
return 1;
}
buf[i++] = (char)c;
}
pclose(fp);
printf("output: %d bytes\n", i);
if (buf != NULL) {
buf[i] = '\0';
fputs(buf, stdout);
}
free(buf);
return 0;
}

Why does this fread segfault

I have tried many things to fix this segfault issue, I'm not sure whats happening wrong because from my understanding, the fread line should not segfault
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Usage: ./recover file");
return 1;
}
char* recover = argv[1];
// open input file
FILE * raw_file = fopen(recover, "r");
if (raw_file == NULL)
{
fprintf(stderr, "Could not open %s.\n", recover);
return 2;
}
//somehow read the file
int counter = 1;
char file[2];
sprintf(file,"%03i.jpg",counter);
int buffer[512];
//read file and put into buffer
int*bf = malloc(sizeof(int));
fread(bf, sizeof(int), 1, raw_file);
you smashed you stack in this block prior to your fread
char file[2];
sprintf(file,"%03i.jpg",counter);
file is to small to hold the number of characters you are formatting into it.

Pass stream by reference

I am suppose to pass stream, which is a pointer, by reference. So I am passing this as a pointer to a pointer. Can someone please verify my code?
int main(int argc, char** argv)
{
FILE *stream;
printf("LINES: %d\n",scan(stream));
}
int scan(FILE *(*stream))
{
stream = fopen("names.txt", "r");
int ch = 0, lines=0;
while (!feof(*stream))
{
ch = fgetc(*stream);
if (ch == '\n')
{
lines++;
}
}
fclose(*stream);
return lines;
}
No output received.
Your code has design issues. What exactly do you want to achieve?
If you just want to count the lines, make the FILE * local to your function:
int count_lines(const char *filename)
{
FILE *stream = fopen(filename, "r");
int lines = 0;
while (1) {
int c = fgetc(stream);
if (c == EOF) break;
if (c == '\n') lines++;
}
fclose(stream);
return lines;
}
If you want to do a regular file operation (read, write, seek, rewind etc.) to a file that has already been opened with fopen, just pass the handle as FILE *:
int fget_non_space(FILE *stream)
{
int c;
do {
c = fgetc(stream);
} while (isspace(c));
return c;
}
In that case, both fopen and fclose are called outside this function. (You don't call fclose in your program, which you should, even if the operating system makes sure to close the file automatically after exiting.)
Passing a pointer to the file handle, FILE **, makes sense only if you want to change that file handle itself in the function, for example by calling fopen:
int fopen_to_read(FILE **FILE pstream, const char *fn)
{
*pstream = fopen(fn, "r");
return (*pstream != NULL) ? 0 : -1;
}
Even then, it would be better to return the file handle, as fopen does.
Your example code leaves the open filehandle accessible in main, but you don't do anything with it, you don't even close it. Is that what you want? I doubt it.
Use
int scan(FILE **stream) //no need for brackets
{
*stream = fopen("names.txt", "r"); //* is for dereferencing
if(*stream==NULL) // Checking the return value of fopen
{
printf("An error occured when opening 'names.txt'");
return -1;
}
int ch = 0, lines=0;
while ((ch = fgetc(*stream))!=EOF) //while(!feof) is wrong
{
if (ch == '\n')
{
lines++;
}
}
fclose(*stream); // Close the FILE stream after use
return lines;
}
int main(void)
{
FILE *stream;
printf("LINES: %d\n",scan(&stream)); //Pass address of `stream`. The address is of type `FILE**`
}
Replace
stream = fopen("names.txt", "r");
with
*stream = fopen("names.txt", "r");
Also
printf("LINES: %d\n",scan(stream));
with
printf("LINES: %d\n",scan(&stream));

How do I use a text file passed in as an argument from the command line in C?

I am having the hardest time trying to figure out how to use a text file that is passed in as a command line argument. I simply dont know to get the file text into my program to be used. My code looks something like this....
char buffer[80];
int i;
int lineCount = 0;
fgets(buffer, 80, stdin); //get the first line
while (buffer != NULL) {
// do some stuff
}//end fgets while
This is for a homework assignment and I know my teacher is going to run the program with the following command:
username#mylunixbox$ ./a.out <data1> output1
data1 is the text file I am trying to use.
Use argv[1]. That will give you the file name, then you can use fopen() and use file operations to read the contents from the file.
int main(int argc, char **argv)
{
int rc = EXIT_SUCCESS;
for (int i = 1; i < argc; i++)
{
FILE *fp = fopen(argv[i], "r");
if (fp == 0)
{
fprintf(stderr, "%s: failed to open file %s for reading\n",
argv[0], argv[i]);
rc = EXIT_FAILURE;
}
else
{
char line[4096];
while (fgets(line, sizeof(line), fp) != 0)
...do stuff with the line read from the file...
fclose(fp);
}
}
return rc;
}

Why wont the program read from the 2 argument file?

So the assignment is to implement a substring search program using an input file to be searched from and an input to be searched. I created the following code:
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
FILE *fp;
fp = fopen(argv[1],"r");
if (fp == NULL)
{
printf("Error");
return 0;
}
char* tmpp[100];
int count = 0;
char* nexts = argv[2];
char* tmp = fgets(tmpp,100,fp);
while(tmp = strstr(tmp,nexts))
{
count++;
tmp++;
}
printf("%d\n\n",count);
fclose(fp);
return 0;
}
The program compiles but when i go to implement it in the ubuntu terminal as:
echo "aabb" >beta
./a.out beta a
1
Why isnt the program using the first argument (argv[1]) as beta and the second argument (argv[2]) as a correctly?
You should open a file and then read bytes from that file into temporary buffer:
FILE *file = fopen("file", "r");
while (1) {
char buffer[BUFSIZ+1];
size_t nread = fread(buffer, 1, sizeof(buffer)-1, file);
if (nread == 0) break; // read error or EOF
buffer[nread] = 0;
// chunk with BUFSIZ amount of bytes is available via buffer (and is zero-terminated)
}
If you want to search for string/pattern in a file, be aware that looked pattern in file may cross your chunk-size boundary, for example: you look for "hello", and BUFSIZ is 512. File contains "hello" at byte 510. Obviously, if you read by 512, you will get the first chunk ending with "he", and the second chunk starting with "llo". Probability of this situation is nonzero for all chunk sizes (except SIZE_MAX, but that buffer size is impossible by other reasons). Dealing with borders may be very complicated.
Close...but this is closer:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s file pattern\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (fp == NULL)
{
fprintf(stderr, "Error: failed to open file %s for reading\n", argv[1]);
return 1;
}
char tmpp[1000];
int count = 0;
char* nexts = argv[2];
while (fgets(tmpp, sizeof(tmpp), fp) != 0)
{
char *tmp = tmpp;
while ((tmp = strstr(tmp, nexts)) != 0)
{
count++;
tmp++;
}
}
printf("%d\n", count);
fclose(fp);
return 0;
}
The main difference is that this loops reading multiple lines from the input file. Yours would only work on files with a single line of input.

Resources