Why system call read() does not work when using user input - c

It`s a file copying program.
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
int main()
{
int fd1,fd2, ndata;
char data[128];
char *openname[1], *creatname[1];
write(1, "Write open file name\n", 24); //user input
read(0, openname, 30 );
write(1, "Write creat file name\n", 25); //user input
read(0, creatname,30);
if((fd1 = open(openname, 0666))<0)
{
perror("cannot open the file");
exit(1);
}
if((fd2 = creat(creatname,0666))<0)
{
perror("cannot create the file");
exit(1);
}
while((ndata = read(fd1, data, 128))>0)
{
if((write(fd2, data, ndata))!=ndata)
{
perror("cannot write the file");
exit(1);
}
}
close(fd1);
close(fd2);
write(1, "File copy is done.",19);
return 0;
}
This code ain`t work. This code print the error message:
cannot open the file.
but if i change the code to this :
if((fd1 = open("copy.c", 0666))<0)
and this :
if((fd2 = creat("real.c",0666))<0)
worked well.
Why this error happend? Please answer.

Your declarations of openname and creatname are incorrect. They should be:
char openname[31], creatname[31];
read() does not add a null terminator to the input, you need to add it. read() returns the number of bytes read. So it should be:
int nread = read(0, openname, sizeof openname -1);
openname[nread-1] = '\0'; // subtract 1 to overwrite the newline

The type of openname and creatname is wrong, and gcc -Wall -g would have warned you. Declare e.g. char openname[256];
And you should use fgets(openname, sizeof(openname), stdin); to read it.
If you insist on using read, take care of the newline (if any) and add a zero terminating byte.
Learn also to use the gdb debugger.

read is very low level. In this case, it reads 30 bytes, including your enter key and also without a terminating null-byte. So the filename won't be what you think you've entered, it will contain additional garbage (and could even make your program crash due to the missing null-termination). You want to use fgets or readline instead.

In a nutshell, by using read() to input the file names, you are making this unnecessarily hard for yourself: it does not terminate the input with NUL, is not guaranteed to read the number of characters you expect, etc.
My advice would be to stick with scanf() or fgets().

Related

How do I modify the stream from one file to another

I need to make a program that takes string data from one file and copy every third char from it to another file.
I am not sure if I am doing it right. The idea I got is to first create one array where I will store original data from file1 and then using 'for' loop I will modify the data and store in in the second array:
(eg for(i=0; i < arraysize; i+=3);
The thing is I dont have an idea how to transfer input to my array and how to do it backwards to have my modified data go to file2.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFER_SIZE 50
int main(int argc, char *argv[]) {
char buffer[BUFFER_SIZE];
char modified[BUFFER_SIZE];
int input_fd, output_fd;
ssize_t ret_in, ret_out;
if(argc !=3 || strcmp(argv[1], "--help") == 0)
{
printf("Usage: %s file_origin file_destination\n", argv[0]);
return 2;
}
input_fd = open(argv[1], O_RDONLY);
if(input_fd == -1)
{
perror("There is no such file");
return 2;
}
out_fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
if(output_fd == -1)
{
perror("create");
return 3;
}
Could someone please tell me how to use function read/write correctly to stream my data to array and how to do it the other way.
Welcome to Stackoverflow!
Given the exact description of your assignment, I would not use a buffer; you could simply read from the input file one byte at a time, and write every third byte to the output file. This avoids any buffer-management overhead.
But, if you do read from the input file into a buffer, you do not need to modify that buffer in any way, nor do you need a second buffer. After reading all the data, simply iterate through the input buffer, outputting every third byte to the output file.
But, if you want/need to reuse the output in some way, you can simply populate a second buffer from the input buffer in the same manner (loop over the input buffer, skipping two bytes each iteration), and then write that second buffer to the output file. (This way, you still have the same output in that second buffer, and you can reuse it in some manner.)
The approach you take will dictate the best functions to use. I see you already know about open(). Read up on read(), write() and close(), but also read up on fopen(), fgetc(), fgets(), fread(), fwrite() and fclose(). There is a lot for you to learn from reading about these various functions, how they are similar to each other, how they differ from each other, and the pros and cons of each. Reading about them will lead you to learn about other related file operations (like seeking, rewinding, etc.), which will serve you well as you learn more about C and programming in general.
Please note that for the approaches using buffers, you need to be very careful about the size of your buffers vs. the size of the input file. There are many pitfalls here. If this is an assignment for a class of some sort, then those considerations might show up in later lessons / assignments, and maybe it's too much to take on just now. But it's never too early to start thinking about what you do and don't know about the input your program will need to handle.
If you do not need cin or cout, I would suggest the following (I assumed strings are ended with newline and those should be preserved in the output and that counting the 3rd character starts anew in every line read):
FILE *f1=fopen("_infile.txt","rt");
FILE *f2=fopen("_outfuile.txt","wt");
char buffer[MAXBUFLEN];
while (!feof(f1)) {
if (fgets(buffer,MAXBUFLEN,f1)>0) {
for(int i=2;i<strlen(buffer);i+=3) {
fprintf(f2,"%c",buffer[i]);
}
fprintf(f2,"\n");
} else break;
}
fclose(f1);
fclose(f2);
This will read input file and reprint every third character to output. You can adapt it to you situation.
#include <stdio.h>
#include <stdlib.h>
int main()
{
size_t i; // index
int c; // char read
FILE *FIN, *FOUT; // file streams
if ((FIN = fopen("in.txt", "rb")) == NULL) {
printf("Error opening input file.\n Exiting.\n");
exit(1);
}
if ((FOUT = fopen("out.txt", "wb")) == NULL) {
printf("Error opening output file.\n Exiting.\n");
exit(1);
}
// read input and reprint every third character
for(i=0;;i++)
{
c = fgetc(FIN); // read byte
if(c == EOF)
{
break; // reached end of file (input), leave loop
}
if((i%3)==2) // get every third character by modulo(i)
{
fputc(c, FOUT); // write output
}
}
fclose(FIN);
fclose(FOUT);
return 0;
}

C - Print lines from file with getline()

I am trying to write a simple C program that loads a text-file, prints the first line to screen, waits for the user to press enter and then prints the next line, and so on.
As only argument it accepts a text-file that is loaded as a stream "database". I use the getline()-function for this, according to this example. It compiles fine, successfully loads the text-file, but the program never enters the while-loop and then exits.
#include <stdio.h>
#include <stdlib.h>
FILE *database = NULL; // input file
int main(int argc, char *argv[])
{
/* assuming the user obeyed syntax and gave input-file as first argument*/
char *input = argv[1];
/* Initializing input/database file */
database = fopen(input, "r");
if(database == NULL)
{
fprintf(stderr, "Something went wrong with reading the database/input file. Does it exist?\n");
exit(EXIT_FAILURE);
}
printf("INFO: database file %s loaded.\n", input);
/* Crucial part printing line after line */
char *line = NULL;
size_t len = 0;
ssize_t read;
while((read = getline(&line, &len, database)) != -1)
{
printf("INFO: Retrieved line of length %zu :\n", read);
printf("%s \n", line);
char confirm; // wait for user keystroke to proceed
scanf("%c", &confirm);
// no need to do anything with "confirm"
}
/* tidy up */
free(line);
fclose(database);
exit(EXIT_SUCCESS);
}
I tried it with fgets() -- I can also post that code --, but same thing there: it never enters the while-loop.
It might be something very obvious; I am new to programming.
I use the gcc-compiler on Kali Linux.
Change your scanf with fgetline using stdin as your file parameter.
You should step through this in a debugger, to make sure your claim that it never enters the while loop is correct.
If it truly never enters the while loop, it is necessarily because getline() has returned -1. Either the file is truly empty, or you have an error reading the file.
man getline says:
On success, getline() and getdelim() return the number of
characters
read, including the delimiter character, but not including the termi‐
nating null byte ('\0'). This value can be used to handle embedded
null bytes in the line read.
Both functions return -1 on failure to read a line (including end-of-
file condition). In the event of an error, errno is set to indicate
the cause.
Therefore, you should enhance your code to check for stream errors and deal with errno -- you should do this even when your code works, because EOF is not the only reason for the function
to return -1.
int len = getline(&line, &len, database);
if(len == -1 && ferror(database)) {
perror("Error reading database");
}
You can write more detailed code to deal with errno in more explicit ways.
Unfortunately handling this thoroughly can make your code a bit more verbose -- welcome to C!

Process returned -1 (0xFFFFFFFF)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)

How to read an integer and a char with read() function in C?

I'm working on linux, I have a file that contains a line like this:
328abc
I would like, in C, to read the integer part (328) and the characters 'a','b','c', using only the function:
ssize_t read (int filedes, void *buffer, size_t size))
This is the only thing the file contains.
I know there are better ways to do that with other functions, but I haven't coded in C for a long time, and trying to help a friend, only this function is alowed.
How do I play with the buffer to do that?
Thanks
edit:
I understand that I need to parse the buffer manually. and my question is how?
If that's the only thing in the file. This will do:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
char buffer[6];
char intBuffer[4];
ssize_t bytesRead;
int number;
int fd;
if ((fd = open("file.txt", O_RDONLY)) == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
if ((bytesRead = read(fd, buffer, 6)) == -1) {
perror("Error reading file");
exit(EXIT_FAILURE);
}
memcpy(intBuffer, buffer, 3);
intBuffer[3] = '\0';
number = atoi(intBuffer);
printf("The number is %d\n", number);
exit(EXIT_SUCCESS);
}
The following code will print "The number is 328".
Is this some kind of homework?
I am asking because there are better ways to do that than using the read function.
Anyway to answer your question, read reads size bytes from the file whose file descriptor is filedes and places them to the buffer.
It does not know anything about line breaks etc. So you need to manually find where a line ends, etc. If you want to only use read, then you need to manually parse the buffer after each call to read (supposing your files contains many lines, that you want to parse).
Beware that a line may be split between two read calls, so you need to handle that case with caution.

stat system call reports "No such file or directory"

I'm working on a homework assignment and I ran into a little snag.
I'm trying to read a filename from standard input and then stat the file to get the size (as per the assignment's requirements):
#define BUFFSIZE 4096
int
main(void) {
int n;
char buffer[BUFFSIZE];
struct stat buf;
while ((n = read(STDIN_FILENO, buffer, BUFFSIZE)) > 0) {
stat(buffer, &buf);
perror("stat");
}
}
Here's the output when ran (I entered the filename file):
file
stat: No such file or directory
But if I try something like this:
#define BUFFSIZE 4096
int
main(void) {
int n;
char buffer[BUFFSIZE] = "file";
struct stat buf;
stat(buffer, &buf);
perror("stat");
}
I get:
stat: Success
The file named file is in the directory that I'm running the program from.
How come there is a difference between reading in the string "file" and just initializing the array to the string "file"?
Before calling stat() print the value of buffer to standard output:
printf("[%s]\n", buffer);
It will not be what you expect as read() will not NULL terminate buffer for you.
Initialise buffer before read().
Not sure why you looping on the read() as you should acquire the complete name of the file before calling stat(). If you have not been forced to use read() consider using fgets().
Did you try printing the buffer? Most likely your read call returned a newline on the end of the string "file," and there is no file "file\n" in your directory. I would recommend using fgets instead to read the filename from the console. Use standard C input/output when you can, and only delegate to platform-specific code when there is a measurable benefit (e.g. there is no cross-platform stat function in the C standard library, and sometimes Unix I/O can measurably improve performance).
There is a '\n' in the buffer in the 1st snippet. Take it out
buffer[strlen(buffer) - 1] = 0;
The problem is that the read leaves the newline in the buffer, so you try to stat "file\n".
read() may be reading too much (or not enough) on the first loop. Try printing out what it's read just before the stat() call:
printf("Read %d characters (%s)\n",n,buf);
read() is probably a bit low level for this task - I'd recommend using scanf() instead.
while ( scanf ("%s",buffer) == 1) {
For safe code, you'll need to specify the maximum number of characters to read, which you can do like this:
while ( scanf ("%4096s",buffer) == 1) {
However, if you want to use the BUFFSIZE macro, you'll need to do a bit of mucking about:
#define XLIM_PERCENT_S(x) "%" #x "s"
#define LIM_PERCENT_S(x) XLIM_PERCENT_S(x)
....
while ( scanf ( LIM_PERCENT_S( BUFFSIZE ) , buffer) == 1) {

Resources