• Main Page
  • Files
  • File List
  • File Members

/home/developer/harmattan/workspace/applauncherd-3.0.3+0m8/src/invoker/invoker.c

Go to the documentation of this file.
00001 /***************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (directui@nokia.com)
00006 **
00007 ** This file is part of applauncherd
00008 **
00009 ** If you have questions regarding the use of this file, please contact
00010 ** Nokia at directui@nokia.com.
00011 **
00012 ** This library is free software; you can redistribute it and/or
00013 ** modify it under the terms of the GNU Lesser General Public
00014 ** License version 2.1 as published by the Free Software Foundation
00015 ** and appearing in the file LICENSE.LGPL included in the packaging
00016 ** of this file.
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 // Delay before exit.
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 // Delay before a new booster is started. This will
00057 // be sent to the launcher daemon.
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 // Enumeration of possible application types:
00066 // M_APP     : MeeGo Touch application
00067 // QT_APP    : Qt/generic application
00068 // QDECL_APP : QDeclarative (QML) application
00069 // EXEC_APP  : Executable generic application (can be used with splash screen)
00070 //
00071 enum APP_TYPE { M_APP, QT_APP, QDECL_APP, EXEC_APP, UNKNOWN_APP };
00072 
00073 // Environment
00074 extern char ** environ;
00075 
00076 // pid of the invoked process
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 // Forwards Unix signals from invoker to the invoked process
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         // Restore signal handlers
00108         sigs_restore();
00109 
00110         // Write signal number to the self-pipe
00111         char signal_id = (char) sig;
00112         write(g_signal_pipe[1], &signal_id, 1);
00113 
00114         // Send the signal to itself using the default handler
00115         raise(sig);
00116 #ifdef WITH_COVERAGE
00117         __gcov_flush();
00118 #endif
00119     }
00120 }
00121 
00122 // Sets signal actions for Unix signals
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 // Sets up the signal forwarder
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 // Sets up the default signal handler
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 // Shows a list of credentials that the client has
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 // Receive ACK
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 // Inits a socket connection for the given application type
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;  //AF_FILE;
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 // Receives pid of the invoked process.
00269 // Invoker doesn't know it, because the launcher daemon
00270 // is the one who forks.
00271 static uint32_t invoker_recv_pid(int fd)
00272 {
00273     // Receive action.
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     // Receive pid.
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 // Receives exit status of the invoked process
00289 static bool invoker_recv_exit(int fd, int* status)
00290 {
00291     uint32_t action;
00292 
00293     // Receive action.
00294     bool res = invoke_recv_msg(fd, &action);
00295 
00296     if (!res || (action != INVOKER_MSG_EXIT))
00297     {
00298         // Boosted application process was killed somehow.
00299         // Let's give applauncherd process some time to cope 
00300         // with this situation.
00301         sleep(2);
00302 
00303         // If nothing happend, return
00304         return false;
00305     }
00306   
00307     // Receive exit status.
00308     res = invoke_recv_msg(fd, (uint32_t*) status);
00309     return res;
00310 }
00311 
00312 // Sends magic number / protocol version
00313 static void invoker_send_magic(int fd, uint32_t options)
00314 {
00315     // Send magic.
00316     invoke_send_msg(fd, INVOKER_MSG_MAGIC | INVOKER_MSG_MAGIC_VERSION | options);
00317 }
00318 
00319 // Sends the process name to be invoked.
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 // Sends booster respawn delay
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 // Sends UID and GID
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 // Sends the environment variables
00379 static void invoker_send_env(int fd)
00380 {
00381     int i, n_vars;
00382 
00383     // Count environment variables.
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 // Sends I/O descriptors
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 // Sends the END message
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 // Prints the usage and exits with given status
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 // Return delay as integer 
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; // To distinguish success/failure after call
00492         delay = strtoul(delay_arg, NULL, 10);
00493 
00494         // Check for various possible errors
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     // Wait for launched process to exit
00512     if (wait_term)
00513     {
00514         // coverity[tainted_string_return_content]
00515         g_invoked_pid = invoker_recv_pid(socket_fd);
00516         debug("Booster's pid is %d \n ", g_invoked_pid);
00517 
00518         // Forward UNIX signals to the invoked process
00519         sigs_init();
00520 
00521         while(1)
00522         {
00523             // Setup things for select()
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             // sig_forwarder() handles signals.
00533             // We only have to receive those here.
00534             FD_SET(g_signal_pipe[0], &readfds);
00535             ndfs = (socket_fd > ndfs) ? socket_fd : ndfs;
00536 
00537             // Wait for something appearing in the pipes.
00538             if (select(ndfs + 1, &readfds, NULL, NULL, NULL) > 0)
00539             {
00540                 // Check if an exit status from the invoked application
00541                 if (FD_ISSET(socket_fd, &readfds))
00542                 {
00543                     bool res = invoker_recv_exit(socket_fd, &status);
00544 
00545                     if (!res)
00546                     {
00547                         // Because we are here, applauncherd.bin must be dead.
00548                         // Now we check if the invoked process is also dead
00549                         // and if not, we will kill it.
00550                         char filename[50];
00551                         snprintf(filename, sizeof(filename), "/proc/%d/cmdline", g_invoked_pid);
00552 
00553                         // Open filename for reading only
00554                         int fd = open(filename, O_RDONLY);
00555                         if (fd != -1)
00556                         {
00557                             // Application is still running
00558                             close(fd);
00559 
00560                             // Send a signal to kill the application too and exit.
00561                             // Sleep for some time to give
00562                             // the new applauncherd some time to load its boosters and
00563                             // the restart of g_invoked_pid succeeds.
00564 
00565                             sleep(10);
00566                             kill(g_invoked_pid, SIGKILL);
00567                             raise(SIGKILL);
00568                         }
00569                         else
00570                         {
00571                             // connection to application was lost
00572                             status = EXIT_FAILURE; 
00573                         }
00574                     }
00575                     break;
00576                 }
00577             }
00578         }
00579 
00580         // Restore default signal handlers
00581         sigs_restore();
00582     }
00583 
00584     return status;
00585 }
00586 
00587 // "normal" invoke through a socket connection
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     // Get process priority
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     // Connection with launcher process is established,
00601     // send the data.
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     // Connection with launcher is broken,
00629     // try to launch application via execve
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     // Fork if wait_term not set
00634     if(!wait_term)
00635     {
00636         // Fork a new process
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) /* parent process */
00645         {
00646             return;
00647         }
00648     }
00649 
00650     // Exec the process image
00651     execve(prog_name, prog_argv, environ);
00652     perror("execve");   /* execve() only returns on error */
00653     exit(EXIT_FAILURE);
00654 }
00655 
00656 // Invokes the given application
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         // This is a fallback if connection with the launcher
00666         // process is broken       
00667         int fd = invoker_init(app_type);
00668         if (fd == -1)
00669         {
00670             invoke_fallback(prog_argv, prog_name, wait_term);
00671         }
00672         // "normal" invoke through a socket connetion
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     // wait-term parameter by default
00700     magic_options |= INVOKER_MSG_MAGIC_OPTION_WAIT;
00701 
00702     // Called with a different name (old way of using invoker) ?
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     // Stops parsing args as soon as a non-option argument is encountered
00711     putenv("POSIXLY_CORRECT=1");
00712 
00713     // Options recognized
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     // Parse options
00732     // TODO: Move to a function
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             // nothing to do, it's by default now
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     // Option processing stops as soon as application name is encountered
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     // Check if application name isn't defined
00820     if (!prog_name)
00821     {
00822         report(report_error, "Application's name is not defined.\n");
00823         usage(1);
00824     }
00825 
00826     // Check if application exists
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     // Check that 
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     // Check if application type is unknown
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     // Send commands to the launcher daemon
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     // Sleep for delay before exiting
00859     if (delay)
00860     {
00861         // DBUS cannot cope some times if the invoker exits too early.
00862         debug("Delaying exit for %d seconds..\n", delay);
00863         sleep(delay);
00864     }
00865 
00866     return ret_val;
00867 }

Generated on Sat Jan 17 2015 19:23:27 for applauncherd by  doxygen 1.7.1