I'm trying to launch Preview on OSX using fork and execv. When I use fork and execv on Preview the icon pops up in the dock, but nothing is displayed on the screen. The console also displays the two error messages below.
4/20/16 12:18:23.276 PM iconservicesagent[319]: -[ISGenerateImageOp generateImageWithCompletion:] Failed to composit image for descriptor <ISBindingImageDescriptor: 0x7f85aa50b890>.
4/20/16 12:18:23.276 PM quicklookd[1959]: Error returned from iconservicesagent: (null)
Below is some code to reproduce the problem, note you will have to replace
the hardcoded file path in the args array to a valid pdf file path for your system.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
pid_t pid = 0;
int32_t rtrn = 0;
pid = fork();
if(pid == 0)
{
char * const args[] = {"/users/nah/desktop/file.pdf", NULL};
rtrn = execv("/Applications/Preview.app/Contents/MacOS/Preview", args);
if(rtrn < 0)
{
printf("Can't execute target program: %s\n", strerror(errno));
_exit(-1);
}
_exit(0);
}
else if(pid > 0)
{
int32_t status = 0;
while(waitpid(-1, &status, 0) > 0)
{
}
}
else
{
printf("Can't create child proc: %s\n", strerror(errno));
return (-1);
}
return (0);
}
However If I replace all the fork and execv code and use system(3) like in the example below, Preview opens and displays just fine and there are no error messages in console. So how do I launch Preview using fork and execv instead using system(3) or having to use Objective-C?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
pid_t pid = 0;
int32_t rtrn = 0;
rtrn = system("/Applications/Preview.app/Contents/MacOS/Preview /users/nah/desktop/file.pdf");
if(rtrn < 0)
{
printf("System: %s\n", strerror(errno));
return (-1);
}
return (0);
}
You also need to set the additional arguments that the Mac OS X application system supplies to main(), but you shouldn't be doing any of this:
Preview may or may not be the default PDF viewer for the system it's running on, and if it is not, congratulations, you now have a bewildered and possibly angry user.
If you're dead set on not using Objective-C, what you'll want to do is system("open /path/to/file.pdf");. This will take care of all the tricky business of figuring out what application to use, where it is and how to launch it.
Related
I am trying to write a program that will fork, then open a file and execute it. The file it should execute is called child and it has been compiled. When I type ./child, it runs. However, when I run this program it does not execute the child program and I am prompted with the error message I put in "Execution failed". What I am doing wrong?
This is my parent class
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main (int argc, char **argv)
{
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
int var = execvp("./child", NULL);
if(var < 0)
{
printf("Execution failed");
}
}
exit(0); // exec never returns
}
This is the child
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
printf ("Im the child");
exit (0);
}
I actually don't know what you are doing wrong. After a copy and a compilation (and several warning complains) your code runs fine (GCC 7.2).
Obviously, child must be in the same working directory in which you run your main executable (the one that forks).
But probably I would write that code in this way, but I'm not an expert in forking:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
extern int errno;
int main () {
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
if (pid == 0) {
int ret = execl("./child", "", (char *)NULL);
if(ret < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
} else {
wait(NULL);
}
return 0;
}
At least it tells you which error execl has encountered.
I write a program, which should create new process (I use fork(), and next in child process call execl()) and communicate with it. Here is my server:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
int main(int argc, char *argv[]) {
pid_t process;
process = fork();
if (process == 0) {
printf("The program will be executed %s...\n\n", argv[0]);
printf("Executing %s", argv[0]);
execl("hello", "Hello, World!", NULL);
return EXIT_SUCCESS;
}
else if (process < 0) {
fprintf (stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
waitpid(process, NULL, NULL);
return 0;
}
And here is my client:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i=0;
printf("%s\n",argv[0]);
printf("The program was executed and got a string : ");
while(argv[++i] != NULL)
printf("%s ",argv[i]);
return 0;
}
The problem is the next: my client and server show output in the same terminal. I want them to show output in separate terminals. So, how can I do it?
You need to have two open terminals. The idea is to run your program in the first terminal and see the output of the client in the second terminal.
First, you need to know what is the ID of the second terminal. So in the second terminal do:
$ tty
/dev/pts/1
(note your output will be probably different because mine is a SSH connection and hence pts, yours will be /dev/tty)
And then in your child process, you tell it to use this other terminal for its output. Like this:
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
int fd = open("/dev/pts/1",O_RDWR) ; // note that in your case you need to update this based on your terminal name
// duplicate the fd and overwrite the stdout value
if (fd < 0){
perror("could not open fd");
exit(0);
}
if (dup2(fd, 0) < 0 ){
perror("dup2 on stdin failed");
exit(0);
}
if (dup2(fd, 1) < 0 ){
perror("dup2 on stdout failed");
exit(0);
}
// from now on all your outputs are directed to the other terminal.
// and inputs are also come from other terminal.
}
I am learning C and have run into a small problem. After reading about fork() bomb on Wikipedia and on StackOverflow. I wanted to implement the same, but using command line args.
I want to endlessly call firefox/chrome, but unable to do the same in my below program. Any assistance would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
pid_t pid;
char *parmList[] = {"firefox", "index.html", NULL};
int a;
if ((pid = fork()) == -1)
{
perror("fork failed");
}
if (pid == 0)
{
a = execvp("/usr/bin/firefox", parmList);
fprintf(stdout, "execvp() returned %d\n", a);
fprintf(stdout, "errno: %s (%d).\n", strerror(errno), errno);
}
else
{
waitpid(pid, 0, 0);
}
return 0;
}
You should clarify what error you're getting, since I don't want to run a fork bomb, but the code you wrote doesn't bomb (call fork() within a loop). It spawns one process, waits nicely, and quits.
I already used execl() in code, and it worked well.
But this time, I really have no idea why it doesn't work.
So here's the code that do not work
#include <unistd.h>
#include <stdio.h>
int main()
{
int i = 896;
printf("please\n");
execl("home/ubuntu/server/LC/admin/admin", (char*)i, NULL);
printf("i have no idea why\n");
return 0;
}
And here's the admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int mid = argv[0];
printf("hi from child\n");
printf("%d\n", mid);
return 0;
}
Of course I compiled admin.c to admin, and the path isn't wrong.
>ls
admin admin.c why why.c
>pwd
/home/ubuntu/server/LC/admin
>./admin
hi from child
-1180858374
>./why
please
i have no ida why
Anyone know why it doesn't work?
My C is a bit rusty but your code made many rookie mistakes.
execl will replace the current process if it succeeds. So the last line ("i have no idea why") won't print if the child can launch successfully. Which means...
execl failed and you didn't check for it! Hint: check the typecast to char *.
You cast an int to a char * in the execl call, then again when you launch the child (admin). This is a big no-no in C. It freely allows you to misinterpret types. The only warning is most often a crash. GGC will warn you about it. I don't know about the compiler on AWS.
Check your array's bound! You don't know how many parameters admin was launched with. argv[0] always exist because it contains a representation of the program name. argv[1] may not be defined. Accessing array out-of-bound is an undefined behavior and highly dangerous.
The standard way to start another process in C is to fork the parent, then call one of the functions in the exec family to start the other process.
Consider this instead (I took the liberty to emit different messages to make them clearer).
parent.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
int i = 896;
char str[15];
int pid;
printf("Hello from parent\n");
sprintf(str, "%d", i); // convert the number into string
pid = fork();
if (pid == -1)
{
printf("Fork failed\n");
}
else if (pid == 0)
{
printf("Continue from parent\n");
}
else
{
// start the child process
execl("home/ubuntu/server/LC/admin/admin", str, NULL);
// check if it started properly
if (errno != 0)
{
printf("Error launching child process: %s\n", strerror(errno));
return 1;
}
}
printf("Goodbye from parent\n");
return 0;
}
admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char * mid;
// argc is always 1 or more
if (argc >= 2)
mid = argv[1];
else
mid = "<nothing>";
printf("hello from child\n");
printf("argc = %d, argv[1] = %s\n", argc, mid);
return 0;
}
I'm trying to create a c program that takes an executable and its arguments and runs them using execve, and then does some other stuff that shouldn't matter. The problem I'm having is that execve won't work when calling it on an exectuable assembly file. I think the problem is with my path because I can get the unix shell commands to work, but I can't get executables in the current directory (using ./spy ./executableName where spy is the name of my c program) to run. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
extern char **environ;
int main(int argc, char* const argv[]) {
pid_t pid;
char filename[50];
char* arglist[argc];
int i = 1,count = 0;
int status;
strcpy(filename, "/bin/");
strcat(filename,argv[1]);
for(i = 1; i< argc; i++)
arglist[i-1] = argv[i];
arglist[argc-1] = 0;
arglist[0] = filename;
if (argc == 1) {
fprintf(stderr,"usage : %s <prog> ...\n",argv[0]);
return -1;
}
pid = fork();
if(pid == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if(execve(filename, arglist, 0) < 0)
fprintf(stdout,"Invalid file.");
}
else {
while(1) {
waitpid(pid,&status,0);
if (WIFEXITED(status))
break;
ptrace(PTRACE_SINGLESTEP, pid,NULL, NULL);
count++;
}
}
return 0;
}
From the source you posted it looks as if you were always prefixing the name passed as parameter with /bin/. So if the file isn't in /bin/ it can not be found, nor run.
Just change these two lines:
strcpy(filename, "/bin/");
strcat(filename,argv[1]);
to be:
strcpy(filename,argv[1]);
Note that having applied this modification the program to be run needs to be specified with its full path.
So to run ls you need to do specfify /bin/ls as parameter to the program.
Some other comments:
So avoid buffer a overflow for long path/file names change:
char filename[50];
to be:
char filename[PATH_MAX];
To get more detailed information on why an execve() might have failed change:
if(execve(filename, arglist, 0) < 0)
fprintf(stdout,"Invalid file.");
to be:
if(execve(filename, arglist, (char*) 0) < 0)
perror("execve() failed");
To detect a possible failure of forking do change:
pid = fork();
to become:
if (-1 == (pid = fork())) then
{
perror("fork() failed");
}
else