I am currently trying to make an application that will receive information from a client and send it to be executed in a server. For that I need to use PseudoTerminals.
I followed the example from a book and I ended up with this code
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
int ptyMasterOpen(char *slavName, size_t snLen)
{
int masterFd, savedErrno;
char *p;
masterFd = posix_openpt(O_RDWR | O_NOCTTY);
printf("Master: %d \n", masterFd);
if(masterFd == -1)
return -1;
if(grantpt(masterFd) == -1 || unlockpt(masterFd) == -1)
{
savedErrno = errno;
close(masterFd);
errno = savedErrno;
return -1;
}
p = ptsname(masterFd); /*Get the name of the of the slave*/
if(p == NULL)
{
savedErrno = errno;
close(masterFd);
errno = savedErrno;
return -1;
}
printf("Slave: %s \n", p);
//*
if(strlen(p) < snLen)
{
strncpy(slavName, p, snLen);
}
else
{
close(masterFd);
errno = EOVERFLOW;
return -1;
}
//*/
return masterFd;
}
pid_t ptyFork(int *masterFd, char *slavName, size_t snLen)
{
int mfd, slaveFd, saveErrno;
pid_t childPid;
char slname[MAX_SNAME];
char cIn[100], cOut[100];
int out = -1, in = -1;
mfd = ptyMasterOpen(slname, MAX_SNAME);
if(mfd == -1)
return -1;
if(slavName != NULL)
{
if(strlen(slname) < snLen)
{
strncpy(slavName, slname, snLen);
}
else
{
close(mfd);
errno = EOVERFLOW;
return -1;
}
}
childPid = fork();
if(childPid == -1)
{
saveErrno = errno;
close(mfd);
errno = saveErrno;
return -1;
}
if(childPid != 0)
{
*masterFd = mfd;
return childPid;
}
close(mfd);
slaveFd = open(slname, O_RDWR);
if(slaveFd != -1)
{
sprintf(cOut, "/tmp/out%d", slaveFd);
sprintf(cIn, "/tmp/in%d", slaveFd);
mkfifo(cOut, S_IRUSR|S_IWUSR);
out = open(cOut, O_RDWR|O_TRUNC|O_NONBLOCK);
mkfifo(cIn, S_IRUSR|S_IWUSR);
in = open(cIn, O_RDONLY|O_TRUNC);dup2(out, STDERR_FILENO);
dup2(out, STDOUT_FILENO);
dup2(in, STDIN_FILENO);
}
else
{
printf("Problem with slave\n\r");
fflush(stdout);
}
//*
if(dup2(slaveFd, STDIN_FILENO) != STDIN_FILENO || dup2(slaveFd, STDERR_FILENO) != STDERR_FILENO || dup2(slaveFd, STDOUT_FILENO) != STDOUT_FILENO)
{
printf("Error on duplicating Files");
close(slaveFd);
exit(0);
}
else
{
dup2(out, STDERR_FILENO);
dup2(out, STDOUT_FILENO);
dup2(in, STDIN_FILENO);
}
//*/
return slaveFd;
}
The problem is:
sprintf(cOut, "/tmp/out%d", childPid);
sprintf(cIn, "/tmp/in%d", childPid);
always return 0 even when I print them in main and they are values like 952...
also using echo "ls" > "/tmp/inxx" and cat /tmp/outxx does nothing.
I believe the problem is when the fork is done, the variables lose their values or something, because, it prints the error messages now, without the while(1) on main
int main(int argc, const char * argv[])
{
// insert code here...
int masterFd;
pid_t slaveFd;
char slavName[MAX_SNAME];
slaveFd = ptyFork(&masterFd, slavName, MAX_SNAME);
//close(masterFd);
//while(1);
return 0;
}
Can anyone help?
Thanks
Related
I'm trying to use pipe command and I can't understand how to.
I've a lot of versions but I can't make it work.
first of all the hierarchy:
main prog - nicecmp - that will execute the child prog and print the result
child prog - loopcmp - that will execute his child prog and get the returned value and send it back to the parent in nicecmp.
loopcmp's childs - lencmp/lexcmp - both prog will be executed in loopcmp and return value between -1 to 2. (100% works)
shortly, I need to create a pipe and a new process that will run new program (loopcmp - added in the end of the code) using execvp, and I need to print the res of the loopcmp in the parent.
I can send it directly from the prog that I executed and I can use WEXITSTATUS in the child after the end of the loopcmp.
what's the right way to do so (from the progrem execution or after that I've returned from the loopcmp)
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LINELEN (80)
#define READFROM ("./loopcmp")
typedef enum { eLexcmp, eLencmp, eNumOfCmp } eCmpstr;
const char* cmpstr[eNumOfCmp] = { "./lexcmp", "./lencmp" };
int lencmp(const char *str1, const char *str2);
int lexcmp(const char *str1, const char *str2);
char *mygets(char *buf, int len);
int mygeti();
int main(int argc, char *argv[])
{
char str1[LINELEN + 1];
char str2[LINELEN + 1];
int index, rc, status, res;
int pfd[2];/* Pipe file descriptors */
if (pipe(pfd) == -1) /* Create pipe */
exit(-2); // pipe failed !
char* myargs[4];
myargs[0]=strdup(READFROM);
while (1)
{
printf("Please enter first string:\n");
if (mygets(str1, LINELEN) == NULL)
break;
printf("Please enter second string:\n");
if (mygets(str2, LINELEN) == NULL)
break;
myargs[2] = strdup(str1);
myargs[3] = strdup(str2);
do {
printf("Please choose:\n");
for (int i = 0; i < eNumOfCmp; i++)
printf("%d - %s\n", i, cmpstr[i]);
index = mygeti();
} while ((index < 0) || (index >= eNumOfCmp));
myargs[1] = strdup(cmpstr[index]);
rc = fork();
if (rc < 0) // fork failed !
{
printf("fork failed\n");
return -2;
}
else if (rc == 0) { // child !
if (close(pfd[1]) == -1) /* Write end is unused */
exit(-2);
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd[0] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd[0], STDIN_FILENO) == -1)
exit(-2);
if (close(pfd[0]) == -1)
exit(-2);
}
execvp(myargs[0],myargs);
}
else { // parent
if (close(pfd[1]) == -1) /* Write end is unused */
exit(-2);
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd[0] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd[0], STDIN_FILENO) == -1)
exit(-2);
if (close(pfd[0]) == -1)
exit(-2);
}
read(pfd[0], &res, sizeof(int));
printf("%d\n", res);
if (close(pfd[0]) == -1)
exit(-2);
}
}
return 0;
}
loopcmp ->
int main(int argc, char *argv[])
{
int status,rc,res = 0;
if (argc != 4)
{
return -1;
}
char* myargs[3];
for(int i=0;i<3;i++){
myargs[i]=argv[i+1];
}
rc = fork();
if (rc < 0) //fork failed
{
return -2;
}
else if (rc == 0) //I'm the child
{
if(execvp(myargs[1], myargs)==-1)
return -2;
}
else // parent
{
wait(&status);
res = WEXITSTATUS(status);
if(res ==254) // invalid file path ! (254== -2)
return -2 ;
}
write(fileno(stdout),&res,sizeof(int));
return res;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0)
{
printf("fork failed\n");
exit(1);
}
else if (rc == 0)
{
close(STDOUT_FILENO);
int ret = open("./out.log", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
if (ret == -1)
{
printf("Failed to open file for stdout redirection\n");
exit(1);
}
char *myargs[2];
myargs[0] = strdup("ls"); // execute ls command
myargs[1] = NULL;
int status = execvp(myargs[0], myargs);
if (status == -1)
{
printf("execvp: failed");
exit(1);
}
printf("Child: Finished\n");
}
else
{
wait(NULL);
printf("Parent: Finished\n");
}
return 0;
}
I am currently trying to create my own (simple) shell - in C language - but I have a hard time with redirection I/O.
I compile and run in VMware(gcc ,and if i want to execute the command :
$cat < file_in.txt > file_out.txt
I get :
File errorcat: '<': No such file or directory
cat: file_in.txt: No such file or directory
Function in header file:
void fileRedirect(char **args, int k, int ioMode)
{
pid_t pid, wpid;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int fd, status = 0;
pid = fork();
if (pid == 0) {
// Child process
if(ioMode == 0) // Input mode
fd = open(args[k+1], O_RDONLY, mode);
else // Output mode
fd = open(args[k+1], O_WRONLY|O_CREAT|O_TRUNC, mode);
if(fd < 0)
fprintf(stderr, "File error");
else {
dup2(fd, ioMode); // Redirect input or output according to ioMode
close(fd); // Close the corresponding pointer so child process can use it
args[k] = NULL;
args[k+1] = NULL;
if (execvp(args[0], args) == -1) {
perror("SHELL");
}
exit(EXIT_FAILURE);
}
}
else if (pid < 0) { // Error forking process
perror("SHELL");
}
else {
// Parent process. Wait till it finishes execution
do {
wpid = waitpid(pid, &status, WUNTRACED);
}
while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}
And .c code :
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "functions.h"
#define BUFSIZE 64 // Size of a single token
#define TOKEN_DELIM " \t\r\n\a" // Token Delimiters
void main(){
char *command = NULL, cwd[1024], *pwd;
char **args, *options[4] = {"<", ">"};
int k = 0, option, found;
pwd = NULL;
pwd = getenv("HOME");
do
{
ssize_t bsize = 0;
found = 0;
printf("$");
if(getcwd(cwd, sizeof(cwd)) != NULL)
{
printf("%s$", cwd);
}
getline(&command, &bsize, stdin);
if(endOfFile(command) == 0)
{
printf("\n");
break;
}
if(charLimit(command) == 0)
{
printf("\n");
break;
}
args = splitTokens(command);
if(args[0] == NULL)
{
free(command);
free(args);
continue;
}
if(strcmp(args[0],"exit") == 0)
{
break;
}
else if(strcmp(args[0], "cd") == 0)
{
if(args[1] == NULL)
{
if(pwd[0] != 0)
{
chdir(pwd);
}
}
else
{
chdir(args[1]);
}
}
else
{
k = 1;
while(args[k] != NULL) { // Check for any of the redirect or process operators <,<,|,&
for(option = 0; option < 2; option++) {
if(strcmp(args[k],options[option]) == 0)
break;
}
if(option < 2) {
found = 1;
if(args[k+1] == NULL) { // For IORedirect and Pipe, argument is necessary
fprintf(stderr, "SHELL: parameter missing\n");
break;
}
fileRedirect(args, k, option);
}
k++;
}
if(found == 0)
execute(args, 0); // Start a foreground process or command
}
free(command);
free(args);
} while(1);
}
I have seen many answers in similar question,but they made me more confused.
Thank you in advance .
I want to use "yp\t\n\0" to run “ypdomainname” command by exploiting auto-completion in busybox, but it failed. my code and result are below:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#define DEFAULT_BUSYBOX_PATH "/bin/busybox"
#define MAX_BUF 1000
int main()
{
int fd[2];
pid_t pid;
FILE *file;
int status;
if(pipe(fd) < 0){
fprintf(stderr, "pipe error!\n");
return -1;
}
if((pid = fork()) < 0){
fprintf(stderr, "pipe error!\n");
}else if(pid == 0){ //child
close(fd[1]);
int fd_output;
fd_output = open("result", O_CREAT | O_RDWR, 777);
if(fd_output != STDOUT_FILENO){
if(dup2(fd_output, STDOUT_FILENO) != STDOUT_FILENO)
fprintf(stderr, "dup2 error to stdout\n");
}
if(fd[0] != STDIN_FILENO){
if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
fprintf(stderr, "dup2 error to stdin\n");
}
execl(DEFAULT_BUSYBOX_PATH, DEFAULT_BUSYBOX_PATH, "ash", NULL);
close(fd[0]);
close(fd_output);
return 0;
}else{ //parent
close(fd[0]);
char buf[MAX_BUF] = "yp";
buf[2] = '\t';
buf[3] = '\n';
buf[4] = '\0';
write(fd[1], buf, strlen(buf));
close(fd[1]);
return 0;
}
}
Result of my code
What makes me confused is that the character is not changed in function lineedit_read_key() in file lineedit.c and it will run the function input_tab() when the character is '\t'.
input_tab will be executed when character is '\t'
Recently, i took some time to learn about terminal to simulate auto-completion, but i still failed. My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <signal.h>
#include <pty.h>
#define DEFAULT_BUSYBOX_PATH "/bin/busybox"
#define MAX_BUF 1000
#define BUFFSIZE 512
typedef void Sigfunc(int);
static void sig_term(int);
static volatile sig_atomic_t sigcaught;
ssize_t writen(int fd, const void *ptr, size_t n){
size_t nleft;
ssize_t nwritten;
nleft = n;
while(nleft > 0){
if((nwritten = write(fd, ptr, nleft)) < 0){
if(nleft == n){
return(-1);
}else{
break;
}
}else if(nwritten == 0) {
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft);
}
Sigfunc *signal_intr(int signo, Sigfunc *func){
struct sigaction act;
struct sigaction oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
int ptym_open(char *pts_name, int pts_namesz)
{
char ptr[50];
int fdm;
int err;
if((fdm = posix_openpt(O_RDWR)) < 0){
return(-1);
}
if(grantpt(fdm) < 0){
goto errout;
}
if(unlockpt(fdm) < 0){
goto errout;
}
if(ptsname_r(fdm, ptr, 50) != 0){
goto errout;
}
strncpy(pts_name, ptr, pts_namesz);
pts_name[pts_namesz - 1] = '\0';
return(fdm); /* return fd of master */
errout:
err = errno;
close(fdm);
errno = err;
return(-1);
}
int ptys_open(char *pts_name){
int fds;
if((fds = open(pts_name, O_RDWR)) < 0)
return(-1);
return(fds);
}
pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz, const struct termios *slave_termios, const struct winsize *slave_winsize){
int fdm, fds;
pid_t pid;
char pts_name[20];
if((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0){
fprintf(stderr, "can't open master pty: %s, error %d", pts_name, fdm);
}
if(slave_name != NULL) {
strncpy(slave_name, pts_name, slave_namesz);
slave_name[slave_namesz - 1] = '\0';
}
if((pid = fork()) < 0) {
return(-1);
}else if (pid == 0) { /* child */
if(setsid() < 0){
fprintf(stderr, "setsid error");
}
if((fds = ptys_open(pts_name)) < 0){
fprintf(stderr, "can't open slave pty");
}
close(fdm);
if(slave_termios != NULL) {
if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
fprintf(stderr, "tcsetattr error on slave pty");
}
if(slave_winsize != NULL) {
if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
fprintf(stderr, "TIOCSWINSZ error on slave pty");
}
if(dup2(fds, STDIN_FILENO) != STDIN_FILENO){
fprintf(stderr, "dup2 error to stdin");
}
if(dup2(fds, STDOUT_FILENO) != STDOUT_FILENO){
fprintf(stderr, "dup2 error to stdout");
}
if(dup2(fds, STDERR_FILENO) != STDERR_FILENO){
fprintf(stderr, "dup2 error to stderr");
}
if(fds != STDIN_FILENO && fds != STDOUT_FILENO && fds != STDERR_FILENO){
close(fds);
}
return(0);
} else { /* parent */
*ptrfdm = fdm;
return(pid);
}
}
void loop(int ptym, int ignoreeof)
{
pid_t child;
int nread;
char buf[BUFFSIZE];
if((child = fork()) < 0) {
fprintf(stderr, "fork error");
}else if(child == 0) {
/*for ( ; ; ){
if((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0){
fprintf(stderr, "read error from stdin");
}else if(nread == 0){
break;
}
if(writen(ptym, buf, nread) != nread)
fprintf(stderr, "writen error to master pty");
}*/
char *temp_buf = "yp\t\n";
if(writen(ptym, temp_buf, strlen(temp_buf)) != strlen(temp_buf)){
fprintf(stderr, "writen error to master pty");
}
if(ignoreeof == 0){
kill(getppid(), SIGTERM);
}
exit(0);
}
if (signal_intr(SIGTERM, sig_term) == SIG_ERR)
fprintf(stderr, "signal_intr error for SIGTERM");
for( ; ; ){
if ((nread = read(ptym, buf, BUFFSIZE)) <= 0){
}
//printf("nread = %d\n", nread);
if (writen(STDOUT_FILENO, buf, nread) != nread){
fprintf(stderr, "writen error to stdout");
}
}
if (sigcaught == 0){
printf("sigcaught == 0 and kill child\n");
kill(child, SIGTERM);
}
}
static void sig_term(int signo)
{
sigcaught = 1;
}
int main(int argc, char *argv[]){
int fd[2];
pid_t pid;
FILE *file;
int status;
int fdm;
int ignoreeof;
char slave_name[40];
struct termios orig_termios;
struct winsize size;
pid = pty_fork(&fdm, slave_name, sizeof(slave_name), &orig_termios, &size);
if(pid < 0){
fprintf(stderr, "fork error!\n");
}else if(pid == 0){ //child
if(execl(DEFAULT_BUSYBOX_PATH, DEFAULT_BUSYBOX_PATH, "ash", NULL) < 0){
fprintf(stderr, "can't execute: %s", DEFAULT_BUSYBOX_PATH);
}
/*if(execvp(argv[1], &argv[1]) < 0){
fprintf(stderr, "can't execute: %s", argv[1]);
}*/
}
loop(fdm, ignoreeof);
}
like the result of my first try, the result is: ash: yp: not found.
Your code fails because a pipe is not a terminal. Many programs will use isatty(3) and alike to detect if the standard input is connected to a terminal and adjust their behaviour depending on the result.
What you can do is to open a pseudo terminal pair using openpty(3) and run the command with the slave duplicated to its standard input, output and error descriptors, and using the master to communicate with it. Unfortunately I have no time right now writing a full solution as it is rather intricate; I've done it ever in Python and it was tricky even there.
I'm trying to write a C program that grabs command output and then i'll be passing that to another program.
I'm having an issue, I cant work out how to get the command output and store it. Below is a sample of what I have
if(fork() == 0){
execl("/bin/ls", "ls", "-1", (char *)0);
/* do something with the output here */
}
else{
//*other stuff goes here*
}
so basically im wondering if there is any way i can get the output from the "execl" and pass it to some thing else (e.g. via storing it in some kind of buffer).
Suggestions would be great.
You have to create a pipe from the parent process to the child, using pipe().
Then you must redirect standard ouput (STDOUT_FILENO) and error output (STDERR_FILENO) using dup or dup2 to the pipe, and in the parent process, read from the pipe.
It should work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
int main() {
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execl("/bin/ls", "ls", "-1", (char *)0);
die("execl");
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}
Open a pipe, and change stdout to match that pipe.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int pipes[2];
pipe(pipes); // Create the pipes
dup2(pipes[1],1); // Set the pipe up to standard output
After that, anything which goes to stdout,(such as through printf), comes out pipe[0].
FILE *input = fdopen(pipes[0],"r");
Now you can read the output like a normal file descriptor. For more details, look at this
Thanks Jonathan Leffler, and i optimize the above code for it can't read all response for one time.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
int main() {
int link[2];
pid_t pid;
char foo[4096 + 1];
memset(foo, 0, 4096);
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execl("/bin/ls", "ls", "-1", (char *)0);
die("execl");
} else {
close(link[1]);
int nbytes = 0;
std::string totalStr;
while(0 != (nbytes = read(link[0], foo, sizeof(foo)))) {
totalStr = totalStr + foo;
printf("Output: (%.*s)\n", nbytes, foo);
memset(foo, 0, 4096);
}
wait(NULL);
}
return 0;
}
If you want the output in a string (char *), here's an option (for Linux at least):
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
char* qx(char** cmd, int inc_stderr) {
int stdout_fds[2];
pipe(stdout_fds);
int stderr_fds[2];
if (!inc_stderr) {
pipe(stderr_fds);
}
const pid_t pid = fork();
if (!pid) {
close(stdout_fds[0]);
dup2(stdout_fds[1], 1);
if (inc_stderr) {
dup2(stdout_fds[1], 2);
}
close(stdout_fds[1]);
if (!inc_stderr) {
close(stderr_fds[0]);
dup2(stderr_fds[1], 2);
close(stderr_fds[1]);
}
execvp(*cmd, cmd);
exit(0);
}
close(stdout_fds[1]);
const int buf_size = 4096;
char* out = malloc(buf_size);
int out_size = buf_size;
int i = 0;
do {
const ssize_t r = read(stdout_fds[0], &out[i], buf_size);
if (r > 0) {
i += r;
}
if (out_size - i <= 4096) {
out_size *= 2;
out = realloc(out, out_size);
}
} while (errno == EAGAIN || errno == EINTR);
close(stdout_fds[0]);
if (!inc_stderr) {
close(stderr_fds[1]);
do {
const ssize_t r = read(stderr_fds[0], &out[i], buf_size);
if (r > 0) {
i += r;
}
if (out_size - i <= 4096) {
out_size *= 2;
out = realloc(out, out_size);
}
} while (errno == EAGAIN || errno == EINTR);
close(stderr_fds[0]);
}
int r, status;
do {
r = waitpid(pid, &status, 0);
} while (r == -1 && errno == EINTR);
out[i] = 0;
return out;
}
int main() {
char* argv[3];
argv[0] = "ls";
argv[1] = "-la";
argv[2] = NULL;
char* out = qx(argv, 0);
printf("%s", out);
free(out);
}