C copying files using only system calls, infinite runtime - c

So I am working on a simple program in C but have been stuck on the copying portion. The program takes two filenames on the command line as arguments and copies the first to the second by using system calls. If the second file exists it asks the user if they want to overwrite, if not it creates it. However, my program when the user choices overwrite goes on infinitely.
Here is my code:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n;
char c;
int num;
if (argc != 3) {
printf("%d\n",argc);
printf("Error, you need to give 2 arguments. Such that [File to copy] [File to create].\n");
exit(1);
}
if (access(argv[1], F_OK) < 0) {
printf("File %s either does not exist or cannot be accessed.\n", argv[1]);
exit(1);
} else {
printf("file %s exists\n", argv[1]);
}
if (access(argv[2], F_OK) < 0) {
printf("File %s does not exist, but one will be created.\n", argv[1]);
fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700);
} else {
printf("file %s exists\n", argv[2]);
printf("Would you like to overwrite %s? (Type 1 for yes or 0 for no)\n", argv[2]);
scanf("%d%c", &num, &c); // use c to capture \n
if (num == 1) {
fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700);
} else {
if (num == 0) {
printf("Ok, the file will not be copied and the program will now exit.\n");
exit(1);
} else {
printf("I do not recognize this response, program will now be terminated.\n");
}
}
}
printf("step\n");
while ((n1 = read(fd1, buffer, 1024)) > 0) {
printf("step\n");
if(write(fd2, buffer, n1) != n1){
printf("step\n");
perror("Error writing file.");
printf("step\n");
exit(3);
}
printf("stepss\n");
}
close(fd1);
close(fd2);
}
The printf("step") is for debugging, but it only prints one. Meaning the program freezes up by the while loop. I can use stat(), open(), read(), write(), close(), and access(). Any ideas on what is wrong or how it can be done better would be appreciated!

Any ideas on what is wrong
Your fd1 never been assigned, so read(fd1, ...) returns an error.
Check return value of read and printf("%m\n") will print the details.
$ ./a.out a b
file a exists
file b exists
Would you like to overwrite b? (Type 1 for yes or 0 for no)
1
step
Bad file descriptor

Related

Reading content of a file in child process and passing it to the parent process using a pipe in C

I want a program which reads a file in the child process and send the string/content to the parent process using simple pipe.
Here is what I have tried, I have read a file and tried to write into the pipe line by line in the while loop. But It doesn't seem to work that way. Your help will be highly appreciated.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE * fptr;
fptr = fopen(argv[1],"r");
char str1;
int pipefds[2];
char buffer[5];
if(pipe(pipefds) == -1)
{
perror("PIPE ERROR");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if(pid == 0)
{
char singleLine[150];
close(pipefds[0]);
while(!feof(fptr))
{
fgets(singleLine, 150, fptr);
//puts(singleLine);
write(pipefds[1], singleLine, sizeof(singleLine));
}
fclose(fptr);
//Close read file descriptor
exit(EXIT_SUCCESS);
}
else if(pid > 0)
{
//wait(NULL); //Wait for child process to finish
close(pipefds[1]); //Close write file descriptor
read(pipefds[0], buffer, 100); //Read pin from pipe
close(pipefds[0]); //Close read file descriptor
printf("%s",buffer);
}
return 0;
}
Check for Program Argument
To ensure that the filename parameter is provided, you could check as follows:
if (argc < 2) {
fprintf(stderr, "usage: progname <filename>");
exit(EXIT_FAILURE);
}
Opening the File
Presumably it makes sense to check whether fopen is successful or not.
You could do a check e.g. like this:
if ((fptr = fopen(argv[1], "r")) == NULL) {
perror("error opening file");
exit(EXIT_FAILURE);
}
Also like mentioned by #pat in the comments this code can be moved to the child.
Reading the file
Reading the file could be done like this:
while (fgets(singleLine, sizeof(singleLine), fptr)) {
write(pipefds[1], singleLine, strlen(singleLine));
}
Like mentioned by Jonathan Leffler in the comments one should not check feof upfront. Also important to note that you don't want to write sizeof(singleLine) bytes, because lines can have variable size and be shorter then the buffer size, so better to use strlen(singleLine) here.
Reading the Data
Reading the data must happen in a loop - as long as data is available. The call of read returns the number of bytes read.
ssize_t n;
while ((n = read(pipefds[0], buffer, sizeof(buffer) - 1)) > 0) {
buffer[n] = '\0';
printf("%s", buffer);
}
To make sure that you don't save data beyond the end of the buffer, you can use sizeof(buffer) - 1 as the third argument to the read call.
Programm
So your program, slightly modified regarding the above points, could look like this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int pipefds[2];
char buffer[100];
if (argc < 2) {
fprintf(stderr, "usage: progname <filename>");
exit(EXIT_FAILURE);
}
if (pipe(pipefds) == -1) {
perror("PIPE ERROR");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == 0) {
FILE *fptr;
if ((fptr = fopen(argv[1], "r")) == NULL) {
perror("error opening file");
exit(EXIT_FAILURE);
}
char singleLine[150];
close(pipefds[0]);
while (fgets(singleLine, sizeof(singleLine), fptr)) {
write(pipefds[1], singleLine, strlen(singleLine));
}
int error = ferror(fptr);
fclose(fptr);
if (error) {
perror("error reading file");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} else if (pid > 0) {
close(pipefds[1]);
ssize_t n;
while ((n = read(pipefds[0], buffer, sizeof(buffer) - 1)) > 0) {
buffer[n] = '\0';
printf("%s", buffer);
}
close(pipefds[0]);
}
return 0;
}

How to bypass the check of setuid

I am now taking a security class. And the professor asked us to exploit a program to gain higher privilege.
This is the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFSIZE 512
int main(int argc, char *argv[]) {
struct stat buf;
char cmd[BUFSIZE];
FILE *f = NULL;
if (argv[1] == NULL) {
fprintf(stderr, "Please provide an argument\n");
exit(1);
}
if (stat(argv[1], &buf)) {
fprintf(stderr, "Can't stat the file\n");
exit(1);
}
if (buf.st_gid != getegid()) {
fprintf(stderr, "The file must be owned by group %d\n", getegid());
exit(1);
}
sleep(1);
if ((f = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open command file\n");
return 1;
}
while (fgets(cmd, BUFSIZE, f)) {
if ((cmd[0] == '\n') || (cmd[0] == 0x7f)) {
fprintf(stderr, "Found empty line, quitting!\n");
return 2;
}
system(cmd);
}
printf("Done!\n");
return 0;
}
The particular situation is:
There is a binary code for this program for us to run. And the SUID of the binary code is set to higher level(here I assume level2). However, buf.st_gid != getegid() will always check if the file we specified is owned by root. Most important thing is, I only have level1 privilege. There is only one file owned by level2 I can use which is provided by our professor. And I certainly tried to pass in that filename. But nothing happens. I don't know if there is anyway I can exploit this program.(To execute some commands during runtime using the privilege of level2)

C Program that makes a copy of a file using standard I/O and system calls

I am trying to write a C program which uses standard I/O and System calls to perform copying of contents of one file to another file.
So far, I have done this :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n1;
if(((fd1 = open(argv[1], O_RDONLY)) == -1) || ((fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700)) == -1)){
perror("file problem");
exit(1);
}
while((n1=read(fd1, buffer, 1024) > 0)){
if(write(fd2, buffer, n1) != n1){
perror("writing problem ");
exit(3);
}
}
close(fd1);
close(fd2);
}
When I run the program like this :
cc copyContents.c
./a.out one.txt two.txt
Assuming that one.txt is well defined, what I want is to create a new file called two.txt and copy over all the contents of one.txt
When I look into the contents of two.txt after running the program, it has literally nothing in it. Just a blank file.
Where am I going wrong?
You wrote
while((n1=read(fd1, buffer, 1024) > 0)){
instead of
while ( (n1 = read(fd1, buffer, 1024)) > 0)
In your code the code int the while condition boils down to:
n1 = (read(fd1, buffer, 1024) > 0)
So the read is done correctly, it's return value is compared to 0, the result of the comparision (0 or 1) is assigned to n1.
This shows once more how important it is to format your code in a way that makes it readable.
You could have debugged this easily yourself with a debugger or by inserting one or two printfs in your code.
Input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void typefile (char *filename)
{
int fd, nread;
char buf[1024];
fd = open (filename, O_RDONLY);
if (fd == -1) {
perror (filename);
return;
}
while ((nread = read (fd, buf, sizeof (buf))) > 0)
write (1, buf, nread);
close (fd);
}
int main (int argc, char **argv)
{
int argno;
for (argno = 1; argno < argc; argno )
typefile (argv[argno]);
exit (0);
}
Output:
student#ubuntu:~$gcc –o prg10.out prg10.c
student#ubuntu:~$cat > ff
hello`enter code here`
hai
student#ubuntu:~$./prg10.out ff
hello
hai
This is the best solution and easily executable.
input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int f1, f2;
char buff[50];
long int n;
if(((f1 = open(argv[1], O_RDONLY)) == -1 || ((f2=open(argv[2], O_CREAT |
O_WRONLY | O_TRUNC, 0700))== 1)))
{
perror("problem in file");
exit(1);
}
while((n=read(f1, buff, 50))>0)
if(write(f2, buff, n)!=n)
{
perror("problem in writing");
exit(3);
}
if(n==-1)
{
perror("problem in reading");
exit(2);
}
close(f2);
exit(0);
}
Output:
cc sys.c
./a.out a.txt b.txt
cat b.txt
So, a.txt should have some content and this content is copied to b.txt
by "cat b.txt" you can cross-check the content(which is in "a.txt").
Narenda checks if n==-1 inside the loop, but, the loop test is n>0, so, that'll never happen.
Also, the test for a bad read should precede the attempt to write.

File reversing copy in c

I am trying to finish a program that can fork function a child process, and parent can get the input file (under same directory) , reverse the content of this file, then using pipe function pass to the child process. Child will read the message from pipe and generate an output file. I have finished fork, create pipe and reverse function. However I got stucked on write it to the pipe. I know there must some type confusion when i try to pass the parameter into the write function, Any hits would be appreciated.
Here is the Code I have so far:
#include <stdio.h>
#include <stdlib.h> //exit
#include <string.h>
#include <sys/types.h> //pid_t
#define READ_END 0
#define WRITE_END 1
int main(int argc, char *argv[]){
long loc;
FILE *in, *out;
char ch;
if (argc != 3)
{
printf("Usage %s message\n", argv[0]);
exit(EXIT_FAILURE);
}
int pipefd[2];
int pipe_return = pipe(pipefd);
if((in = fopen(argv[1], "rb")) == NULL) {
printf("Cannot open input file.\n");
exit(1);
}
if((out = fopen(argv[2], "wb"))==NULL) {
printf("Cannot open output file.\n");
exit(1);
}
if(pipe_return == -1)
{
printf("Unable to create pipe\n");
exit(EXIT_FAILURE);
}
pid_t return_from_fork = fork();
if (return_from_fork == -1)
{
printf("Unable to fork\n");
exit(EXIT_FAILURE);
}
else if (return_from_fork == 0) //this is a child
{
char msg;
close(pipefd[WRITE_END]);
int read_return = read(pipefd[READ_END], &msg, 1);
printf("read return:%d\n", read_return);
while(read_return > 0){
fputc(ch, out);
printf("%c",msg);
read_return = read(pipefd[READ_END], &msg, 1);
}
printf("child ends\n");
close(pipefd[READ_END]);
exit(EXIT_SUCCESS);
}
else if (return_from_fork > 0)
{
close(pipefd[READ_END]);
printf("this is parent\n");
fseek(in, 0L, SEEK_END);
loc = ftell(in);
while(loc >= 0L){
fseek(in, loc, SEEK_SET);
ch = fgetc(in);
printf("%c",ch);
int write_r = write(pipefd[WRITE_END], ch, 1);//here is the problem the printf() return -1
printf("%d",write_r);
loc--;
}
printf("\n");
close(pipefd[WRITE_END]);
wait(NULL);
printf("file successful generated.\n");
fcloseall();
exit(EXIT_SUCCESS);
}
}
And Here is the compile result:
zzz#ubuntu:~/Desktop/test$ gcc filereversecopy.c -o run
zzz#ubuntu:~/Desktop/test$ ./run src.txt out.txt
this is parent
�-1
-1e-1c-1n-1e-1t-1n-1e-1s-1 -1a-1 -1s-1i-1 -1s-1i-1h-1T-1
read return:0
child ends
file successful generated.
zzz#ubuntu:~/Desktop/test$
On the line you say is problem you are passing ch to write, and ch is type char. I'm sure you mean &ch instead. I bet if you change that write will return 1 instead of -1.
Also, you seek to the end to start reading, but when you seek to the end you are pointing at EOF. You need to start reading at the position before EOF. So after "fseek(in, 0L, SEEK_END); loc = ftell(in);" adding "loc--; fseek(in, loc, SEEK_SET);" makes it work.

Contents of file not being printed in terminal

Hi I am trying to read from a file and print it on terminal. But fwrite() does not print anything. Can anyone please help! I cannot see the output from the file on the terminal. After debugging all I can see is program is not entering into while loop used before fwrite().
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#define BUF_SIZE 128
int main(int argc, char* argv[])
{
int BATT_fd, ret_write, ret_read, i;
char buffer[BUF_SIZE];
if(argc != 2)
{
printf ("\nUsage: cp file1 file2\n");
return 1;
}
BATT_fd = open (argv [1], O_RDWR | O_CREAT, S_IRWXU);
if (BATT_fd == -1)
{
perror ("open");
return 2;
}
printf("\n file opened successfully with file desc %d\n", BATT_fd);
printf("enter data into file\n");
scanf("%[^\n]", buffer);
if((ret_write = write (BATT_fd, &buffer, BUF_SIZE)) == 0)
{
printf("nothing is write");
}
else if((ret_write = write (BATT_fd, &buffer, BUF_SIZE)) == -1)
{
printf("write error");
}
else
{
printf("wrote %d characters to file\n", ret_write);
printf("address writeen is %x\n", buffer[i]);
}
if((ret_read = read(BATT_fd, &buffer, BUF_SIZE)) > 0)
{
perror("read");
return 4;
}
else
{
while((ret_read = read (BATT_fd, &buffer, BUF_SIZE)) > 0)
{
fwrite(buffer, 1, ret_read, stdout);
}
}
close (BATT_fd);
return 0;
}
output:
Before reading data from file, you need to move current position in file to the begining. That's because your write operations have moved current position to the end of file, so there is nothing left for reading ;).
see fseek
EDIT:
lseek would be better in your case (see comments)

Resources