1

I am creating a Quine in C and where i need to create a new c file and then compile it and execute it.

I made a simple snippet to understand why it's not working.

My guess is that execv start the command before fprintf is done writing but i put a sleep and it's wasn't working too.

(All my apologize for this ugliest code but it's not the goal)

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
    char *cmd[100]= {"sh", "-c", "\"gcc tmp.c && ./a.out\""};

    fprintf(fopen("tmp.c", "w"), "#include <stdio.h>\nint main(){puts(\"Hello World\");}");
    execv("/bin/sh", cmd);
    return (0);
}

Output

sh: gcc tmp.c && ./a.out: No such file or directory

Any idea ?

albttx
  • 3,444
  • 4
  • 23
  • 42
  • Isn't the object of a quine program to recreate its own source code as the output when it is run? See [Program that prints its own source code as its output](http://stackoverflow.com/questions/10238670/) and [Program that prints itself even if the source file is deleted](http://stackoverflow.com/questions/15325385/) as examples; there are more in the 'Related questions' list on the RHS. – Jonathan Leffler Nov 04 '16 at 21:48

2 Answers2

2

Your argument array cmd is not terminated with a NULL pointer. Also, it has the quote issue.

You should also close the file before execv() call. The reason you are not seeing anything in the file is because fprintf() buffering. While all the open files are closed at process exit, you are exec'ing before that.

int main(void)
{

   char *cmd[]= {"sh", "-c", "gcc tmp.c && ./a.out", (char*)0};

    FILE *fp = fopen("tmp.c", "w");
    if (!fp) {
       perror("fopen");
       exit(1);
    }

    fprintf(fp, "#include <stdio.h>\nint main(){puts(\"Hello World\");}");
    fclose(fp);
    execv("/bin/sh", cmd);
    perror("execv");
    return (0);
}
P.P
  • 117,907
  • 20
  • 175
  • 238
0

when you're calling your shell in a normal shell you do:

sh -c "gcc tmp.c && ./a.out"

(sh -c gcc tmp.c && ./a.out works in my shell but not yours as your comments are stating)

So it means that you have to pass the arguments not as much quoted to execv or they're interpreted as a single argument like if you did:

sh -c \""gcc tmp.c && ./a.out\""

proposed fix:

char *cmd[100]= {"sh", "-c", "gcc tmp.c && ./a.out", NULL};

BTW: don't forget to fclose your file or tmp.c may be zero. BTW2: thanks to usr, a NULL was missing: edited.

Fully fixed code proposal:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
    char *cmd[100]= {"sh", "-c", "gcc tmp.c && ./a.out", NULL};
    FILE *outfile = fopen("tmp.c", "w");
    if (!outfile) {printf("cannot open output file\n");exit(1);}

    fprintf(outfile, "#include <stdio.h>\nint main(){puts(\"Hello World\");}");
    fclose(outfile);  // required else file remains open
    execv("/bin/sh", cmd);
    return (0);
}
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219