00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #define _GNU_SOURCE
00021
00022 #include <stdio.h>
00023 #include <stdint.h>
00024 #include <stdbool.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <signal.h>
00028 #include <sys/socket.h>
00029 #include <bits/socket.h>
00030 #include <sys/un.h>
00031 #include <sys/uio.h>
00032 #include <sys/time.h>
00033 #include <sys/resource.h>
00034 #include <sys/stat.h>
00035 #include <unistd.h>
00036 #include <errno.h>
00037 #include <sys/wait.h>
00038 #include <limits.h>
00039 #include <getopt.h>
00040 #include <fcntl.h>
00041
00042 #include "report.h"
00043 #include "protocol.h"
00044 #include "invokelib.h"
00045 #include "search.h"
00046
00047 #ifdef HAVE_CREDS
00048 #include <sys/creds.h>
00049 #endif
00050
00051
00052 static const unsigned int EXIT_DELAY = 0;
00053 static const unsigned int MIN_EXIT_DELAY = 1;
00054 static const unsigned int MAX_EXIT_DELAY = 86400;
00055
00056
00057
00058 static const unsigned int RESPAWN_DELAY = 3;
00059 static const unsigned int MIN_RESPAWN_DELAY = 0;
00060 static const unsigned int MAX_RESPAWN_DELAY = 10;
00061
00062 static const unsigned char EXIT_STATUS_APPLICATION_CONNECTION_LOST = 0xfa;
00063 static const unsigned char EXIT_STATUS_APPLICATION_NOT_FOUND = 0x7f;
00064
00065
00066
00067
00068
00069
00070
00071 enum APP_TYPE { M_APP, QT_APP, QDECL_APP, EXEC_APP, UNKNOWN_APP };
00072
00073
00074 extern char ** environ;
00075
00076
00077 static pid_t g_invoked_pid = -1;
00078
00079 static void sigs_restore(void);
00080 static void sigs_init(void);
00081
00083 static int g_signal_pipe[2];
00084
00085
00086 static void sig_forwarder(int sig)
00087 {
00088 if (g_invoked_pid >= 0)
00089 {
00090 if (kill(g_invoked_pid, sig) != 0)
00091 {
00092 report(report_error, "Can't send signal to application: %s \n", strerror(errno));
00093 }
00094
00095
00096 sigs_restore();
00097
00098
00099 char signal_id = (char) sig;
00100 write(g_signal_pipe[1], &signal_id, 1);
00101
00102
00103 raise(sig);
00104 }
00105 }
00106
00107
00108 static void sigs_set(struct sigaction *sig)
00109 {
00110 sigaction(SIGABRT, sig, NULL);
00111 sigaction(SIGALRM, sig, NULL);
00112 sigaction(SIGBUS, sig, NULL);
00113 sigaction(SIGCHLD, sig, NULL);
00114 sigaction(SIGCONT, sig, NULL);
00115 sigaction(SIGHUP, sig, NULL);
00116 sigaction(SIGINT, sig, NULL);
00117 sigaction(SIGIO, sig, NULL);
00118 sigaction(SIGIOT, sig, NULL);
00119 sigaction(SIGPIPE, sig, NULL);
00120 sigaction(SIGPROF, sig, NULL);
00121 sigaction(SIGPWR, sig, NULL);
00122 sigaction(SIGQUIT, sig, NULL);
00123 sigaction(SIGSEGV, sig, NULL);
00124 sigaction(SIGSYS, sig, NULL);
00125 sigaction(SIGTERM, sig, NULL);
00126 sigaction(SIGTRAP, sig, NULL);
00127 sigaction(SIGTSTP, sig, NULL);
00128 sigaction(SIGTTIN, sig, NULL);
00129 sigaction(SIGTTOU, sig, NULL);
00130 sigaction(SIGUSR1, sig, NULL);
00131 sigaction(SIGUSR2, sig, NULL);
00132 sigaction(SIGVTALRM, sig, NULL);
00133 sigaction(SIGWINCH, sig, NULL);
00134 sigaction(SIGXCPU, sig, NULL);
00135 sigaction(SIGXFSZ, sig, NULL);
00136 }
00137
00138
00139 static void sigs_init(void)
00140 {
00141 struct sigaction sig;
00142
00143 memset(&sig, 0, sizeof(sig));
00144 sig.sa_flags = SA_RESTART;
00145 sig.sa_handler = sig_forwarder;
00146
00147 sigs_set(&sig);
00148 }
00149
00150
00151 static void sigs_restore(void)
00152 {
00153 struct sigaction sig;
00154
00155 memset(&sig, 0, sizeof(sig));
00156 sig.sa_flags = SA_RESTART;
00157 sig.sa_handler = SIG_DFL;
00158
00159 sigs_set(&sig);
00160 }
00161
00162
00163 static void show_credentials(void)
00164 {
00165 #ifdef HAVE_CREDS
00166 creds_t creds;
00167 creds_value_t value;
00168 creds_type_t type;
00169 int i;
00170
00171 creds = creds_gettask(0);
00172 for (i = 0; (type = creds_list(creds, i, &value)) != CREDS_BAD; ++i) {
00173 char buf[200];
00174 (void)creds_creds2str(type, value, buf, sizeof(buf));
00175 buf[sizeof(buf)-1] = 0;
00176 printf("\t%s\n", buf);
00177 }
00178 creds_free(creds);
00179 #else
00180 printf("Security credential information isn't available.\n");
00181 #endif
00182
00183 exit(0);
00184 }
00185
00186
00187 static bool invoke_recv_ack(int fd)
00188 {
00189 uint32_t action;
00190
00191 invoke_recv_msg(fd, &action);
00192
00193 if (action == INVOKER_MSG_BAD_CREDS)
00194 {
00195 die(1, "Security credential check failed.\n");
00196 }
00197 else if (action != INVOKER_MSG_ACK)
00198 {
00199 die(1, "Received wrong ack (%08x)\n", action);
00200 }
00201
00202 return true;
00203 }
00204
00205
00206 static int invoker_init(enum APP_TYPE app_type)
00207 {
00208 int fd;
00209 struct sockaddr_un sun;
00210
00211 fd = socket(PF_UNIX, SOCK_STREAM, 0);
00212 if (fd < 0)
00213 {
00214 error("Failed to open invoker socket.\n");
00215 return -1;
00216 }
00217
00218 sun.sun_family = AF_UNIX;
00219
00220 const int maxSize = sizeof(sun.sun_path) - 1;
00221 if(app_type == M_APP)
00222 {
00223 strncpy(sun.sun_path, INVOKER_M_SOCK, maxSize);
00224 }
00225 else if (app_type == QT_APP)
00226 {
00227 strncpy(sun.sun_path, INVOKER_QT_SOCK, maxSize);
00228 }
00229 else if (app_type == QDECL_APP)
00230 {
00231 strncpy(sun.sun_path, INVOKER_QDECL_SOCK, maxSize);
00232 }
00233 else if (app_type == EXEC_APP)
00234 {
00235 strncpy(sun.sun_path, INVOKER_EXEC_SOCK, maxSize);
00236 }
00237 else
00238 {
00239 die(1, "Unknown type of application: %d\n", app_type);
00240 }
00241
00242 sun.sun_path[maxSize] = '\0';
00243
00244 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
00245 {
00246 error("Failed to initiate connect on the socket.\n");
00247 return -1;
00248 }
00249
00250 return fd;
00251 }
00252
00253
00254
00255
00256 static uint32_t invoker_recv_pid(int fd)
00257 {
00258
00259 uint32_t action;
00260 invoke_recv_msg(fd, &action);
00261 if (action != INVOKER_MSG_PID)
00262 die(1, "Received a bad message id (%08x)\n", action);
00263
00264
00265 uint32_t pid = 0;
00266 invoke_recv_msg(fd, &pid);
00267 if (pid == 0)
00268 die(1, "Received a zero pid \n");
00269
00270 return pid;
00271 }
00272
00273
00274 static bool invoker_recv_exit(int fd, int* status)
00275 {
00276 uint32_t action;
00277
00278
00279 bool res = invoke_recv_msg(fd, &action);
00280
00281 if (!res || (action != INVOKER_MSG_EXIT))
00282 {
00283
00284
00285
00286 sleep(2);
00287
00288
00289 return false;
00290 }
00291
00292
00293 res = invoke_recv_msg(fd, (uint32_t*) status);
00294 return res;
00295 }
00296
00297
00298 static void invoker_send_magic(int fd, uint32_t options)
00299 {
00300
00301 invoke_send_msg(fd, INVOKER_MSG_MAGIC | INVOKER_MSG_MAGIC_VERSION | options);
00302 }
00303
00304
00305 static void invoker_send_name(int fd, char *name)
00306 {
00307 invoke_send_msg(fd, INVOKER_MSG_NAME);
00308 invoke_send_str(fd, name);
00309 }
00310
00311 static void invoker_send_splash_file(int fd, char *filename)
00312 {
00313 invoke_send_msg(fd, INVOKER_MSG_SPLASH);
00314 invoke_send_str(fd, filename);
00315 }
00316
00317 static void invoker_send_landscape_splash_file(int fd, char *filename)
00318 {
00319 invoke_send_msg(fd, INVOKER_MSG_LANDSCAPE_SPLASH);
00320 invoke_send_str(fd, filename);
00321 }
00322
00323 static void invoker_send_exec(int fd, char *exec)
00324 {
00325 invoke_send_msg(fd, INVOKER_MSG_EXEC);
00326 invoke_send_str(fd, exec);
00327 }
00328
00329 static void invoker_send_args(int fd, int argc, char **argv)
00330 {
00331 int i;
00332
00333 invoke_send_msg(fd, INVOKER_MSG_ARGS);
00334 invoke_send_msg(fd, argc);
00335 for (i = 0; i < argc; i++)
00336 {
00337 debug("param %d %s \n", i, argv[i]);
00338 invoke_send_str(fd, argv[i]);
00339 }
00340 }
00341
00342 static void invoker_send_prio(int fd, int prio)
00343 {
00344 invoke_send_msg(fd, INVOKER_MSG_PRIO);
00345 invoke_send_msg(fd, prio);
00346 }
00347
00348
00349 static void invoker_send_delay(int fd, int delay)
00350 {
00351 invoke_send_msg(fd, INVOKER_MSG_DELAY);
00352 invoke_send_msg(fd, delay);
00353 }
00354
00355
00356 static void invoker_send_ids(int fd, int uid, int gid)
00357 {
00358 invoke_send_msg(fd, INVOKER_MSG_IDS);
00359 invoke_send_msg(fd, uid);
00360 invoke_send_msg(fd, gid);
00361 }
00362
00363
00364 static void invoker_send_env(int fd)
00365 {
00366 int i, n_vars;
00367
00368
00369 for (n_vars = 0; environ[n_vars] != NULL; n_vars++) ;
00370
00371 invoke_send_msg(fd, INVOKER_MSG_ENV);
00372 invoke_send_msg(fd, n_vars);
00373
00374 for (i = 0; i < n_vars; i++)
00375 {
00376 invoke_send_str(fd, environ[i]);
00377 }
00378
00379 return;
00380 }
00381
00382
00383 static void invoker_send_io(int fd)
00384 {
00385 struct msghdr msg;
00386 struct cmsghdr *cmsg = NULL;
00387 int io[3] = { 0, 1, 2 };
00388 char buf[CMSG_SPACE(sizeof(io))];
00389 struct iovec iov;
00390 int dummy;
00391
00392 memset(&msg, 0, sizeof(struct msghdr));
00393
00394 iov.iov_base = &dummy;
00395 iov.iov_len = 1;
00396
00397 msg.msg_iov = &iov;
00398 msg.msg_iovlen = 1;
00399 msg.msg_control = buf;
00400 msg.msg_controllen = sizeof(buf);
00401
00402 cmsg = CMSG_FIRSTHDR(&msg);
00403 cmsg->cmsg_len = CMSG_LEN(sizeof(io));
00404 cmsg->cmsg_level = SOL_SOCKET;
00405 cmsg->cmsg_type = SCM_RIGHTS;
00406
00407 memcpy(CMSG_DATA(cmsg), io, sizeof(io));
00408
00409 msg.msg_controllen = cmsg->cmsg_len;
00410
00411 invoke_send_msg(fd, INVOKER_MSG_IO);
00412 if (sendmsg(fd, &msg, 0) < 0)
00413 {
00414 warning("sendmsg failed in invoker_send_io: %s \n", strerror(errno));
00415 }
00416
00417 return;
00418 }
00419
00420
00421 static void invoker_send_end(int fd)
00422 {
00423 invoke_send_msg(fd, INVOKER_MSG_END);
00424 invoke_recv_ack(fd);
00425
00426 }
00427
00428
00429 static void usage(int status)
00430 {
00431 printf("\nUsage: %s [options] [--type=TYPE] [file] [args]\n\n"
00432 "Launch m, qt, or qdeclarative application compiled as a shared library (-shared) or\n"
00433 "a position independent executable (-pie) through %s.\n\n"
00434 "TYPE chooses the type of booster used. Qt-booster may be used to\n"
00435 "launch anything. Possible values for TYPE:\n"
00436 " m Launch a MeeGo Touch application.\n"
00437 " q (or qt) Launch a Qt application.\n"
00438 " d Launch a Qt Declarative (QML) application.\n"
00439 " e Launch any application, even if it's not a library.\n"
00440 " Can be used if only splash screen is wanted.\n\n"
00441 "Options:\n"
00442 " -c, --creds Print Aegis security credentials (if enabled).\n"
00443 " -d, --delay SECS After invoking sleep for SECS seconds\n"
00444 " (default %d).\n"
00445 " -r, --respawn SECS After invoking respawn new booster after SECS seconds\n"
00446 " (default %d, max %d).\n"
00447 " -w, --wait-term Wait for launched process to terminate (default).\n"
00448 " -n, --no-wait Do not wait for launched process to terminate.\n"
00449 " -G, --global-syms Places symbols in the application binary and its\n"
00450 " libraries to the global scope.\n"
00451 " See RTLD_GLOBAL in the dlopen manual page.\n"
00452 " -s, --single-instance Launch the application as a single instance.\n"
00453 " The existing application window will be activated\n"
00454 " if already launched.\n"
00455 " -S, --splash FILE Show splash screen from the FILE.\n"
00456 " -L, --splash-landscape LANDSCAPE-FILE\n"
00457 " Show splash screen from the LANDSCAPE-FILE\n"
00458 " in case the device is in landscape orientation.\n"
00459 " -o, --daemon-mode Notify invoker that the launched process is a daemon.\n"
00460 " This resets the oom_adj of the process.\n"
00461 " -h, --help Print this help.\n\n"
00462 "Example: %s --type=m /usr/bin/helloworld\n\n",
00463 PROG_NAME_INVOKER, PROG_NAME_LAUNCHER, EXIT_DELAY, RESPAWN_DELAY, MAX_RESPAWN_DELAY, PROG_NAME_INVOKER);
00464
00465 exit(status);
00466 }
00467
00468
00469 static unsigned int get_delay(char *delay_arg, char *param_name,
00470 unsigned int min_value, unsigned int max_value)
00471 {
00472 unsigned int delay = EXIT_DELAY;
00473
00474 if (delay_arg)
00475 {
00476 errno = 0;
00477 delay = strtoul(delay_arg, NULL, 10);
00478
00479
00480 if ((errno == ERANGE && delay == ULONG_MAX)
00481 || delay < min_value
00482 || delay > max_value)
00483 {
00484 report(report_error, "Wrong value of %s parameter: %s\n", param_name, delay_arg);
00485 usage(1);
00486 }
00487 }
00488
00489 return delay;
00490 }
00491
00492 static int wait_for_launched_process_to_exit(int socket_fd, bool wait_term)
00493 {
00494 int status = 0;
00495
00496
00497 if (wait_term)
00498 {
00499
00500 g_invoked_pid = invoker_recv_pid(socket_fd);
00501 debug("Booster's pid is %d \n ", g_invoked_pid);
00502
00503
00504 sigs_init();
00505
00506 while(1)
00507 {
00508
00509 fd_set readfds;
00510 int ndfs = 0;
00511
00512 FD_ZERO(&readfds);
00513
00514 FD_SET(socket_fd, &readfds);
00515 ndfs = (socket_fd > ndfs) ? socket_fd : ndfs;
00516
00517 FD_SET(g_signal_pipe[0], &readfds);
00518 ndfs = (socket_fd > ndfs) ? socket_fd : ndfs;
00519
00520
00521 if (select(ndfs + 1, &readfds, NULL, NULL, NULL) > 0)
00522 {
00523
00524 if (FD_ISSET(socket_fd, &readfds))
00525 {
00526 bool res = invoker_recv_exit(socket_fd, &status);
00527
00528 if (!res)
00529 {
00530
00531
00532
00533
00534 char filename[50];
00535 snprintf(filename, sizeof(filename), "/proc/%d/cmdline", g_invoked_pid);
00536
00537
00538 int fd = open(filename, O_RDONLY);
00539 if (fd != -1)
00540 {
00541
00542
00543 close(fd);
00544
00545
00546
00547
00548
00549
00550
00551 sleep(10);
00552 kill(g_invoked_pid, SIGKILL);
00553 raise(SIGKILL);
00554 }
00555 else
00556 {
00557
00558 status = EXIT_FAILURE;
00559 }
00560 }
00561 break;
00562 }
00563
00564 else if (FD_ISSET(g_signal_pipe[0], &readfds))
00565 {
00566
00567 char signal_id;
00568 read(g_signal_pipe[0], &signal_id, sizeof(signal_id));
00569
00570
00571
00572 sigs_init();
00573 }
00574 }
00575 }
00576
00577
00578 sigs_restore();
00579 }
00580
00581 return status;
00582 }
00583
00584
00585 static int invoke_remote(int socket_fd, int prog_argc, char **prog_argv, char *prog_name,
00586 uint32_t magic_options, bool wait_term, unsigned int respawn_delay,
00587 char *splash_file, char *landscape_splash_file)
00588 {
00589
00590 errno = 0;
00591 int prog_prio = getpriority(PRIO_PROCESS, 0);
00592 if (errno && prog_prio < 0)
00593 {
00594 prog_prio = 0;
00595 }
00596
00597
00598
00599 invoker_send_magic(socket_fd, magic_options);
00600 invoker_send_name(socket_fd, prog_argv[0]);
00601 invoker_send_exec(socket_fd, prog_name);
00602 invoker_send_args(socket_fd, prog_argc, prog_argv);
00603 invoker_send_prio(socket_fd, prog_prio);
00604 invoker_send_delay(socket_fd, respawn_delay);
00605 invoker_send_ids(socket_fd, getuid(), getgid());
00606 if (( magic_options & INVOKER_MSG_MAGIC_OPTION_SPLASH_SCREEN ) != 0)
00607 invoker_send_splash_file(socket_fd, splash_file);
00608 if (( magic_options & INVOKER_MSG_MAGIC_OPTION_LANDSCAPE_SPLASH_SCREEN ) != 0)
00609 invoker_send_landscape_splash_file(socket_fd, landscape_splash_file);
00610 invoker_send_io(socket_fd);
00611 invoker_send_env(socket_fd);
00612 invoker_send_end(socket_fd);
00613
00614 if (prog_name)
00615 {
00616 free(prog_name);
00617 }
00618
00619 int exit_status = wait_for_launched_process_to_exit(socket_fd, wait_term);
00620 return exit_status;
00621 }
00622
00623 static void invoke_fallback(char **prog_argv, char *prog_name, bool wait_term)
00624 {
00625
00626
00627 warning("Connection with launcher process is broken. \n");
00628 error("Start application %s as a binary executable without launcher...\n", prog_name);
00629
00630
00631 if(!wait_term)
00632 {
00633
00634 pid_t newPid = fork();
00635
00636 if (newPid == -1)
00637 {
00638 error("Invoker failed to fork. \n");
00639 exit(EXIT_FAILURE);
00640 }
00641 else if (newPid != 0)
00642 {
00643 return;
00644 }
00645 }
00646
00647
00648 execve(prog_name, prog_argv, environ);
00649 perror("execve");
00650 exit(EXIT_FAILURE);
00651 }
00652
00653
00654 static int invoke(int prog_argc, char **prog_argv, char *prog_name,
00655 enum APP_TYPE app_type, uint32_t magic_options, bool wait_term, unsigned int respawn_delay,
00656 char *splash_file, char *landscape_splash_file)
00657 {
00658 int status = 0;
00659
00660 if (prog_name && prog_argv)
00661 {
00662
00663
00664 int fd = invoker_init(app_type);
00665 if (fd == -1)
00666 {
00667 invoke_fallback(prog_argv, prog_name, wait_term);
00668 }
00669
00670 else
00671 {
00672 status = invoke_remote(fd, prog_argc, prog_argv, prog_name,
00673 magic_options, wait_term, respawn_delay,
00674 splash_file, landscape_splash_file);
00675 close(fd);
00676 }
00677 }
00678
00679 return status;
00680 }
00681
00682 int main(int argc, char *argv[])
00683 {
00684 enum APP_TYPE app_type = UNKNOWN_APP;
00685 int prog_argc = 0;
00686 uint32_t magic_options = 0;
00687 bool wait_term = true;
00688 unsigned int delay = EXIT_DELAY;
00689 unsigned int respawn_delay = RESPAWN_DELAY;
00690 char **prog_argv = NULL;
00691 char *prog_name = NULL;
00692 char *splash_file = NULL;
00693 char *landscape_splash_file = NULL;
00694 struct stat file_stat;
00695
00696
00697 magic_options |= INVOKER_MSG_MAGIC_OPTION_WAIT;
00698
00699
00700 if (!strstr(argv[0], PROG_NAME_INVOKER) )
00701 {
00702 die(1,
00703 "Incorrect use of invoker, don't use symlinks. "
00704 "Run invoker explicitly from e.g. a D-Bus service file instead.\n");
00705 }
00706
00707
00708 putenv("POSIXLY_CORRECT=1");
00709
00710
00711 struct option longopts[] = {
00712 {"help", no_argument, NULL, 'h'},
00713 {"creds", no_argument, NULL, 'c'},
00714 {"wait-term", no_argument, NULL, 'w'},
00715 {"no-wait", no_argument, NULL, 'n'},
00716 {"global-syms", no_argument, NULL, 'G'},
00717 {"deep-syms", no_argument, NULL, 'D'},
00718 {"single-instance", no_argument, NULL, 's'},
00719 {"daemon-mode", no_argument, NULL, 'o'},
00720 {"type", required_argument, NULL, 't'},
00721 {"delay", required_argument, NULL, 'd'},
00722 {"respawn", required_argument, NULL, 'r'},
00723 {"splash", required_argument, NULL, 'S'},
00724 {"splash-landscape", required_argument, NULL, 'L'},
00725 {0, 0, 0, 0}
00726 };
00727
00728
00729
00730 int opt;
00731 while ((opt = getopt_long(argc, argv, "hcwnGDsod:t:r:S:L:", longopts, NULL)) != -1)
00732 {
00733 switch(opt)
00734 {
00735 case 'h':
00736 usage(0);
00737 break;
00738
00739 case 'c':
00740 show_credentials();
00741 break;
00742
00743 case 'w':
00744
00745 break;
00746
00747 case 'o':
00748 magic_options |= INVOKER_MSG_MAGIC_OPTION_OOM_ADJ_DISABLE;
00749 break;
00750
00751 case 'n':
00752 wait_term = false;
00753 magic_options &= (~INVOKER_MSG_MAGIC_OPTION_WAIT);
00754 break;
00755
00756 case 'G':
00757 magic_options |= INVOKER_MSG_MAGIC_OPTION_DLOPEN_GLOBAL;
00758 break;
00759
00760 case 'D':
00761 magic_options |= INVOKER_MSG_MAGIC_OPTION_DLOPEN_DEEP;
00762 break;
00763
00764 case 't':
00765 if (strcmp(optarg, "m") == 0)
00766 app_type = M_APP;
00767 else if (strcmp(optarg, "q") == 0 || strcmp(optarg, "qt") == 0)
00768 app_type = QT_APP;
00769 else if (strcmp(optarg, "d") == 0)
00770 app_type = QDECL_APP;
00771 else if (strcmp(optarg, "e") == 0)
00772 app_type = EXEC_APP;
00773 else
00774 {
00775 report(report_error, "Unknown application type: %s \n", optarg);
00776 usage(1);
00777 }
00778 break;
00779
00780 case 'd':
00781 delay = get_delay(optarg, "delay", MIN_EXIT_DELAY, MAX_EXIT_DELAY);
00782 break;
00783
00784 case 'r':
00785 respawn_delay = get_delay(optarg, "respawn delay",
00786 MIN_RESPAWN_DELAY, MAX_RESPAWN_DELAY);
00787 break;
00788
00789 case 's':
00790 magic_options |= INVOKER_MSG_MAGIC_OPTION_SINGLE_INSTANCE;
00791 break;
00792
00793 case 'S':
00794 magic_options |= INVOKER_MSG_MAGIC_OPTION_SPLASH_SCREEN;
00795 splash_file = optarg;
00796 break;
00797
00798 case 'L':
00799 magic_options |= INVOKER_MSG_MAGIC_OPTION_LANDSCAPE_SPLASH_SCREEN;
00800 landscape_splash_file = optarg;
00801 break;
00802
00803 case '?':
00804 usage(1);
00805 }
00806 }
00807
00808
00809 if (optind < argc)
00810 {
00811 prog_name = search_program(argv[optind]);
00812 if (!prog_name)
00813 {
00814 report(report_error, "Can't find application to invoke.\n");
00815 usage(0);
00816 }
00817
00818 prog_argc = argc - optind;
00819 prog_argv = &argv[optind];
00820 }
00821
00822
00823 if (!prog_name)
00824 {
00825 report(report_error, "Application's name is not defined.\n");
00826 usage(1);
00827 }
00828
00829
00830 if (stat(prog_name, &file_stat))
00831 {
00832 report(report_error, "%s: not found\n", prog_name);
00833 return EXIT_STATUS_APPLICATION_NOT_FOUND;
00834 }
00835
00836
00837 if (!S_ISREG(file_stat.st_mode) && !S_ISLNK(file_stat.st_mode))
00838 {
00839 report(report_error, "%s: not a file\n", prog_name);
00840 return EXIT_STATUS_APPLICATION_NOT_FOUND;
00841 }
00842
00843
00844 if (app_type == UNKNOWN_APP)
00845 {
00846 report(report_error, "Application's type is unknown.\n");
00847 usage(1);
00848 }
00849
00850 if (pipe(g_signal_pipe) == -1)
00851 {
00852 report(report_error, "Creating a pipe for Unix signals failed!\n");
00853 exit(EXIT_FAILURE);
00854 }
00855
00856
00857
00858 info("Invoking execution: '%s'\n", prog_name);
00859 int ret_val = invoke(prog_argc, prog_argv, prog_name, app_type, magic_options, wait_term, respawn_delay, splash_file, landscape_splash_file);
00860
00861
00862 if (delay)
00863 {
00864
00865 debug("Delaying exit for %d seconds..\n", delay);
00866 sleep(delay);
00867 }
00868
00869 return ret_val;
00870 }