#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
char *buffer = malloc(1024);
FILE* f = popen("ls", "r");
int byteReads = fread(buffer, 1, 1024, f);
fclose(f);
printf("%s\n", buffer);
return 0;
}
Ther are 2 folders ./parent/folder1 and ./parent/folder2 . ./main is in folder1, and I want it to execute ls in folder2 and get the result.
Not something that is specific to "ls", but that works for any commands in general.
How can I do it using popen()? Or do I have to use another command?
You could use popen as you use it in your question. You could pass the cmd you want to execute as argument to the program call, e.g. if your program is named myexecute the command line call would look like this:
myexecute folder2 'ls -l'
or
myexecute 'another folder' 'ls'
Please note the single quotes to get an argument if spaces are included in the argument.
With chdir you can change the current working directory. The output of the command can be read in a loop and output to the stdout.
Finally, with pclose, you would wait for the associated process to finish and it would even return the exit status of the executed command, just in case you are interested.
You code slightly modified could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if(argc != 3) {
fprintf(stderr, "usage: %s '<dir>' '<cmd>'\n", basename(argv[0]));
return EXIT_FAILURE;
}
if(chdir(argv[1]) != 0) {
perror(argv[1]);
return EXIT_FAILURE;
}
FILE *f = popen(argv[2], "r");
if (!f) {
perror("popen failed");
return EXIT_FAILURE;
}
char buf[1024];
while (fgets(buf, sizeof(buf), f)) {
printf("%s", buf);
}
if (pclose(f) != 0) {
perror("pclose failed");
}
return EXIT_SUCCESS;
}
Related
The manpage for popen says "reading from a "popened" stream reads the command's standard output".
However, I can't seem to get the subprocess output in the trivial program below. The "reader" parent process blocks on the read (whether using fgets or fread)
What am I missing?
Attaching to the pinger program with gdb shows it is looping and calling printf to output text. Just nothing detected by fgets on the parent's side...
PINGER.C
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int i = 0;
while (1)
{
printf("stdout %d\n", i++);
sleep(1);
}
}
POPENTEST.C
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
char *cmd = "./pinger";
printf("Running '%s'\n", cmd);
FILE *fp = popen(cmd, "r");
if (!fp)
{
perror("popen failed:");
exit(1);
}
printf("fp open\n");
char inLine[1024];
while (fgets(inLine, sizeof(inLine), fp) != NULL)
{
printf("Received: '%s'\n", inLine);
}
printf("feof=%d ferror=%d: %s\n", feof(fp), ferror(fp), strerror(errno));
pclose(fp);
}
OUTPUT
$ ./popenTest
fp open
By default, C buffers writes to the stdout when stdout is not connected to a tty. This means that from the OS' perspective, the program has not written anything to stdout until either the buffer is full or you manually flushed the output:
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int i = 0;
while (1)
{
printf("stdout %d\n", i++);
fflush(stdout);
sleep(1);
}
}
When connected to a tty, the stdout is automatically flushed on every newline. But this automatic flushing does not happen when the stdout is connected to a pipe.
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
I am now taking a security class. And the professor asked us to exploit a program to gain higher privilege.
This is the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFSIZE 512
int main(int argc, char *argv[]) {
struct stat buf;
char cmd[BUFSIZE];
FILE *f = NULL;
if (argv[1] == NULL) {
fprintf(stderr, "Please provide an argument\n");
exit(1);
}
if (stat(argv[1], &buf)) {
fprintf(stderr, "Can't stat the file\n");
exit(1);
}
if (buf.st_gid != getegid()) {
fprintf(stderr, "The file must be owned by group %d\n", getegid());
exit(1);
}
sleep(1);
if ((f = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open command file\n");
return 1;
}
while (fgets(cmd, BUFSIZE, f)) {
if ((cmd[0] == '\n') || (cmd[0] == 0x7f)) {
fprintf(stderr, "Found empty line, quitting!\n");
return 2;
}
system(cmd);
}
printf("Done!\n");
return 0;
}
The particular situation is:
There is a binary code for this program for us to run. And the SUID of the binary code is set to higher level(here I assume level2). However, buf.st_gid != getegid() will always check if the file we specified is owned by root. Most important thing is, I only have level1 privilege. There is only one file owned by level2 I can use which is provided by our professor. And I certainly tried to pass in that filename. But nothing happens. I don't know if there is anyway I can exploit this program.(To execute some commands during runtime using the privilege of level2)
I am trying to write a simple C PROGAM which EXECUTE a Python SCRIPT (and let it running...) and closes itself.
I tried the following commands but in both cases the C PROGRAM is still alive...
popen("sudo python /home/pi/main.py", "r");
system("sudo python /home/pi/main.py");
Thanks!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Edited !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
I tried this command based on your comments but no success:
char *argv[] = {"/home/pi/main.py"};
execv("sudo python", argv);
Anyone could help? Thanks!
!!!!!!!!!!! Edit 2 !!!!!!!!!!!!!!
This is how I compile it:
gcc -Wall restart.c -o safekill
This is the C program
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
my_popen(char cmd[])
{
FILE *fp;
char path[1035];
fp = popen(cmd, "r");
if (fp == NULL)
{
printf("Failed to run command\n");
exit(1);
}
//Read the output a line at a time - output it
while (fgets(path, sizeof(path)-1, fp) != NULL)
{
printf("%s", path);
}
pclose(fp);
}
int main()
{
my_popen("sudo killall python");
sleep(1);
my_popen("sudo killall raspivid");
sleep(1);
if(fork())
printf("Am I here?");
return 0;
char *file = "restart";
char *argv[] = {file, "-c", "sudo python main.py", NULL};
execvp(file, argv);
}
Result: It prints am I here and doesn't start the python.
It is so frustrating.... :-(
You need to add the filename of the program itself to the argument list (argv[0]) and terminate the argument list with a NULL pointer.
Example:
#include <stdlib.h>
#include <unistd.h>
int main() {
if(fork())
return 0;
char *file = "python";
char *argv[] = {file, "-c", "import time; time.sleep(5); print 'Hello'", NULL};
execvp(file, argv);
}
Expected behavior: Immediate (parent) program termination and a short Hello printed 5 seconds later by the child.
Maybe you need to workaround the sudo somehow, but this should get you started.
my code is pasted below.
I'm trying to use dup2 to redirect my output to file.
if I use it to redirect it works fine (if I remove the comments), output in file and not on stdout. ex: ls > test , results in ls outputting to test.
the problem is that ls, without the > doesn't output anything. If I leave the comments ls outputs just as it should, albeit with no ability to redirect.
redirect[0] is either < or > or nothing
redirect[1] is the path for the file to redirect to
command is is an array of cstrings with the pices of the command commands is as well
example output
with code commented
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1> ls
a.out myshell.c myshell.c~
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1>
with code uncommented
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1> ls
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1>
/*
if (!strcmp(redirect[0],">")){
if ((fd = open(redirect[1], O_RDWR | O_CREAT)) != -1)
dup2(fd, STDOUT_FILENO);
close(fd);
}
*/
if (command[0][0] == '/'){
int c = execv(command[0], commands);
if (c != 0){
printf("ERROR: command does not exist at path specified\n");
exit(0);
}
}
else if (!execv(path, commands)){
exit(0);
}
This code works, redirecting to file.out:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char *redirect[] = { ">", "file.out" };
char *command[] = { "/bin/ls", "-l", 0 };
if (!strcmp(redirect[0], ">"))
{
if ((fd = open(redirect[1], O_WRONLY | O_CREAT, 0644)) != -1)
{
fprintf(stderr, "Dupping stdout to %s\n", redirect[1]);
dup2(fd, STDOUT_FILENO);
close(fd);
}
}
if (command[0][0] == '/')
{
execv(command[0], command);
fprintf(stderr, "ERROR: command %s does not exist at path specified\n", command[0]);
return(1);
}
else
{
fprintf(stderr, "ERROR: not handling relative names like %s\n", command[0]);
return(1);
}
return 0;
}
This code works too, not redirecting to file:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char *redirect[] = { "<", "file.in" };
char *command[] = { "/bin/ls", "-l", 0 };
if (!strcmp(redirect[0], ">"))
{
if ((fd = open(redirect[1], O_WRONLY | O_CREAT, 0644)) != -1)
{
fprintf(stderr, "Dupping stdout to %s\n", redirect[1]);
dup2(fd, STDOUT_FILENO);
close(fd);
}
}
if (command[0][0] == '/')
{
execv(command[0], command);
fprintf(stderr, "ERROR: command %s does not exist at path specified\n", command[0]);
return(1);
}
else
{
fprintf(stderr, "ERROR: not handling relative names like %s\n", command[0]);
return(1);
}
return 0;
}
Note that it sets up the command array and uses execv(command[0], command); — this is the recommended way of doing business. Your code appears to have a variable commands with presumably the arguments to the program; you also appear to have a variable path with presumably the path name of the program. Since we can't see what's in those, it is hard to know what they contain and where there might be problems. Note the explicit null pointer (0) at the end of the command array. That is crucial. Note too that the error messages identify what was failing. There are few things more frustrating than a program that says "it went wrong" without identifying what 'it' is.