Using of a system call in c - c

I would like to create a program name patch witch recives a FILENAME and a string.In the file there is the string 'allis'.I need to replace each time the string 'allis' appears in the text with the string I recieved as an input.
I need to use only system call and not the standat libary.
This is an example code on how the code should look like(this just example of the structure it is not the mission, the code writes "allis" word instead of "hello world"):
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc , char* argv[], char* envp[])
{
char buf[6];
int fd = open(argv[1],O_WRONLY,0777);
if (fd == -1)
exit(1);
write(fd,"hello world!\n",13);
close(fd);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
exit(1);
read(fd,buf,5);
buf[5]='\0';
close(fd);
fd = open(argv[1],O_WRONLY,0777);
if (fd == -1)
exit(1);
write(fd,"allis",5);
close(fd);
return 0;
}
I need to use the system call lseek but I dont know how I should use it because I dont know where in the text 'allis' is located and what happens if the string i get as an input is bigger than 'allis' I need to move all the text to the right or something because I will override other text.
EDIT:
I wrote a code which check char by char (instead of allis its shira and it replace it with sergay)It actually worked. and than I tried to change the code to work with argv[1] and argv[2] as needed and it didnt work I revert back to the code that originally worked for me and its just doesnt work now!! The problem is that the buf doesnt take 5 character (only 1)
and believe me or not it worked before.
The code :
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define SYS_WRITE 1
#define STDOUT 1
extern int system_call();
int main(int argc , char* argv[], char* envp[])
{
char buf[5];
int index1=0,index2=0;//the index of the file
int fd1;
int fd = open("file.txt", O_RDONLY);
if (fd == -1)
return 1;
fd1 = open("copytext.txt",O_WRONLY,0777);
if (fd1 == -1)
return 1;
int i =0;
while (fd!=-1){//while there is still info to read
printf("enter the %d loop\n",i);
i++;
if(read(fd,buf,5) == 0 ) break;//read 5 chars from the file //buf[5]='\0';//!! not sure about this
printf("the buffer is: %s\n",buf);
if ((buf[0]=='s') && (buf[1]=='h') && (buf[2]=='i') && (buf[3]=='r') && (buf[4]=='a'))// if (strcmp(buf,"shira")==0)//if we found shira
{
write(fd1,"sergay",6);//replace shira
index2 = index2 + 6;
if(lseek(fd1,index2,SEEK_SET) < 0) break;
index1 = index1 + 5;//size of shira
if(lseek(fd,index1,SEEK_SET) < 0) break;
}
else {//we did not find shira;
write(fd1,buf,1);//write only one
index2++;
if(lseek(fd1,index2,SEEK_SET) < 0) break;
index1++;
if(lseek(fd,index1,SEEK_SET) < 0) break;
}
}
printf("get out of the loop\n");
char buffer[index2];
fd1 = open("copytext.txt", O_RDONLY);
if (fd1 == -1)
return 1;
if(lseek(fd1,0,SEEK_SET) < 0) return 1;
if(read(fd1,buffer,index2) == 0 ) return 1;
fd = open("file.txt",O_WRONLY,0777);
if (fd == -1)
return 1;
if(lseek(fd,0,SEEK_SET) < 0) return 1;
write(fd,buffer,index2);
close(fd);
close(fd1);
return 0;
}

Related

How do I read from a file and output specific strings in c

I'm writing a program that will read from /etc/passwd and output the username and shell.
For example, here is the first line of the /etc/passwd file:
root:x:0:0:root:/root:/bin/bash
I need to only output the user and the shell. In this instance it would print:
root:/bin/bash
The values are separated by ':' so I just need to print the string before the first ':' and the string after the 6th ':'
Here is the code I have so far:
#include <string.h>
#define BUFFERSIZE 4096
int printf(const char *text, ...);
int main(void) {
int fd;
int buff_size = 1;
char buff[BUFFERSIZE];
int size;
fd = open("/etc/passwd", O_RDONLY);
if (fd < 0) {
printf("Error opening file \n");
return -1;
}
size = strlen(buff - 17);
size = size + 1;
while ((size = read(fd, buff, 1)) > 0) {
buff[1] = '\0';
write(STDOUT_FILENO, buff, size);
}
}
(I am creating prototypes for printf because one of the requirements was to write the program without including <stdio.h> or <stdlib.h>)
Another approach is to use a single loop and a state variable to track the state of where you are in each line based on the number of colons read. The state-variable ncolon does that below. Essentially you read every character and check whether the loop is in a state where you should write the character as output or not. You condition the write on the number of colons, whether you are before the 1st or after the last.
Putting it altogether, you could do:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (int argc, char **argv) {
int fd, /* file descriptor */
ofd = STDOUT_FILENO, /* output file descriptor */
ncolon = 0; /* counter - number of colons seen */
/* open file given on command line or read from stdin otherwise */
if ((fd = argc > 1 ? open (argv[1], O_RDONLY) : STDIN_FILENO) == -1) {
return 1;
}
for (;;) { /* loop continually */
unsigned char c; /* storage for character */
int rtn; /* var to save return */
if ((rtn = read (fd, &c, 1)) < 1) { /* validate read of 1 char */
if (rtn == -1) { /* return on error */
return 1;
}
break; /* break read loop on EOF */
}
if (ncolon < 1 || ncolon == 6) { /* if before 1st or after last */
write (ofd, &c, 1); /* output char */
}
if (c == '\n') { /* reset ncolon on newline */
ncolon = 0;
}
else if (c == ':') { /* increment on colon */
ncolon += 1;
}
}
if (fd != STDIN_FILENO) { /* close file */
close (fd);
}
}
Example Use/Output
$ ./read_etc-passwd /etc/passwd
root:/bin/bash
messagebus:/usr/bin/false
systemd-network:/usr/sbin/nologin
systemd-timesync:/usr/sbin/nologin
nobody:/bin/bash
mail:/usr/sbin/nologin
chrony:/usr/sbin/nologin
...
Confirm the Format
$ diff <(./read_etc-passwd /etc/passwd) <(awk -F: '{print $1":"$7}' /etc/passwd)
(no output means program output and awk output were identical)
Your program has undefined behavior when you evaluate strlen(buff - 17). It is unclear why you do this.
You can solve the problem with these simple steps:
read one byte at a time
count the ':' on the line
output the byte if the count is equal to 0 or equal to 6.
reset the count at newline (and print the newline)
Note that read(fd, &b, 1) and write(1, &b, 1) return -1 in case of error or interruption and should be restarted if errno is EINTR.
Here is a modified version:
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void) {
int fd;
unsigned char b;
int count;
ssize_t ret;
fd = open("/etc/passwd", O_RDONLY);
if (fd < 0) {
write(2, "Error opening /etc/password\n", 28);
return 1;
}
count = 0;
for (;;) {
ret = read(fd, &b, 1);
if (ret == 0) { // end of file
break;
}
if (ret < 0) { // error
if (errno == EINTR)
continue;
write(2, "Read error on /etc/password\n", 28);
return 1;
}
if (b == '\n') {
// reset count, print b
count = 0;
} else
if (b == ':') {
// increment count, print ':' only if count == 1
count = count + 1;
if (count != 1)
continue;
} else
if (count != 0 && count != 6) {
// print b only if count is 0 or 6
continue;
}
for (;;) {
ret = write(1, &b, 1);
if (ret == 1)
break;
if (ret < 0 && errno = EINTR)
continue;
write(2, "Write error\n", 12);
return 1;
}
}
close(fd);
return 0;
}

preventing errors when implementing the mv command and copying strings from argv

I implemented the move command from linux.
I did not try to prevent errors. The program would check if the source file named in argv [1] exists and can be opened, how can I do that?
I also think it's a problem copying strings from argv, because I need to call malloc and free which also use system calls and thus affect the performance of the program (if I'm not mistaken)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
char *source, *destination, *new_source, *new_destination;
char *current_directory;
if (argc != 3) {
printf("usage- %s source destination\n", *argv);
exit(EXIT_FAILURE);
}
// work on copy
source = (char*)malloc(strlen(argv[1]) + 1);
strcpy(source, argv[1]);
destination = (char*)malloc(strlen(argv[2]) + 1);
strcpy(destination, argv[2]);
current_directory = getenv("PWD");
new_source = (char*)malloc(strlen(source) + 1 + strlen(current_directory) + 1);
strcpy(new_source,current_directory);
strcat(new_source,"/");
strcat(new_source,source);
new_destination = (char*)malloc(strlen(destination) + 1 + strlen(current_directory) + 1 + strlen(source) + 1);
strcpy(new_destination,current_directory);
strcat(new_destination,"/");
strcat(new_destination,destination);
strcat(new_destination,"/");
strcat(new_destination,source);
/*execute systemcall*/
if(rename(new_source,new_destination) != 0){
fprintf(stderr,"error: %s\n",strerror(errno));
}
free(new_source);
free(new_destination);
free(source);
free(destination);
exit(EXIT_SUCCESS)
The use-cases i see :
src || target is a directory
src || target is a symlink
src || target are not accessible (bad rights)
Take a look at this snippet :
int main(int ac, char **av) {
if (ac < 3)
return (1); // bad arguments
int sfd, tfd = -1;
if ((sfd = open(av[1], O_RDONLY | O_SYMLINK)) < 0 || (tfd = open(av[2], O_WRONLY | O_CREAT | O_TRUNC | O_SYMLINK, 0666)) < 0)
return (2); // opens fail
struct stat sstat, tstat;
if (stat(av[1], &sstat) || S_ISDIR(sstat.st_mode) || !stat(av[2], &tstat) && S_ISDIR(tstat.st_mode))
return (3); // no source or source is a directory or target is a directory
char *sdata = malloc(sstat.st_size);
if (read(sfd, sdata, sstat.st_size) < 0)
return (4); // read fail
if (write(tfd, sdata, sstat.st_size) < 0)
return (5); // write fail
}

unbuffered I/O: read int from file and write it on standard output

This program is meant to take as parameter a file, then read a string from standard input and write its length into the file, then read the content of the file (which is supposed to contain the lengths of the strings from the standard input) and write it in standard output:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX_BUFF 4096
int main(int argc, char **argv)
{
if (argc != 2)
{
puts("you must specify a file!");
return -1;
}
int nRead;
char buffer[MAX_BUFF], tmp;
int fd;
puts("write \"end\" to stop:");
fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRWXU);
while ((nRead = read(STDIN_FILENO, buffer, MAX_BUFF)) > 0 && strncmp(buffer,"end", nRead-1) != 0 )
{
if ( write(fd, &nRead, 1) < 0 )
{
perror("write error.");
return -1;
}
}
puts("now i am gonna print the length of the strings:");
lseek(fd, 0, SEEK_SET); //set the offset at start of the file
while ((nRead = read(fd, buffer, 1)) > 0)
{
tmp = (char)buffer[0];
write(STDOUT_FILENO, &tmp, 1);
}
close(fd);
return 0;
}
this is the result:
write "end" to stop:
hello
world
i am a script
end
now i am gonna print the length of the strings:
I tried to convert the values written in the file into char before write in standard output with no success.
How am i supposed to print on standard output the lengths by using unbuffered I/O? Thank you for your replies
EDIT: i changed the read from file with this:
while((read(fd, &buffer, 1)) > 0)
{
tmp = (int)*buffer;
sprintf(buffer,"%d:", tmp);
read(fd, &buffer[strlen(buffer)], tmp);
write(STDOUT_FILENO, buffer, strlen(buffer));
}
but actually i have no control on the effective strlen of the string thus the output is this:
13:ciao atottti
4:wow
o atottti
5:fine
atottti
as you can see, the strlength is correct because it consinder the newline character ttoo. Still there is no control on the effective buffer size.

C - Read by basic I/O reads only "\n"

I have a problem at my C-lecture skill practice. My exercise is to read a text document (which is in the same directory like the program) char by char and write it reversed (so from the end to the beginning, char by char) at the Terminal (i have to work at Ubuntu).
Unfortunately it doesn't work - "read" only reads newline-chars (\n).
Can you find my mistake?
#include <sys/stat.h> //mode_t: accessing rights for the file
#include <fcntl.h> //for I/O
#include <unistd.h> //for file descriptors
#include <string.h> //for strlen
short const EXIT_FAILURE = 1;
short const EXIT_SUCCESS = 0;
char const* USAGE_CMD = "usage: write_file filename string_to_write\n";
char const* ERR_OPEN = "error in open\n";
char const* ERR_READ = "error in reading\n";
char const* ERR_CLOSE = "error in close\n";
char const* ERR_WRITE = "error in write\n";
int main(int argc, char** argv){
int fd = open(argv[1], O_RDONLY);
if(fd == -1){
write(STDERR_FILENO, ERR_OPEN, strlen(ERR_OPEN));
return EXIT_FAILURE;
}
int two_char_back = (-1)*sizeof(char); //shift-value for char
int one_back = -1; //shift-value for "no shift"
int length = lseek(fd, one_back, SEEK_END);//setting to one before oef
int i = 0; //for the loop
char buffer;
char* pbuffer = &buffer; //buffer for writing
while (i < length){
if (read(fd, pbuffer, sizeof(buffer)) == -1){ //READING
write(STDERR_FILENO, ERR_READ, strlen(ERR_READ));
return EXIT_FAILURE;
}
if(write(STDOUT_FILENO, pbuffer, sizeof(buffer)) == -1){ //WRITING
write(STDERR_FILENO, ERR_WRITE, strlen(ERR_WRITE));
return EXIT_FAILURE;
}
lseek(fd, two_char_back, SEEK_CUR); //STEPPING
i++;
}
if(close(fd) == -1){ //CLOSING
write(STDERR_FILENO, ERR_CLOSE, strlen(ERR_CLOSE));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This is wrong:
int two_char_back = (-1)*sizeof(char);
sizeof(char) is 1, you need -2
Haven't tried running it, but looks like two_char_back should be -2. The read advances the cursor, so -1 keeps reading the same one.
Also, just an option, you could make it more efficient by reading the whole file in then reversing it, then writing.
You have a typo in following line:
int two_char_back = (-1)*sizeof(char);
It must be:
int two_char_back = (-2)*sizeof(char);
As read() increments a cursor, you are actually reading the same character all the time e.g:
example text
^
|
After reading:
example text
^
|
After seeking:
example text
^
|
Thanks for your advices a lot!
& Thanks to my colleagues!
Now it works but I created kind of a new version, here it is:
#include <sys/stat.h> //mode_t: accessing rights for the file
#include <fcntl.h> //for I/O
#include <unistd.h> //for file descriptors
#include <string.h> //for strlen
short const EXIT_FAILURE = 1;
short const EXIT_SUCCESS = 0;
char const* USAGE_CMD = "usage: write_file filename string_to_write\n";
char const* ERR_OPEN = "error in open\n";
char const* ERR_READ = "error in reading\n";
char const* ERR_CLOSE = "error in close\n";
char const* ERR_WRITE = "error in write\n";
int main(int argc, char** argv){
int fd = open(argv[1], O_RDONLY); //OPENING
if(fd == -1){
write(STDERR_FILENO, ERR_OPEN, strlen(ERR_OPEN));
return EXIT_FAILURE;
}
int file_size = lseek(fd, 0, SEEK_END); //setting to eof
int i = file_size-1; //for the loop, runs from the end to the start
char buffer;
//the files runs from the end to the back
do{
i--;
lseek(fd, i, SEEK_SET); //STEPPING from the start
if (read(fd, &buffer, sizeof(buffer)) != sizeof(buffer)){ //READING
write(STDERR_FILENO, ERR_READ, strlen(ERR_READ));
return EXIT_FAILURE;
}
if(write(STDOUT_FILENO, &buffer, sizeof(buffer)) != sizeof(buffer)){ //WRITING
write(STDERR_FILENO, ERR_WRITE, strlen(ERR_WRITE));
return EXIT_FAILURE;
}
}while (i != 0);
buffer = '\n';
write(STDOUT_FILENO, &buffer, sizeof(buffer));//no error-det. due to fixed value
if(close(fd) == -1){ //CLOSING
write(STDERR_FILENO, ERR_CLOSE, strlen(ERR_CLOSE));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

shell with input & output on files in C

I'm having some trouble to run an interactive shell (/bin/bash, /bin/sh for ins) in the background with input and output redirected in files. I tried different things but it does not work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
char *argve[2];
argve[0]="/bin/sh";
argve[1]=NULL;
FILE *fichin, *fichout;
fichin=fopen("/root/C/fichin.temp", "w+");
fichout=fopen("/root/C/fichout.temp", "w+");
dup2(fileno(fichin), 0); //stdin
dup2(fileno(fichout), 1); //stdout
dup2(fileno(fichout), 2); //stderr
/*freopen("/root/C/fichin.temp", "r", stdin);
freopen("/root/C/fichout.temp", "w+", stdout);*/
system("/bin/sh");
//execve("/bin/sh", argve, NULL);
return 0;
}
you want this :
/* shell interactive */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv) {
int file_input ;
int file_output;
int size_read = 0;
pid_t pid_command;
char _command[10];
char *read_one_char=NULL;
char command_separator;
int i=0;
/* open file input on READONLY */
/* open return file descriptor */
file_input = open("fichin.temp", O_RDONLY , 0666);
if (file_input <0 )
{
perror("can't open input file");
}
file_output = open("fichout.temp", O_CREAT | O_TRUNC | O_WRONLY , 0666) ;
if (file_output < 0)
{
perror("can't open output file");
}
read_one_char = malloc(sizeof(char));
if (read_one_char == NULL)
{
perror(" malloc failed ");
}
dup2(file_input, 0); //stdin
dup2(file_output, 1); //stdout
dup2(file_output, 2); //stderr
/*reading commands assuming that each line is a command
command 1
command 2
..
command n
you can change command_seperator
*/
command_separator = '\n';
do
{
size_read = read(file_input,(void*)read_one_char,1);
if (*read_one_char!=command_separator && size_read > 0)
{
_command[i]=*read_one_char;
i++;
}
else
{
_command[i--]='\0';
i=0;
write(1,"\n\t============ output for command ==========\n",45);
system(_command);
}
}while(size_read != 0);
return 0;
}
i wrote it quickly; try it and tell me if its that you want

Resources