I have this program:
#include <ncurses.h>
SCREEN * sstderr;
SCREEN * sstdout;
int main() {
sstderr = newterm(NULL, stderr, NULL);
noecho();
sstdout = newterm(NULL, stdout, stdin);
set_term(sstdout);
addstr("PRESS A KEY");
getch();
def_prog_mode();
endwin();
system("ls -l");
getchar();
reset_prog_mode();
refresh();
addstr("Press another key");
getch();
set_term(sstdout);
endwin();
set_term(sstderr);
endwin();
}
every line that is in the output of the 'ls -l' command gets missprinted like this:
drwxr-xr-x 2 root root 4096 Feb 11 09:22 bin
drwxr-xr-x 3 root root 4096 Mar 6 2016 boot
drwxr-xr-x 18 root root 3380 Feb 23 00:12 dev
drwxr-xr-x 113 root root 12288 Apr 25 10:45 etc
...
I tried using def_shell_mode() just before the initscr() line (or newterm() in my case), and reset_shell_mode() just before system("ls -l"); but the problem persists.
the only way I can kind of fix this is using
system("reset");
just before the system("ls -l"); line.
Anyone know what the real problem is, and how I can fix it without that "reset" call?
Thanks!
Your program initializes the same terminal into curses mode twice. But the first time it sets the terminal into raw mode starting from cooked mode. The second time it is already in raw mode. It doesn't matter (much) that those are separate streams, but that they're connected to the same terminal driver.
Having initialized the second screen (for standard output), and then doing a "restore", nothing happens because it restores to raw mode.
You could "fix" it by switching back to the standard-error screen before doing endwin. Offhand, you'd have problems copying the shell-mode terminal settings from one screen to another.
Related
This question already has answers here:
Writing to stdin and reading from stdout (UNIX/LINUX/C Programming)
(5 answers)
Closed 10 months ago.
In order to understand the workings of C and linux, I was doing the pwnable.kr challenges, but there is something in the first challenge that doesn't quite add to me.
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
To my understanding, the 0 fd is for stdin, and the 1 and 2 fd are for stdout, yet all three of them allow me to solve the challenge. I understand the first one, but wouldn't the other 2 file descriptors just read what I print on my promt, and not allow me to write anything after?
Let's take a look at what /proc says:
$ ls -al /proc/self/fd
total 0
dr-x------. 2 mrsam mrsam 0 Apr 23 15:25 .
dr-xr-xr-x. 9 mrsam mrsam 0 Apr 23 15:25 ..
lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 0 -> /dev/pts/1
lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 1 -> /dev/pts/1
lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 2 -> /dev/pts/1
For an interactive terminal all three file descriptors are, basically the same. All three are connected to the terminal device, after all, why won't they be? Input and output goes to the same screen.
And, for simplicity, you can think of them as dup()s of each other. So, as a side effect, all three file descriptors are read/write.
Now, of course, this is only true for programs launched from an interactive terminal. In an arbitrary program, launched in an unknown environment you can only rely on being able to read from 0 and write to 1 and 2.
I realized a GUI with GTK3 that, essentially, generates an input text file for an exe program that with these inputs can do elaborations.
This exe is put in executions in the GUI by mean of a System call ( system("exe input.dat &") ).
This exe can print on screen message of information or error.
What I want to do is redirect these message on a GtkTextView.
The idea that I had is to redirect output and error on a file ( system("exe input.dat > output_file.txt 2>&1 &") ) and in the GUI read line by line this
file and send this strings in the textView.
I was not sure that 2 process can write and read the same file and to test this concept I used these 2 simple programs:
the writer (used like ./writer > out_file.txt):
#include <stdio.h>
#include <unistd.h>
main()
{
int a;
while(1)
{
fprintf(stdout,"a=%d\n",a);
fflush(stdout);
sleep(1);
a++;
}
}
and the reader:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
fp = fopen("out_file.txt","r");
char string_new[1024];
char string_old[1024];
strcpy(string_old," ");
while(1)
{
fgets(string_new,1024,fp);
if ( strlen(string_new) != 0 )
{
if ( strcmp(string_new, string_old) != 0 )
{
fprintf(stdout,"%s",string_new);
fflush(stdout);
strcpy(string_old,string_new);
}
}
}
}
This two programs run correctly and the second one print the output of the first one.
Putting in the GUI a similar code, the GUI read only the first line of the file.
How I can solve this issue?
Thank you
You should use popen instead of executing system("exe input.dat &"), then it's easy to read from the stdout output of the program.
Like this:
#include <stdio.h>
int main(void)
{
FILE *fp = popen("ls -lah /tmp", "r");
if(fp == NULL)
return 1;
char buffer[1024];
int linecnt = 0;
while(fgets(buffer, sizeof buffer, fp))
printf("Line: %d: %s", ++linecnt, buffer);
putchar('\n');
fclose(fp);
return 0;
}
which outputs:
$ ./b
Line: 1: total 108K
Line: 2: drwxrwxrwt 8 root root 12K Mar 10 02:30 .
Line: 3: drwxr-xr-x 26 root root 4.0K Feb 15 01:05 ..
Line: 4: -rwxr-xr-x 1 shaoran shaoran 16K Mar 9 22:29 a
Line: 5: -rw-r--r-- 1 shaoran shaoran 3.6K Mar 9 22:29 a.c
Line: 6: -rw------- 1 shaoran shaoran 16K Mar 9 22:29 .a.c.swp
Line: 7: -rwxr-xr-x 1 shaoran shaoran 11K Mar 10 02:30 b
Line: 8: -rw-r--r-- 1 shaoran shaoran 274 Mar 10 02:30 b.c
Line: 9: -rw------- 1 shaoran shaoran 12K Mar 10 02:30 .b.c.swp
Line: 10: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:08 firefox_shaoran
Line: 11: drwxrwxrwt 2 root root 4.0K Mar 9 20:06 .ICE-unix
Line: 12: srwx------ 1 mongodb mongodb 0 Mar 9 20:07 mongodb-27017.sock
Line: 13: prwx------ 1 shaoran shaoran 0 Mar 9 20:08 oaucipc-c2s-1874
Line: 14: prwx------ 1 shaoran shaoran 0 Mar 9 20:08 oaucipc-s2c-1874
Line: 15: drwxrwxr-x 2 root utmp 4.0K Mar 9 20:06 screen
Line: 16: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:07 ssh-XueH0w8zWCSE
Line: 17: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:08 thunderbird_shaoran
Line: 18: -r--r--r-- 1 root root 11 Mar 9 20:07 .X0-lock
Line: 19: drwxrwxrwt 2 root root 4.0K Mar 9 20:07 .X11-unix
If you need more control and want also to read stderr, then you would have to create pipes for stdout and stderr,
make a fork and the child dup2 the pipes to stderr & stdout and
then execute exec (or any other function of that family) to execute the
program.
Like this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
int stdout_pipe[2];
int stderr_pipe[2];
pipe(stdout_pipe);
pipe(stderr_pipe);
pid_t pid = fork();
if(pid < 0)
return 1;
if(pid == 0)
{
// closing reading ends and duplicating writing ends
close(stdout_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
close(stderr_pipe[0]);
dup2(stderr_pipe[1], STDERR_FILENO);
execlp("ls", "ls", "-alh", "a.c", "kslkdl", NULL);
exit(1);
}
// closing writing end
close(stdout_pipe[1]);
close(stderr_pipe[1]);
int status;
if(waitpid(pid, &status, 0) < 0)
{
fprintf(stderr, "could not wait\n");
return 1;
}
if(WIFEXITED(status) == 0)
{
fprintf(stderr, "ls exited abnormally\n");
close(stdout_pipe[0]);
close(stderr_pipe[0]);
return 1;
}
puts("STDOUT:");
char buffer[1024];
ssize_t len;
while((len = read(stdout_pipe[0], buffer, sizeof(buffer) - 1)) > 0)
{
buffer[len] = 0;
printf("%s", buffer);
}
putchar('\n');
close(stdout_pipe[0]);
puts("STDERR:");
while((len = read(stderr_pipe[0], buffer, sizeof(buffer) - 1)) > 0)
{
buffer[len] = 0;
printf("%s", buffer);
}
putchar('\n');
close(stderr_pipe[0]);
return 0;
}
which outputs:
$ ./b
STDOUT:
-rw-r--r-- 1 shaoran shaoran 3.6K Mar 9 22:29 a.c
STDERR:
ls: cannot access 'kslkdl': No such file or directory
Pablo's answer is correct, you need to use pipe(7)-s.
And you could probably use GTK & Glib's g_spawn_async_with_pipes (which is based on pipe and fork and execve on Linux) for that (instead of fork or popen). In a GTK interactive program, it is better than the usual popen because the forked program would run concurrently with your event loop.
You could even consider using g_source_add_unix_fd on the (or on some) of the pipe fd-s given by pipe(2) or by g_spawn_async_with_pipes which use that pipe(2) call. But you might prefer g_io_channel_unix_new and g_io_add_watch
Be aware that the GTK main loop (and Gtk Input and Event Handling Model), i.e. GtkApplication and the related g_application_run or the older gtk_main are an event loop around some multiplexing system call like poll(2) (or the older select(2)) and you probably need that loop to be aware of your pipes. When some data arrives on the pipe, you probably want to read(2) it (and then call some GtkTextBuffer insert function).
You should make design choices: do you want the GUI interface and the other process to run concurrently? Or is the other exe process always so quick and with a small output (and no input) that you might just use popen?
On current GUI applications, the event loop should run quickly (at least 30 or 50 times per second) if you want a responsive GUI app.
Look also for inspiration inside the source code of some existing free software GTK application (e.g. on github or from your Linux distro).
I have a program that seems to be hanging in the parent process. It's a mock bash program that accepts commands like bash, and then operates them. The code is below. (Note this is simplified code without error checking so it would be more easily readable. Assume its all properly nested inside main function)
#define MAX_LINE 80
char *args[MAX_LINE/2 + 1];
while(should_run){
char *inputLine = malloc(MAX_LINE);
runConcurrently = 0; /*Resets the run in background to be line specific */
fprintf(stdout, "osh> "); /*Command prompt austhetic */
fflush(stdout);
/*User Input */
fgets(inputLine, MAX_LINE, stdin);
/*Reads into Args array */
char *token = strtok(inputLine, " \n");
int spot = 0;
while (token){
args[spot] = token;
token = strtok(NULL, " \n");
spot++;
}
args[spot] = NULL;
/* checks for & and changes flag */
if (strcmp(args[spot-1], "&") == 0){
runConcurrently = 1;
args[spot-1] = NULL;
}
/* Child-Parent Fork Process */
pid_t pid;
pid = fork(); /*Creates the fork */
if (pid == 0){
int run = execvp(args[0], args);
if (run < 0){
fprintf(stdout, "Commands Failed, check syntax!\n");
exit(1);
}
}
else if (pid > 0) {
if (!runConcurrently){
wait(NULL);
}
}
else {
fprintf(stderr, "Fork Failed \n");
return 1;
}
}
The problem here has to do with when I use an '&' and activate the run concurrently flag. This makes it so the parent no longer has to wait, however when I do this I lose some functionality.
Expected output:
osh> ls-a &
//Outputs a list of all in current directory
osh>
So I want it to run them concurently, but give control of the terminal back to me. But instead I get this.
Actual Result:
osh> ls -a &
//Outputs a list of all in current directory
<---- Starts a new line without the osh>. And stays like this indefinitely
And if I type something into this blank area the result is:
osh> ls -a &
//Outputs a list of all in current directory
ls -a
//Outputs a list of all in current directory
osh> osh> //I get two osh>'s this time.
This is my first time working with split processes and fork(). Am I missing something here? When I run it concurrently should I be choosing processes or something like that? Any help is welcome, thanks!
Your code actually works fine. The only problem is, you spit out the prompt "too quickly", and the new prompt appears before the command output. See a test output here:
osh> ls -al &
osh> total 1944 --- LOOK HERE
drwxrwxrwt 15 root root 4096 Feb 15 14:34 .
drwxr-xr-x 24 root root 4096 Feb 3 02:13 ..
drwx------ 2 test test 4096 Feb 15 09:30 .com.google.Chrome.5raKDW
drwx------ 2 test test 4096 Feb 15 13:35 .com.google.Chrome.ueibHT
drwx------ 2 test test 4096 Feb 14 12:15 .com.google.Chrome.ypZmNA
See the "LOOK HERE" line. The new prompt is there, but ls command output appears later. Your application is responsive to new commands, even though the prompt is displayed before command output. You can verify all this by using a command that does not produce any output, for example
osh> sleep 10 &
Hannu
I am creating a file in read/write mode and writing a string into it. Then I am trying to read it into a buffer where I get read error.
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd,count,fd1;
char buf[10];
fd=creat("./smarak",S_IRWXU);
if(fd<0)
{
perror("creat");
}
count=write(fd,"Hello smarak",7);
printf("count=%d\n",count);
count=read(fd,buf,7);
printf("buf=%s\n",buf);
printf("%d\n",count);
}
I get nothing in buf and also count is -1 which is read error. Why this error? Isn't it possible to read a file created by creat() system call?
You need to reposition between writing and reading:
count=write(fd,"Hello smarak",7);
printf("count=%d\n",count);
// added:
if ( lseek( fd, 0, SEEK_SET ) < 0 )
{
perror("lseek");
}
count=read(fd,buf,7);
printf("buf=%s\n",buf);
printf("%d\n",count);
After your write, the current position in the file is right after what you have written. If you want to read that back in, you have to "rewind" the current position to the beginning of the file.
Check man lseek for details.
And I don't know how Unix calls handle this, but the C standard (C99, 7.19.5.3 The fopen function, section 6) has this to say:
[...] output shall not be directly followed by input without an
intervening call to the fflush function or to a file positioning
function (fseek, fsetpos, or rewind), and input shall not be directly
followed by output without an intervening call to a file positioning
function, unless the input operation encounters end-of-file.
So you might be looking at undefined behaviour in your code sample.
use lseek() function to set the position to the specified.
Try to use open() system call instead of creat() system call.
When you use creat() it will open the process as
root#Lenovo-G585:/proc/6988/fd$ ls -la
total 0
dr-x------ 2 root root 0 Sep 18 16:20 .
dr-xr-xr-x 8 root root 0 Sep 18 16:20 ..
lrwx------ 1 root root 64 Sep 18 16:20 0 -> /dev/pts/4
lrwx------ 1 root root 64 Sep 18 16:20 1 -> /dev/pts/4
lrwx------ 1 root root 64 Sep 18 16:20 2 -> /dev/pts/4
l-wx------ 1 root root 64 Sep 18 16:20 3 -> /tmp/smarak
^
Look ^ here.
The read permission is missing so you cannot able to read from that file.
If you use open() system call like
fd=open("./smarak",O_CREAT|O_RDWR);
O_CREAT - Which is used to create a new file if doesn't exist.
O_RDWR - Which is used to open a file for read and write mode.
By using open with the given argument, you can do your requirement.
When using creat() it will open the file in O_CREAT|O_WRONLY|O_TRUNC.
O_TRUNC - Which is used to truncate remove the file content and keep
the cursor position in start of file.
Note: While using creat() it will truncate the file if already exist.
I'm working on setting up a basic CTF for my school and one of the challenges is to simply analyze the ASM (x86) of a binary, figure out how it works, and break it. This one is simple: push 37 arguments to it, you get escalted to a 'flag' user that reads the flag in the directory, and you get points.
However for some reason I get segfaulted when it gets to reading the flag.
Heres the code:
void readflag()
{
setgid(1401);
char ch;
FILE *fp;
fp=fopen("argcimapirate.flag", "r");
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
fclose(fp);
}
int main(int argc, char* argv[])
{
printf("ARRRRRRR!\n");
if (argc == 37)
{
printf("Shiver me timbers...\n");
readflag();
}
return 0;
}
Also, this is the output of ls -l to see the permissions.
-r-sr-s--- 1 argcimapirate argcimapirate 8811 Jul 13 15:58 argcimapirate
-r-------- 1 root root 335 Jul 13 15:58 argcimapirate.c
-r--r----- 1 flag flag 17 Jul 11 21:12 argcimapirate.flag
Any ideas, let me know. Thanks!
I've solved it guys.
Turns out that the flag user needs to own the file in order for the setuid/setgid to escalate to a point where the user can read files that flag owns.