I have been stuck with this problem on and off since last night and I'm hoping a second fresh pair of eyes will help.
The problem, if an invalid input is entered in the userIn function (anything that isn't a number between 1-99) the test printf at the end of the while loop in main prints "ERR = 1", the while loops and userIn is called again. So far so good, but when a valid input is entered the test printf at the end of the while loop prints "ERR = 0" and then the program hangs. The test printf saying "HELLO" never gets printed.
Any suggestions as to why are most welcome.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void userIn (int *x)
{
char b;
printf("Please enter a new value for Vm: ");
scanf(" %i",x);
while (((b=getchar())!='\n')&&(b!=EOF));
return;
}
int main (void)
{
int fd, x, err;
char *npipe = "/tmp/fms",
input[3];
struct stat info;
printf("\n");
//get user input
err = 1;
while (err)
{
userIn(&x);
if (x > 0 && x < 100) err = 0;
//else printf("\033[1A\033[K");
printf("ERR = %i\n",err);//TEST PRINTF
}
printf("HELLO");//TEST PRINTF
//if pipe exists
if ( (!lstat(npipe,&info)) && (S_ISFIFO(info.st_mode)) )
{
sprintf(input,"%i",x);
//write user input to named pipe created by 'parent.c'
fd = open(npipe, O_WRONLY);
write(fd, input, sizeof(input));
close(fd);
}
else printf("\033[0;31mNamed pipe doesn't exist, %i not passed.\n\n\033[0m",x);
return 0;
}
Contrary to your intuition, the program freezes somewhere after the printf("HELLO"); line. Since you don't have a newline in that printf, HELLO gets buffered up and is not flushed to the terminal immediately.
Is there a process reading from the other end of that pipe of yours?
If I run your code on my system the output looks like this:
Please enter a new value for Vm: 101
ERR = 1
Please enter a new value for Vm: 1
ERR = 0
HELLONamed pipe doesn't exist, 1 not passed.
That is, the loop exits exactly when you think it should. Of course, the code then exits immediately because /tmp/fms does not exist on my system.
However, if I create /tmp/fms, then I see:
Please enter a new value for Vm: 1
ERR = 0
...and no additional output. This is because the output from the printf statement is buffered, and the write to the named pipe is blocking, so the output never gets flushed. Adding a \n to your printf will probably display it as you expect.
Related
I want to output the ASCII Code of the last key I pressed, every x second.
As example:
If i press a(97), the terminal should show the 97 every x second. When I now press the w(119), the program now should print the 119 instead of the 97.
So far my program just prints the first key I've pressed.
Here are the main and the other method:
int main(int argc, char const *argv[]){
printf("Hello World!");
while(1){
movePlayer();
fflush(stdout);
sleep(1);
}
return 0;
}
void movePlayer(){
system("/bin/stty raw");
int input = getchar(); //support_readkey(1000);
//fprintf(stdout, "\033[2J");
//fprintf(stdout, "\033[1;1H");
printf("\b%d",input);
system("/bin/stty cooked");
}
EDIT:
With a little bit of testing i've now a method which solves my problem
int read_the_key(int timeout_ms) {
struct timeval tv = { 0L, timeout_ms * 1000L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
int r = select(1, &fds, NULL, NULL, &tv);
if (!r) return 0;
return getchar();
}
getchar() waits for only one character, so this:
while(1){
movePlayer(); // getchar() and printf() here
fflush(stdout);
sleep(1);
}
causes this behavior. You read one character, you print it in movePlayer(). Then you flush the output buffer and go to sleep. Then you just repeat, which means that you have to input again.
Store the input and print it again, if you wish. However, your function will always wait for new input to arrive.
Here is an attempt with read() as suggested, but it will have similar behavior to your code as it is now:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int old_c = -1;
char c[1] = {0};
void movePlayer();
int main(int argc, char const *argv[]){
while(1) {
movePlayer();
fflush(stdout);
sleep(1);
}
return 0;
}
void movePlayer(){
system("/bin/stty raw");
if(read(STDIN_FILENO, c, sizeof(c)) > 0)
old_c = (int)c[0];
if(old_c == -1)
old_c = (int)c[0];
printf("\b%d", old_c);
system("/bin/stty cooked");
}
Please read read() from stdin to go on. You can tell read() for how many characters to wait and then return, but how will you know if the user intends to input a new character to command read() to wait for user's input?
As a result, I would say that you can not do what you wish, at least as far as I can tell, with a simple approach. You could have your program feed the stale input to stdin, so that your program has the impression it reads user's input. However, in case the user actually inputs fresh input, your program should handle that case carefully.
You can setup SIGALARM handler, setup alarm after x seconds and display what getchar returns in handler
I've written the following program, that simulates the work of semaphore. There are three functions: lock, unlock, lockpath.
lock = opens the file; checks if the file already exists, and if it does, puts the current process to sleep. If the file didn't exist, it is created and TRUE is returned.
unlock = deletes the file
lockpath = returns the path name corresponding to the file that might be created.
Here's the source code:
#include <unistd.h>
//exit();
#include <stdlib.h>
//errno
#include <errno.h>
//creat(..)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//strcat, strcpy
#include <string.h>
//For err_sys
#include <stdio.h>
#define LOCKDIR "/tmp/"
#define MAXTRY 3
#define WAITTIME 5
enum BOOLEAN{TRUE, FALSE};
void err_sys(const char* x) {
perror(x);
exit(1);
}
static char* lockpath(char* name) {
static char path[20];
strcpy(path, LOCKDIR);
return (strcat(path, name));
}
int lock(char* name) {
char *path;
int fd, incerc;
extern int errno;
path = lockpath(name);
int try = 0;
while ((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0
&& errno == EEXIST) {
if (++try >= MAXTRY)
return FALSE;
sleep(WAITTIME);
}
if (fd < 0 || close(fd) < 0)
err_sys("lock");
return TRUE;
}
void unlock(char* name) {
if (unlink(lockpath(name)) < 0)
err_sys("unlock");
}
int main(void) {
pid_t child_process;
child_process = fork();
char* sem_file_name = "test_semaf";
if (child_process != 0)
{
printf("\nParent process ID: %d", getpid());
}
else
{
printf("\nChild process ID: %d", getpid());
}
if (lock(sem_file_name))
{
printf("\nProcess with ID: %d", getpid());
printf("\nonly, has access to %s", strcat(LOCKDIR, sem_file_name)); //****
unlock(sem_file_name);
} else {
printf("\nProcess with ID: %d", getpid());
printf("\nwas unable to get access to %s", strcat(LOCKDIR, sem_file_name));
}
return 0;
}
The line at which the program stops is marked with: ****
The error is:
Program received signal SIGSEGV, Segmentation fault.
__strcat_ssse3 () at ../sysdeps/x86_64/multiarch/strcat-ssse3.S:571
571 ../sysdeps/x86_64/multiarch/strcat-ssse3.S: No such file or directory.
The problem is that I get Segmentation Fault, and can't find where's the problem. To me, everything's fine. A process is supposed to create file X. Then, if another process tries to create it's own file X, it is not allowed; the process is put to sleep. This second process is allowed to make MAXTRY attempts. If it does not succeed after MAXTRY attempts, the lock() function returns FALSE. Finally, when a process, that has successfully created his own X file, doesn't need it now, the file X is deleted.
Can you, please, tell what do you think is the problem with this program? Thank you in advance.
EDIT :
Here's the link to the page that explains why lockpath() function isn't correct.
Is returning a pointer to a static local variable safe?
This is the cause of your crashes:
strcat(LOCKDIR, sem_file_name)
Here you try to append to a literal string constant.
You should use the lockpath function here as well.
The problem seems to be in your misunderstanding of strcat() function. The function appends string in second parameter to the string in first parameter - but you need to ensure there is enough space for the data. Read the man page.
That means that
char * dest = "whatever";
strcat(dest, anything_else);
is always wrong. What you want is
char dest[SIZE] = "whatever";
strcat(dest, anything_else);
where SIZE is big enough for the buffer to be able to contain the whole concatenated string.
Also, your lockpath() function is broken. See this answer to learn why. You need to create the dest buffer outside the lockpath() function and pass it to it as a parameter.
I am trying to exploit a SUID program.
The program is:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }
void print(unsigned char *buf, int len)
{
int i;
printf("[ ");
for(i=0; i < len; i++) printf("%x ", buf[i]);
printf(" ]\n");
}
int main()
{
unsigned char buf[512];
unsigned char *ptr = buf + (sizeof(buf)/2);
unsigned int x;
while((x = getchar()) != EOF) {
switch(x) {
case '\n': print(buf, sizeof(buf)); continue; break;
case '\\': ptr--; break;
default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
}
}
printf("All done\n");
}
We can easily see that if we somehow change ptr's contents to some address that starts with CA then a new shell will be spawned for us. And as ptr normally holds some address starting with FF the way to decrease it(ptr) is to enter \ character. So I make a file with 0x35000000 '\' characters, and finally 3 'a' at the end of the file
perl -e "print '\\\'x889192448" > file # decimal equivalent of 0x35000000
echo aaa > file # So that e() is called which actually spawns the shell
And finally in gdb,
run < file
However instead of spawning a shell gdb is saying
process <some number> is executing new program /bin/dash
inferior 1 exited normally
And then back to gdb prompt instead of getting a shell.
I have confirmed by setting breakpoints at appropriate locations that ptr is indeed starting with CA before setresuid() gets called.
Also if I pipe this outside of gdb, nothing happens.
./vulnProg < file
Bash prompt returns back.
Please tell me where am I making mistake.
You can see the problem by compiling a simpler test program
int main() { execlp("/bin/sed", "-e", "s/^/XXX:/", NULL); }
All this does is start a version of sed (rather than the shell) and converts input by prepending "XXX:".
If you run the resulting program, and type in the Terminal you get behaviour like this:
$./a.out
Hello
XXX:Hello
Test
XXX:Test
^D
Which is exactly as we'd expect.
Now if you feed it input from a file containing "Hello\nWorld" you get
$./a.out < file
XXX:Hello
XXX:World
$
And the application exits immediately, with the input stream to the application being closed when the input file has all been read.
If you want to provide additional input, you need to use a trick to not break the input stream.
{ cat file ; cat - ; } | ./a.out
This will put all the input from file into a running ./a.out and then
read from stdin and add that too.
$ { cat file ; cat - ; } | ./a.out
XXX:Hello
XXX:World
This is a Test
XXX:This is a Test
I want to fulfill the following things in a console application:
If user inputs a character, the application will do the
corresponding task. For example, if user inputs 1, the program
will do task 1, if user inputs q, the program will quit;
If user inputs nothing, the program will do the default task every 10 seconds (the time needn't to be very strict).
Here is my code:
#include <stdio.h>
#include <time.h>
char buff[64];
char command;
while(command != 'q')
{
begin:
printf(">> ");
scanf("%s", buff);
command = buff[0];
switch (command)
{
case '1':
// task 1 code will be added here;
break;
case '2':
// task 2 code will be added here;
break;
case 'q':
printf("quit the loop.\n");
break;
}
// wait for 10 seconds;
Sleep(10000);
// default task code will be added here;
if(command != 'q')
{
goto begin;
}
}
But the problem is the program will trap at the line of scanf() function forever to wait for an input character, if no character is entered. So I'm wondering how to skip the line of scanf() after a certain time, I mean for example, if no input after 1 second, the program can continue, so as to fulfill the second thing listed above.
The platform is Windows, if it matters.
I've removed the semicolon after the while() it was an obvious mistake.
Try using the select() function. Then you can wait for 10 seconds until you can read from stdin without blocking. If select() returns with zero, perform the default action.
I don't know if this works on windows, it's POSIX standard. If you happen to develop on unix/linux, try man select
I just wrote a working example using select:
#include <stdlib.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define MAXBYTES 80
int main(int argc, char *argv[])
{
fd_set readfds;
int num_readable;
struct timeval tv;
int num_bytes;
char buf[MAXBYTES];
int fd_stdin;
fd_stdin = fileno(stdin);
while(1) {
FD_ZERO(&readfds);
FD_SET(fileno(stdin), &readfds);
tv.tv_sec = 10;
tv.tv_usec = 0;
printf("Enter command: ");
fflush(stdout);
num_readable = select(fd_stdin + 1, &readfds, NULL, NULL, &tv);
if (num_readable == -1) {
fprintf(stderr, "\nError in select : %s\n", strerror(errno));
exit(1);
}
if (num_readable == 0) {
printf("\nPerforming default action after 10 seconds\n");
break; /* since I don't want to test forever */
} else {
num_bytes = read(fd_stdin, buf, MAXBYTES);
if (num_bytes < 0) {
fprintf(stderr, "\nError on read : %s\n", strerror(errno));
exit(1);
}
/* process command, maybe by sscanf */
printf("\nRead %d bytes\n", num_bytes);
break; /* to terminate loop, since I don't process anything */
}
}
return 0;
}
Note: the poll() example below is OK too, no problem. For the rest I chose to read the available bytes into a buffer (up to MAXBYTES). It can be (s)scanned afterwards. (scanf() just isn't too much my friend, but that's a personal taste matter).
Here is a working example of how to do this with poll (probably the most 'correct' way on Linux):
#include <unistd.h>
#include <poll.h>
#include <stdio.h>
int main()
{
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
char string[10];
if( poll(&mypoll, 1, 2000) )
{
scanf("%9s", string);
printf("Read string - %s\n", string);
}
else
{
puts("Read nothing");
}
return 0;
}
The timeout is the third argument to poll and is in milliseconds - this example will wait for 2 seconds for input on stdin. Windows has WSAPoll, which should work similarly.
But the problem is the program will trap at the line of scanf() function forever to wait for an input character,
Remove the semicolon after while.
Try alarm(3)
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char buf [10];
alarm(3);
scanf("%s", buf);
return 0;
}
As others have said, the best way to do truly async IO is with select(...).
But a quick and dirty way to do what you want is with getline(...) which will return the number of bytes read every time (not hanging on IO) and returns -1 on no bytes read.
The following is from the getline(3) man page:
// The following code fragment reads lines from a file and writes them to standard output.
// The fwrite() function is used in case the line contains embedded NUL characters.
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, fp)) > 0)
fwrite(line, linelen, 1, stdout);
Unfortunately, what you are asking for is not possible in plain ISO C. However, most platforms offer platform-specific extensions which provide the functionality that you require.
Since you stated that your question applies to Microsoft Windows, the two functions that you are looking for are WaitForSingleObject and ReadConsoleInput. You won't be able to use the function scanf or C-style streams (FILE*) for this.
The function WaitForSingleObject allows you to wait until a specific object is in a signalled state. It also allows you to set a timeout (which should be 10 seconds in your case).
One type of object that WaitForSingleObject can wait for is a console handle. It will be in a signalled state when there is new input available to be read by ReadConsoleInput. According to my tests, it won't work reliably with ReadConsole though, because even if WaitForSingleObject indicates that input is waiting, the function ReadConsole will still sometimes block. This is because in contrast to ReadConsoleInput, the function ReadConsole will filter some events. Therefore, attempting to read one event with ReadConsole may actually attempt to read more than one raw event, which will cause the function to block if there are no non-filtered raw events available. The function ReadConsoleInput does not have this problem, as it works with raw events directly and does not filter any.
Here is my program which uses the functions mentioned above, and does exactly what you asked for.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void DoDefaultTask()
{
printf( "Doing default task.\n" );
}
void DoTask1()
{
printf( "Doing task #1.\n" );
}
void DoTask2()
{
printf( "Doing task #2.\n" );
}
int main(void)
{
INPUT_RECORD ir;
HANDLE hConInput = GetStdHandle(STD_INPUT_HANDLE);
DWORD dwReadCount;
bool should_prompt = true, quit = false;
while ( !quit )
{
//prompt user for input
if ( should_prompt )
{
printf( "Please select an option: " );
should_prompt = false;
}
//flush output
fflush( stdout );
switch ( WaitForSingleObject( hConInput, 10000 ) )
{
case WAIT_OBJECT_0:
//attempt to read input
if ( !ReadConsoleInput( hConInput, &ir, 1, &dwReadCount ) || dwReadCount != 1 )
{
fprintf( stderr, "Unexpected input error!\n" );
exit( EXIT_FAILURE );
}
//only handle key-down events
if ( ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown )
break;
//echo output, if character is printable
if ( isprint( (unsigned char)ir.Event.KeyEvent.uChar.AsciiChar ) )
{
printf( "%c", ir.Event.KeyEvent.uChar.AsciiChar );
}
printf( "\n" );
switch ( ir.Event.KeyEvent.uChar.AsciiChar )
{
case '1':
DoTask1();
break;
case '2':
DoTask2();
break;
case 'q':
printf( "Quitting program...\n" );
quit = true;
break;
default:
printf( "Unknown command.\n" );
}
should_prompt = true;
break;
case WAIT_TIMEOUT:
printf( "Timeout!\n" );
DoDefaultTask();
should_prompt = true;
break;
default:
fprintf( stderr, "unexpected error!" );
exit( EXIT_FAILURE );
}
}
return 0;
}
This program has the following behavior:
Please select an option: 1
Doing task #1.
Please select an option: 2
Doing task #2.
Please select an option: 3
Unknown command.
Please select an option: 4
Unknown command.
Please select an option: Timeout!
Doing default task.
Please select an option: Timeout!
Doing default task.
Please select an option: 1
Doing task #1.
Please select an option: 3
Unknown command.
Please select an option: 2
Doing task #2.
Please select an option: 1
Doing task #1.
Please select an option: Timeout!
Doing default task.
Please select an option: q
Quitting program...
Tried to create shared memory block, and what I got is strange behaviour.
#include <sys/shm.h>
#include "stdio.h"
#include <sys/ipc.h>
int main() {
printf("starting\n");
int mid = -1;
mid = shmget((key_t)1234, 4096, IPC_CREAT|0666);
if(mid == -1) {
printf("cant get mid\n");
return 1;
} else {
printf("got mid");
}
int* maddr = 0;
maddr = shmat(mid, NULL ,0);
if(maddr == (int*)-1) {
printf("cant attach memory\n");
return 1;
} else {
printf("got maddr");
}
while(1) {
int cval = __sync_add_and_fetch(maddr, 1);
if(cval % 2) { // odd values
printf("messager 1");
sleep(1000);
}
}
}
If I try to execute that code, it prints starting and hangs, nothing more happens, but some why it accepts input from stdin, so I can print just like if scanf is running
stdout is line-buffered by default, which means that it is not flushed until a newline is printed. This means that you need to put \n at the end of your "got mid", "got maddr" and "messager 1" strings, or fflush(); after those printf()s.
By the way, SYSV shared memory is outdated. The POSIX mechanisms are significantly better designed - see shm_open() and related calls.
Try adding a new line (\n) at the end of all of your printf statements. I assume it's failing before printing/flushing the buffer.
You can enter things in because the terminal is not blocking keystrokes, even though you haven't paused anywhere to read it. I regularly type in the "next thing" while my command-line/terminal is busy doing something else so that it just picks up when it's done. The stdin buffer can still accept the input. It just doesn't use it yet.