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