Make a file to act as tty with dup - c

Okay, so I have a problem. I must get the output of a program using the execlp and make the output go directly to a file. The problem is that the program only outputs certain information if it's running in a tty,(I guess it calls isatty(3)).
Here is my code so far
void main(){
int fd = open("file", O_WRONLY | O_CREAT | O_TRUNC, 0755);
close(1);
dup(fd);
execlp("program","program",NULL);
close(fd);
}
I don't want to use OS commands like script (which works) or so on.
So the question is, how can I "trick" the program into thinking that it is writing into a tty?

Use a "pty" (Pseudo Terminal) as output. see this question for details.
Rachid Koucha wrote a lengthy article explaining the details how to work with ptys: Using pseudo-terminals (pty) to control interactive programs
Stop reading This text here just exists to stop the stupid SO algorithm to turn my answer into a comment. I hate it when software makes itself smarter than me :-(

Related

What are `open()` default permissions at file creation? [duplicate]

This question already has answers here:
Why does open() create my file with the wrong permissions?
(7 answers)
Closed 5 years ago.
I made a little project some weeks ago, but it somehow didn't work anymore recently (or at least, not like it previously worked).
It had to create a file with open(), and fill it with some content.
[...]
int fd=open(filename, O_RDWR | O_CREAT);
/* write content */
close(fd);
[...]
The problem was just that it recently didn't create the file with the right permissions anymore (it was created with 0110 when the problem was occurring)
I now know that I just have to specify the permissions like this :
int fd=open(filename, O_RDWR | O_CREAT, 0700); /* (for instance) */
But the project still worked on some computers (Didn't work on OSX, but did work on a Linux, on which it was created with 0640, so it still worked because I still had reading permission).
So here is my question:
How are those default permissions defined for open() function at file creation?
(If I don't explicitly pass it to my open() call as a parameter.)
There is no default. You must specify them when you use O_CREAT.
According to the documentation on my system,
[The mode] argument must be supplied when O_CREAT is specified in flags
(Emphasis mine)
This makes it sound like it's undefined behaviour when you don't, and I do indeed get junk when I omit it (--wS--S--T).
You need to specify the mode arguments as an integer containing a set of bit flags. Something like:
int fd=open(filename, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG);
See the man page for chmod. The call also uses the process umask to limit things.

writing STDIN of bash application from c program

I would like to open an bash application(prog1) and send command to that application with C program.
I tried and wrote the following code.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
FILE * fp;
char message[10] = "command1\n";
fp = popen("sudo prog1","r");
write(STDIN_FILENO, message, 10);
pclose(fp);
execlp("sudo prog1", "sudo prog1", "-l", NULL);
return 0;
}
This code gives an output:
Linux:~$ ./ prog 2 // running the code
command // prints "command"
prog1-> // Then opens "prog1" (prog1 waits for user commands)
But I want it to be
Linux:~$ ./ prog 2 // running the code
prog1-> command // open "prog1" and write command (instead of getting it from user)
It either writes after quitting prog1 or before starting prog1. Please let me know how to write the "command" in prog1, after opening the application prog1. Thank you.
Note: If I make
fp = popen("sudo prog1","w"); //to write
It throws the following error
tcgetattr : Inappropriate ioctl for device
Your main bug is thinking that popen() somehow associates your child process with your STDIN_FILENO. It doesn't. STDIN_FILENO is not associated with your "sudo prog1" child. You'd have to create a pipe, dup the descriptors to stdin/stdout, and fork+exec to do that. But you used popen() so don't do that either.
Instead, you should be writing and reading from fp.
Something like:
fprintf(fp, message);
fgets(response, 100, fp);
Since fprintf() is buffered, you should use \n at the end of the line, or fflush().
Also, there is no point is using exec/execlp at the end when you've already called popen(). Looks like you may be mixing two approaches that you've seen by example.
popen() essentially does a combination of (pipe, dup stdin/stdout/stderr, fork, execl) to take care of redirecting a child process to a file stream connected to the parent. So no need to reimplement unless you need different semantics than popen().
You technically are implementing "expect" functionality, so you might want to look into expect, or expect modules for different languages. Expect is included with Linux distributions but is usually optional.
http://expect.sourceforge.net/
http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod
And not to mention, Perl has a Sudo module already.
http://search.cpan.org/~landman/Sudo-0.21/lib/Sudo.pm

How to lock files correctly in ANSI C

I am writing an ANSI C cgi-bin server program.
Each instance of program can access to the same files simultaneously.
I do as follows:
handle = fopen(name,type);
fd = fileno(handle);
MyLockFile(fd) //I use fcntl
.....
The problem is that I open file with "fopen", not with "open".
Will "locking" work in such manner?
I can lock "fd", not "handle".
The reason is that I can't write workable "fd=open..." code.
My code below creates the executable file, write permissions were not set.
I don't know why
fd = open(name,O_CREAT|O_WRONLY|S_IREAD|S_IWRITE|S_IRGRP|
S_IWGRP|S_IROTH|S_IWOTH);
write(fd,data,strlen(data));
close(fd);
I can neither write nor append to this file.
Your open() function is wrong, when you specify O_CREAT, the permission bits needs to be the 3. argument, e.g.
open(name,O_CREAT|O_WRONLY,
S_IREAD|S_IWRITE|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);

C /sys/class/pwm init within a program

So you can see in this link that you have a pwm /sys/class/pwm/.
So I am currently putting the right data into the appropriate files and things are working well.
That is not the issue. The issue is that you need to do a "cat" on the /sys/class/pwm/{port}/request file before it becomes active. So if you reboot it will not work and you have to re-initiate it.
I have tried to just fopen("~request","r") hoping it would work but it doesn't. Opening it for "w" either. I also tried doing an exec() but that didn't work and is clunky anyhow. I don't want to have to make the assumptions required.
Here is my execv() code anyhow.
char *request[1];
request[0] = pwmbus;
execv("/bin/cat",request);
What is the most elegant way to cat the file? I din't need the information it outputs. It just initializes the sysfs. Otherwise I will be stuck having to manually do this or scripting it all the time.
cat /sys/class/pwm/gpio_pwm.0:0/request
sysfs 719
You can read one byte from the file:
int fd = open("/sys/class/pwm", O_RDONLY);
char buf[1];
read(fd, buf, 1);
close(fd);

Extracting dos command output in C

Using system() or exec(), I can get any command to execute but they display the result into the Console. I want to execute the command and extract the output and process it, and then display it. How can I achieve this on Windows/DOS Platform?
There's nothing like that in standard C, but usually, for compatibility with POSIX, compilers implement popen (_popen in VC++), which starts a command (as it would do with system) and returns a FILE * to the stream you asked for (you can ask for stdout if you want to read the output or stdin if you want to give some input to the program).
Once you have the FILE *, you can read it with the usual fread/fscanf/..., like you would do on a regular file.
If you want to have both input and output redirection things start to get a bit more complicated, since Windows compilers usually do have something like POSIX pipe, but it isn't perfectly compatible (mostly because the Windows process creation model is different).
In this case (and in any case where you need more control on the started process than the plain popen gives you) I would simply go with the "real" way to perform IO redirection on Windows, i.e. with CreateProcess and the appropriate options; see e.g. here.
Matteo Italia's answer is awesome. But some compilers (especially older ones) don't support popen().
If popen() is not supported, here's a possible solution.
In DOS we can redirect the output to a temporary file using >.
Ex:
C:\> ipconfig > temp.txt
I can then open temp.txt in my C-code and then reprocess its content.
My C code for this will be something like:
system("ipconfig > temp.txt");
FILE *fp;
fp = fopen("temp.txt","r");
// //
//... Code for reprocessing can go here ...//
// //
Here's an alternative answer for those without popen that should work on most system. This code is not thread safe. I expect that this is not a significant limitation for most situation.
#include <stdio.h>
#include <process.h>
#include <io.h>
#include <sys\stat.h>
#include <assert.h>
int main()
{
int so = dup(1);
close(1);
int i = creat("output.txt", S_IWRITE);
assert(i == 1); // i should be 1...
system("dir");
close(i);
dup2(so, 1);
close(so);
}

Resources