• Main Page
  • Files
  • File List
  • File Members

/home/bifh6/cs2009q3-i386/work/applauncherd-0.30.5+rq730927+0m6/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             report(report_error, "Can't send signal to application: %s \n", strerror(errno));
00093         }
00094 
00095         // Restore signal handlers
00096         sigs_restore();
00097 
00098         // Write signal number to the self-pipe
00099         char signal_id = (char) sig;
00100         write(g_signal_pipe[1], &signal_id, 1);
00101 
00102         // Send the signal to itself using the default handler
00103         raise(sig);
00104     }
00105 }
00106 
00107 // Sets signal actions for Unix signals
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 // Sets up the signal forwarder
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 // Sets up the default signal handler
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 // Shows a list of credentials that the client has
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 // Receive ACK
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 // Inits a socket connection for the given application type
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;  //AF_FILE;
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 // Receives pid of the invoked process.
00254 // Invoker doesn't know it, because the launcher daemon
00255 // is the one who forks.
00256 static uint32_t invoker_recv_pid(int fd)
00257 {
00258     // Receive action.
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     // Receive pid.
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 // Receives exit status of the invoked process
00274 static bool invoker_recv_exit(int fd, int* status)
00275 {
00276     uint32_t action;
00277 
00278     // Receive action.
00279     bool res = invoke_recv_msg(fd, &action);
00280 
00281     if (!res || (action != INVOKER_MSG_EXIT))
00282     {
00283         // Boosted application process was killed somehow.
00284         // Let's give applauncherd process some time to cope 
00285         // with this situation.
00286         sleep(2);
00287 
00288         // If nothing happend, return
00289         return false;
00290     }
00291   
00292     // Receive exit status.
00293     res = invoke_recv_msg(fd, (uint32_t*) status);
00294     return res;
00295 }
00296 
00297 // Sends magic number / protocol version
00298 static void invoker_send_magic(int fd, uint32_t options)
00299 {
00300     // Send magic.
00301     invoke_send_msg(fd, INVOKER_MSG_MAGIC | INVOKER_MSG_MAGIC_VERSION | options);
00302 }
00303 
00304 // Sends the process name to be invoked.
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 // Sends booster respawn delay
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 // Sends UID and GID
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 // Sends the environment variables
00364 static void invoker_send_env(int fd)
00365 {
00366     int i, n_vars;
00367 
00368     // Count environment variables.
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 // Sends I/O descriptors
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 // Sends the END message
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 // Prints the usage and exits with given status
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 // Return delay as integer 
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; // To distinguish success/failure after call
00477         delay = strtoul(delay_arg, NULL, 10);
00478 
00479         // Check for various possible errors
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     // Wait for launched process to exit
00497     if (wait_term)
00498     {
00499         // coverity[tainted_string_return_content]
00500         g_invoked_pid = invoker_recv_pid(socket_fd);
00501         debug("Booster's pid is %d \n ", g_invoked_pid);
00502 
00503         // Forward UNIX signals to the invoked process
00504         sigs_init();
00505 
00506         while(1)
00507         {
00508             // Setup things for select()
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             // Wait for something appearing in the pipes.
00521             if (select(ndfs + 1, &readfds, NULL, NULL, NULL) > 0)
00522             {
00523                 // Check if an exit status from the invoked application
00524                 if (FD_ISSET(socket_fd, &readfds))
00525                 {
00526                     bool res = invoker_recv_exit(socket_fd, &status);
00527 
00528                     if (!res)
00529                     {
00530                         // Check if the process
00531                         // on the other side of socket just died / was killed.
00532                         // We check from /proc whether the launched program is still
00533                         // running.
00534                         char filename[50];
00535                         snprintf(filename, sizeof(filename), "/proc/%d/cmdline", g_invoked_pid);
00536 
00537                         // Open filename for reading only
00538                         int fd = open(filename, O_RDONLY);
00539                         if (fd != -1)
00540                         {
00541                             // Application is still running, so applauncherd must be dead,
00542                             // because the blocking read on the socket returned.
00543                             close(fd);
00544 
00545                             // Send a signal to kill the application too and exit.
00546                             // We must do this, because the invoker<->application
00547                             // mapping is lost. Sleep for some time to give
00548                             // the new applauncherd some time to load its boosters and
00549                             // the restart of g_invoked_pid succeeds.
00550 
00551                             sleep(10);
00552                             kill(g_invoked_pid, SIGKILL);
00553                             raise(SIGKILL);
00554                         }
00555                         else
00556                         {
00557                             // connection to application was lost
00558                             status = EXIT_FAILURE; 
00559                         }
00560                     }
00561                     break;
00562                 }
00563                 // Check if we got a UNIX signal.
00564                 else if (FD_ISSET(g_signal_pipe[0], &readfds))
00565                 {
00566                     // Clean up the pipe
00567                     char signal_id;
00568                     read(g_signal_pipe[0], &signal_id, sizeof(signal_id));
00569 
00570                     // Set signals forwarding to the invoked process again
00571                     // (they were reset by the signal forwarder).
00572                     sigs_init();
00573                 }
00574             }
00575         }
00576 
00577         // Restore default signal handlers
00578         sigs_restore();
00579     }
00580 
00581     return status;
00582 }
00583 
00584 // "normal" invoke through a socket connection
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     // Get process priority
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     // Connection with launcher process is established,
00598     // send the data.
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     // Connection with launcher is broken,
00626     // try to launch application via execve
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     // Fork if wait_term not set
00631     if(!wait_term)
00632     {
00633         // Fork a new process
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) /* parent process */
00642         {
00643             return;
00644         }
00645     }
00646 
00647     // Exec the process image
00648     execve(prog_name, prog_argv, environ);
00649     perror("execve");   /* execve() only returns on error */
00650     exit(EXIT_FAILURE);
00651 }
00652 
00653 // Invokes the given application
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         // This is a fallback if connection with the launcher
00663         // process is broken       
00664         int fd = invoker_init(app_type);
00665         if (fd == -1)
00666         {
00667             invoke_fallback(prog_argv, prog_name, wait_term);
00668         }
00669         // "normal" invoke through a socket connetion
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     // wait-term parameter by default
00697     magic_options |= INVOKER_MSG_MAGIC_OPTION_WAIT;
00698 
00699     // Called with a different name (old way of using invoker) ?
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     // Stops parsing args as soon as a non-option argument is encountered
00708     putenv("POSIXLY_CORRECT=1");
00709 
00710     // Options recognized
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     // Parse options
00729     // TODO: Move to a function
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             // nothing to do, it's by default now
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     // Option processing stops as soon as application name is encountered
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     // Check if application name isn't defined
00823     if (!prog_name)
00824     {
00825         report(report_error, "Application's name is not defined.\n");
00826         usage(1);
00827     }
00828 
00829     // Check if application exists
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     // Check that 
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     // Check if application type is unknown
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     // Send commands to the launcher daemon
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     // Sleep for delay before exiting
00862     if (delay)
00863     {
00864         // DBUS cannot cope some times if the invoker exits too early.
00865         debug("Delaying exit for %d seconds..\n", delay);
00866         sleep(delay);
00867     }
00868 
00869     return ret_val;
00870 }

Generated on Mon Jul 4 2011 14:23:01 for applauncherd by  doxygen 1.7.1