ETXTBSY and how to override it - c

I need to write to an executable file that is being executed, but I can't open it for writing. For example:
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd = open(argv[0], O_RDWR);
if (fd == -1) perror(NULL);
return 0;
}
% uname -rs
FreeBSD 8.0-STABLE
% ./example_ETXTBSY
Text file busy
There are some explanations what the heck is ETXTBSY in Linux, but nevertheless, is it possible to override this error?
P.S.
I'm not trying to write a virus.

If you are trying to replace an executing file, as opposed to modifying an executable on the fly, you can unlink() it first and then open it for writing.
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
unlink(argv[0]);
int fd = open(argv[0], O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
if (fd == -1) perror(NULL);
return 0;
}
If you are trying to get access to the actual running process, your best bet is ptrace().
(Edited to add the mode bits.)

Related

Communicating through pipes and sending messages

I am having trouble communicating with the child process. I am trying to make quick.c simply get an input from stdin and send it to sand.c to capitialise it and send it back to the parent and then print it to stdout. Right now the program asks for an input twice instead of only asking once.
this is quick.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2];
int test[2];
int pid;
pid_t child_a;
char buffer[50], buff[50];
if(pipe(fds)) {
perror("Pipe:");
exit(0);
}
if(pipe(test)) {
perror("Pipe:");
exit(0);
}
child_a = fork();
if (child_a == 0) {
//Child
FILE *f = fdopen(fds[0], "r");
FILE *e = fdopen(test[1], "w");
close(fds[1]);
close(test[0]);
//dup2(fds[0],0); causes infinite loop
dup2(test[1],1);
execlp("./sand", "sand", NULL);
fclose(e);
fclose(f);
} else {
// Parent
// Wrap the pipes
FILE *f = fdopen(fds[1], "w");
FILE *e = fdopen(test[0], "r");
close(fds[0]);
close(test[1]);
fgets(buffer,50, stdin);
fprintf(f,"%s",buffer);
while(fgets(buff, 50, e)) {
printf("Parent receive %s", buff);
}
fflush(stdout);
fclose(f);
fclose(e);
wait(NULL);
}
return 0;
}
This method is sand.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[]) {
char buffer[50];
int i = 0;
fgets(buffer,50,stdin);
char chr;
// Loop
while (buffer[i]) {
buffer[i] = toupper(buffer[i]);
i++;
}
fprintf(stdout,"%s",buffer);
return 0;
}
On running the code in my machine, the commented dup2 line does not loop to infinity. That may be because pipe programs run differently on different machines. However, the program terminates after taking input. Here are the things that are wrong with your code:
You aren't waiting for the child to write data to test pipe before printing in the parent. You must put the wait statement after taking input.
You've used file pointers for handling pipes. Pipes are accessed with file descriptors and cause unexpected results when handled with file pointers. Instead of fgets and fprintf, use read and write methods to work with file descriptors.
Error in the execlp command which I've commented.
There are errors regarding buffers, I've commented them in the code where they occur.
This is quick.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2];
int test[2];
int pid;
pid_t child_a;
char buffer[50], buff[50];
if(pipe(fds)) {
perror("Pipe:");
exit(0);
}
if(pipe(test)) {
perror("Pipe:");
exit(0);
}
child_a = fork();
if (child_a == 0) {
//Child
//CHANGED: No need to open file pointers here. Pipes are already open and accessed by file descriptor instead of file pointer. File pointers create trouble when used with pipes. 0 is file descriptor of stdin, 1 for stdout.
close(fds[1]);
close(test[0]);
dup2(fds[0],0);
dup2(test[1],1);
//CHANGED: There was an error with the command you wrote.
//That's because ./sand arg will look for a 'sand' directory which doesn't exist
//This line will throw warnings because execlp requires needs a command as the second argument, but in this case the filename is the command.
//NOTE: before running quick.c, compile sand.c as sand.out and not a.out
execlp("./sand.out",NULL);
printf("Exec Error\n"); //this will only execute if execlp didn't run. Always have this line in your code to know what's happening.
}
else
{
// Parent
// Wrap the pipes
//Got rid of the file pointers
close(fds[0]);
close(test[1]);
//CHANGE: fgets is only used with file pointers. While handling pipes, we work with file descriptors, with which read and write methods are used
int n = read(0,buffer,50); //If this is new to you, I strongly recommend reading manual pages for read and write, but for right now
// The signature should be enough to understand - read/write(int file_descriptor, char *buffer, int number_of_bytes)
write(fds[1],buffer,n);
//MOST IMPORTANT: You need to wait for child after this point. Because test pipe doesn't have data yet which will be received by child.
wait(NULL);
//CHANGE: printf statements do not work well with buffere, because buffers are not terminated with null
//%s specifier will always look for a null or print garbage
//If you still want to use printf, look into $man bzero
while((n = read(test[0],buff, 50))>0)
{
write(1,buff,n);
}
fflush(stdout);
}
return 0;
}
This is sand.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
char buffer[50];
int i = 0;
int n = read(0,buffer,sizeof(buffer)); //changed fgets to read, to get number of bytes read.
char chr;
// Loop
// we have number of bytes. So change while to for
for (i=0;i<n;i++)
{
buffer[i] = toupper(buffer[i]);
}
write(1,buffer,n); //Changed fprintf to write to get rid of %s problem.
//Again, to fill remaining places of buffer with null, look up bzero.
//The reason I haven't done that is to not confuse you with so many changed methods.
return 0;
}
Let me know, if the solution also helps you find the source of the infinity loop.

How to use exec() system call to return the square of a number and store it to a file?

Given a number in the command line by the user, I need to return the square of that number and store it into a file called child.txt, but I need to do this by creating a child process and using exec(). How exactly do I do that? Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *f;
f = fopen("child.txt", "w");
int pid = fork();
square(argv);
exec(); // This is wrong, I need to fix this
return 0;
}
int square(char *argv[]) {
int i;
i = atoi(argv[1]);
return i*i;
}
What parameters should I be passing into exec()? I've seen other examples where exec() has parameters such as echo or -ls, but is it possible to somehow pass in the square() function I've written?
This is such a terrible idea for so many reasons....
But you can certainly do it:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int square(const char *arg) {
int i;
i = strtoll(arg, NULL, 10);
return i*i;
}
int main(int argc, char *argv[]) {
FILE *f;
char cmd[128];
int rv;
if( argc < 3 ) {
fputs( "Please specify target file and integer to square\n", stderr);
exit(EXIT_FAILURE);
}
f = fopen(argv[1], "w");
if( f == NULL ) {
perror(argv[1]);
exit(EXIT_FAILURE);
}
rv = snprintf(cmd, sizeof cmd, "echo %d >& %d", square(argv[2]), fileno(f));
if( rv >= sizeof cmd ) {
fputs( "Choose a smaller int\n", stderr);
exit(EXIT_FAILURE);
}
execl("/bin/sh", "sh", "-c", cmd, NULL);
perror("execl");
return EXIT_FAILURE;
}
But note that if this is for an assignment and you've been told to use exec*, then this solution would be an F grade. This is not what you're supposed to do. (At least I hope not. If that is the goal, then this is a terrible assignment.)
If you want to make some calculation not in main thread, you can create thread and detach it.
If you use c11 compiler you can use threads.h.
thrd_create wil create your thread, thrd_detach will detach it from main process.
If your compiler doesn't support c11 you can use native multitreading options.
#include <pthread.h> for Unix systems
#include <windows.h for Windows

Reading and writng with named pipes C

I'm writing a program that should run indefinitely maintaining the value of a variable. Two other programs could change the value of the variable. I use named pipes to receive and send the variable value to external programs.
Here is my code for the manager of the variable.
manager.c:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
char a = 'a';
void *editTask(void *dummy)
{
int fd;
char* editor = "editor";
mkfifo(editor, 0666);
while(1)
{
fd = open(editor, O_RDONLY);
read(fd, &a, 1);
close(fd);
}
}
void *readTask(void *dummy)
{
int fd;
char* reader = "reader";
mkfifo(reader, 0666);
while(1)
{
fd = open(reader, O_WRONLY);
write(fd,&a,1);
close(fd);
}
}
int main()
{
pthread_t editor_thread, reader_thread;
pthread_create(&editor_thread, NULL, editTask, NULL);
pthread_create(&reader_thread, NULL, readTask, NULL);
pthread_join (editor_thread, NULL);
pthread_join (reader_thread, NULL);
return 0;
}
This program uses pthreads to separately get external values for the variable and to communicate the current value of the variable to external programs.
The program that is able to write values to the variable is:
writer.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("Need an argument!\n");
return 0;
}
int fd;
char * myfifo = "editor";
fd = open(myfifo, O_WRONLY);
write(fd, argv[0], 1);
close(fd);
return 0;
}
The program that could read the current value is:
reader.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd;
char * myfifo = "reader";
fd = open(myfifo, O_RDONLY);
char value = 'z';
read(fd, &value, 1);
printf("The current value of the variable is:%c\n",value);
close(fd);
return 0;
}
I ran these programs in my Ubuntu system as follows:
$ ./manager &
[1] 5226
$ ./writer k
$ ./reader
bash: ./reader: Text file busy
Why doesn't my system allow me to run this program?
Thank you.
You are trying to call both the FIFO and the reader program "reader".
Also, you have no error checking. You have no idea whether those calls to mkfifo and open succeeded or not. Adding this is critical before you attempt to do any troubleshooting.

Can't open() second file C

For some reason if I do a second open, it compiles but when I try to run it, it does nothing like it's locked. It's missing a lot of other functions, because it's a work in progress for a school project. If I remove one of the open(), the program runs just fine.
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFER_SIZE 100
#define INPUT "/tmp/father"
int main(int argc, char **argv)
{
int fds;
int fd;
char mode[BUFFER_SIZE];
char buffer[BUFFER_SIZE];
unlink(INPUT);
mkfifo(INPUT, S_IRUSR | S_IWUSR);
if(argc != 2)
{
fputs("Argumentos invalidos\n", stderr);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_WRONLY);
if(fd == -1)
{
fprintf(stderr, "\nCan't open pipe\n");
exit(EXIT_FAILURE);
}
fds = open(INPUT, O_RDONLY);
if(fds == -1)
{
fprintf(stderr, "\nCan't open pipe\n");
exit(EXIT_FAILURE);
}
while(1)
{
fgets(buffer,BUFFER_SIZE,stdin);
sscanf(buffer,"%s", mode);
write(fd,buffer,strlen(buffer));
}
}
Are you sure there's a problem? You are reading from stdin (the fgets at the bottom), and writing to the pipe. What you're missing is something reading from the pipe. So if in another terminal you type:
$ cat /tmp/father
then anything you type into your prog will appear there.
So, in one terminal I do:
$ ./test /tmp/father
line one
line two
And in the second terminal:
$ cat /tmp/father
and I see:
line one
line two
No?
P.S. You are doing sscanf to read from buffer and write to mode, then writing out the buffer string. Not that it matters, but you're not using mode.

sending a string between two programs using named pipes

I am trying to send a string to another program
but i am having problem using O_WRONLY | O_NONBLOCK,
if i replace that with O_RDWR the program works fine
but i wanted to know if there is a way to send/read the
string without using O_RDWR. Right now it returns a
empty string for some reason.
Writer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_LINE 1024
int main(int argc, char **argv)
{
char line[MAX_LINE];
int pipe;
printf("Enter line: \n");
fgets(line, MAX_LINE, stdin);
pipe = open("link1", O_WRONLY | O_NONBLOCK);
write(pipe, line, strlen(line));
system("./run"); //executing the reader
close(pipe);
return 0;
}
reader:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_BUF 1024
int main(int argc, char **argv)
{
int fd;
char * link1 = "link1";
char buf[MAX_BUF];
fd = open(link1, O_RDONLY | O_NONBLOCK);
read(fd, buf, MAX_BUF);
printf("%s\n", buf);
close(fd);
return 0;
}
Are you running the reader first? If no process has the FIFO open for reading when the writer attempts to open it write only, then the open will fail.
From the Open Group man page:
When opening a FIFO with O_RDONLY or O_WRONLY set: If O_NONBLOCK is set:
An open() for reading only will return without delay. An open() for writing only will return an error if no process currently has the file open for reading.

Resources