applauncherd
invoker.c
Go to the documentation of this file.
1 /***************************************************************************
2 **
3 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** Copyright (c) 2012 - 2021 Jolla Ltd.
5 ** Copyright (c) 2021 Open Mobile Platform LLC.
6 ** All rights reserved.
7 ** Contact: Nokia Corporation (directui@nokia.com)
8 **
9 ** This file is part of applauncherd
10 **
11 ** If you have questions regarding the use of this file, please contact
12 ** Nokia at directui@nokia.com.
13 **
14 ** This library is free software; you can redistribute it and/or
15 ** modify it under the terms of the GNU Lesser General Public
16 ** License version 2.1 as published by the Free Software Foundation
17 ** and appearing in the file LICENSE.LGPL included in the packaging
18 ** of this file.
19 **
20 ****************************************************************************/
21 
22 #define _GNU_SOURCE
23 
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <stdbool.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/uio.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <sys/wait.h>
40 #include <limits.h>
41 #include <getopt.h>
42 #include <fcntl.h>
43 #include <time.h>
44 #include <poll.h>
45 #include <dbus/dbus.h>
46 
47 #include "report.h"
48 #include "protocol.h"
49 #include "invokelib.h"
50 #include "search.h"
51 
52 #define BOOSTER_SESSION "silica-session"
53 #define BOOSTER_GENERIC "generic"
54 
55 /* Setting VERBOSE_SIGNALS to non-zero value logs receiving of
56  * async-signals - which is useful only when actively debugging
57  * booster / invoker interoperation.
58  */
59 #define VERBOSE_SIGNALS 01
60 
61 // Utility functions
62 static char *strip(char *str)
63 {
64  if (str) {
65  char *dst = str;
66  char *src = str;
67  while (*src && isspace(*src))
68  ++src;
69  for (;;) {
70  while (*src && !isspace(*src))
71  *dst++ = *src++;
72  while (*src && isspace(*src))
73  ++src;
74  if (!*src)
75  break;
76  *dst++ = ' ';
77  }
78  *dst = 0;
79  }
80  return str;
81 }
82 
83 static char *slice(const char *pos, const char **ppos, const char *delim)
84 {
85  char *tok = NULL;
86  if (pos) {
87  const char *beg = pos;
88  while (*pos && !strchr(delim, *pos))
89  ++pos;
90  tok = strndup(beg, pos - beg);
91  if (*pos)
92  ++pos;
93  }
94  if (ppos)
95  *ppos = pos;
96  return tok;
97 }
98 
99 static char **split(const char *str, const char *delim)
100 {
101  char **arr = NULL;
102  if (str) {
103  /* Upper limit for token count is number of delimeters + one */
104  int n = 1;
105  for (const char *pos = str; *pos; ++pos)
106  if (strchr(delim, *pos))
107  ++n;
108 
109  /* Upper limit for required array size is token count + one */
110  arr = calloc(n + 1, sizeof *arr);
111 
112  /* Fill in the array */
113  int i = 0;
114  while (*str) {
115  char *tok = slice(str, &str, delim);
116  if (*strip(tok))
117  arr[i++] = tok;
118  else
119  free(tok);
120  }
121  arr[i] = NULL;
122  }
123  return arr;
124 }
125 
126 // Delay before exit.
127 static const unsigned int EXIT_DELAY = 0;
128 static const unsigned int MIN_EXIT_DELAY = 1;
129 static const unsigned int MAX_EXIT_DELAY = 86400;
130 
131 // Delay before a new booster is started. This will
132 // be sent to the launcher daemon.
133 static const unsigned int RESPAWN_DELAY = 1;
134 static const unsigned int MIN_RESPAWN_DELAY = 0;
135 static const unsigned int MAX_RESPAWN_DELAY = 10;
136 
137 static const unsigned char EXIT_STATUS_APPLICATION_NOT_FOUND = 0x7f;
138 
139 // Environment
140 extern char ** environ;
141 
142 // pid of the invoked process
143 static pid_t g_invoked_pid = -1;
144 
145 static void sigs_restore(void);
146 static void sigs_init(void);
147 
149 static int g_signal_pipe[2] = { -1, -1 };
150 
151 // Forwards Unix signals from invoker to the invoked process
152 static void sig_forwarder(int sig)
153 {
154 #if VERBOSE_SIGNALS
155  static const char m[] = "*** signal\n";
156  if (write(STDERR_FILENO, m, sizeof m - 1) == -1) {
157  // dontcare
158  }
159 #endif
160 
161  // Write signal number to the self-pipe
162  char signal_id = (char) sig;
163  if (g_signal_pipe[1] == -1 || write(g_signal_pipe[1], &signal_id, 1) != 1) {
164  const char m[] = "*** signal pipe write failure, terminating\n";
165  if (write(STDERR_FILENO, m, sizeof m - 1) == -1) {
166  // dontcare
167  }
168  _exit(EXIT_FAILURE);
169  }
170 }
171 
172 // Sets signal actions for Unix signals
173 static void sigs_set(struct sigaction *sig)
174 {
175  sigaction(SIGINT, sig, NULL);
176  sigaction(SIGTERM, sig, NULL);
177 }
178 
179 // Sets up the signal forwarder
180 static void sigs_init(void)
181 {
182  struct sigaction sig;
183 
184  memset(&sig, 0, sizeof(sig));
185  sig.sa_flags = SA_RESTART;
186  sig.sa_handler = sig_forwarder;
187 
188  sigs_set(&sig);
189 }
190 
191 // Sets up the default signal handler
192 static void sigs_restore(void)
193 {
194  struct sigaction sig;
195 
196  memset(&sig, 0, sizeof(sig));
197  sig.sa_flags = SA_RESTART;
198  sig.sa_handler = SIG_DFL;
199 
200  sigs_set(&sig);
201 }
202 
203 static unsigned timestamp(void)
204 {
205  struct timespec ts = { 0, 0 };
206  if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1 &&
207  clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
208  error("can't obtain a monotonic timestamp\n");
209  exit(EXIT_FAILURE);
210  }
211 
212  /* NOTE: caller must assume overflow to happen i.e.
213  * the return values themselves mean nothing, only
214  * differences between return values should be used.
215  */
216  return ((unsigned)(ts.tv_sec * 1000u) +
217  (unsigned)(ts.tv_nsec / (1000 * 1000u)));
218 }
219 
220 static bool shutdown_socket(int socket_fd)
221 {
222  bool disconnected = false;
223 
224  /* Close transmit end from our side, then wait
225  * for peer to receive EOF and close the receive
226  * end too.
227  */
228 
229  info("trying to disconnect booster socket...\n");
230 
231  if (shutdown(socket_fd, SHUT_WR) == -1) {
232  warning("socket shutdown failed: %m\n");
233  goto EXIT;
234  }
235 
236  unsigned started = timestamp();
237  unsigned timeout = 5000;
238  for (;;) {
239  unsigned elapsed = timestamp() - started;
240  if (elapsed >= timeout)
241  break;
242 
243  struct pollfd pfd = {
244  .fd = socket_fd,
245  .events = POLLIN,
246  .revents = 0,
247  };
248 
249  info("waiting for booster socket input...\n");
250  int rc = poll(&pfd, 1, (int)(timeout - elapsed));
251 
252  if (rc == 0)
253  break;
254 
255  if (rc == -1) {
256  if (errno == EINTR || errno == EAGAIN)
257  continue;
258  warning("socket poll failed: %m\n");
259  goto EXIT;
260  }
261 
262  char buf[256];
263  rc = recv(socket_fd, buf, sizeof buf, MSG_DONTWAIT);
264  if (rc == 0) {
265  /* EOF -> peer closed the socket */
266  disconnected = true;
267  goto EXIT;
268  }
269 
270  if (rc == -1) {
271  warning("socket read failed: %m\n");
272  goto EXIT;
273  }
274  }
275  warning("socket poll timeout\n");
276 
277 EXIT:
278  if (disconnected)
279  info("booster socket was succesfully disconnected\n");
280  else
281  warning("could not disconnect booster socket\n");
282 
283  return disconnected;
284 }
285 
286 static void kill_application(pid_t pid)
287 {
288  if (pid == -1) {
289  warning("application pid is not known, can't kill it");
290  goto EXIT;
291  }
292 
293  warning("sending SIGTERM to application (pid=%d)", (int)pid);
294 
295  if (kill(pid, SIGTERM) == -1)
296  goto FAIL;
297 
298  for (int i = 0; i < 10; ++i) {
299  sleep(1);
300  if (kill(pid, 0) == -1)
301  goto FAIL;
302  }
303 
304  warning("sending SIGKILL to application (pid=%d)", (int)pid);
305 
306  if (kill(pid, SIGKILL) == -1)
307  goto FAIL;
308 
309  for (int i = 0; i < 10; ++i) {
310  sleep(1);
311  if (kill(pid, 0) == -1)
312  goto FAIL;
313  }
314 
315  warning("application (pid=%d) did not exit", (int)pid);
316  goto EXIT;
317 
318 FAIL:
319  if (errno == ESRCH)
320  info("application (pid=%d) has exited", (int)pid);
321  else
322  warning("application (pid=%d) kill failed: %m", (int)pid);
323 
324 EXIT:
325  return;
326 }
327 
328 // Receive ACK
329 static bool invoke_recv_ack(int fd)
330 {
331  uint32_t action;
332 
333  invoke_recv_msg(fd, &action);
334 
335  if (action != INVOKER_MSG_ACK)
336  {
337  die(1, "Received wrong ack (%08x)\n", action);
338  }
339 
340  return true;
341 }
342 
343 // Inits a socket connection for the given application type
344 static int invoker_init(const char *app_type, const char *app_name)
345 {
346  info("try type=%s app=%s ...", app_type, app_name);
347 
348  bool connected = false;
349  int fd = -1;
350 
351  /* Sanity check args */
352  if (!app_type || strchr(app_type, '/'))
353  goto EXIT;
354  if (app_name && strchr(app_name, '/'))
355  goto EXIT;
356 
357  const char *runtimeDir = getenv("XDG_RUNTIME_DIR");
358  if (!runtimeDir || !*runtimeDir) {
359  error("XDG_RUNTIME_DIR is not defined.\n");
360  goto EXIT;
361  }
362 
363  if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
364  error("Failed to create socket: %m\n");
365  goto EXIT;
366  }
367 
368  struct sockaddr_un sun = {
369  .sun_family = AF_UNIX,
370  };
371  int maxSize = sizeof(sun.sun_path);
372  int length;
373 
374  if (app_name)
375  length = snprintf(sun.sun_path, maxSize, "%s/mapplauncherd/_%s/%s/socket",
376  runtimeDir, app_name, app_type);
377  else
378  length = snprintf(sun.sun_path, maxSize, "%s/mapplauncherd/%s",
379  runtimeDir, app_type);
380 
381  if (length <= 0 || length >= maxSize) {
382  if (app_name)
383  error("Invalid booster type: %s / application: %s\n",
384  app_type, app_name);
385  else
386  error("Invalid booster type: %s\n", app_type);
387  goto EXIT;
388  }
389 
390  if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
391  if (errno != ENOENT)
392  warning("connect(\"%s\") failed: %m\n", sun.sun_path);
393  goto EXIT;
394  }
395 
396  info("connected to: %s\n", sun.sun_path);
397  connected = true;
398 
399 EXIT:
400  if (!connected && fd != -1)
401  close(fd), fd = -1;
402  return fd;
403 }
404 
405 // Receives pid of the invoked process.
406 // Invoker doesn't know it, because the launcher daemon
407 // is the one who forks.
408 static uint32_t invoker_recv_pid(int fd)
409 {
410  // Receive action.
411  uint32_t action;
412  invoke_recv_msg(fd, &action);
413  if (action != INVOKER_MSG_PID)
414  die(1, "Received a bad message id (%08x)\n", action);
415 
416  // Receive pid.
417  uint32_t pid = 0;
418  invoke_recv_msg(fd, &pid);
419  if (pid == 0)
420  die(1, "Received a zero pid \n");
421 
422  return pid;
423 }
424 
425 // Receives exit status of the invoked process
426 static bool invoker_recv_exit(int fd, int* status)
427 {
428  uint32_t action;
429 
430  // Receive action.
431  bool res = invoke_recv_msg(fd, &action);
432 
433  if (!res || (action != INVOKER_MSG_EXIT))
434  {
435  // Boosted application process was killed somehow.
436  // Let's give applauncherd process some time to cope
437  // with this situation.
438  sleep(2);
439 
440  // If nothing happend, return
441  return false;
442  }
443 
444  // Receive exit status.
445  res = invoke_recv_msg(fd, (uint32_t*) status);
446  return res;
447 }
448 
449 // Sends magic number / protocol version
450 static void invoker_send_magic(int fd, uint32_t options)
451 {
452  // Send magic.
453  invoke_send_msg(fd, INVOKER_MSG_MAGIC | INVOKER_MSG_MAGIC_VERSION | options);
454 }
455 
456 // Sends the process name to be invoked.
457 static void invoker_send_name(int fd, const char *name)
458 {
459  invoke_send_msg(fd, INVOKER_MSG_NAME);
460  invoke_send_str(fd, name);
461 }
462 
463 static void invoker_send_exec(int fd, char *exec)
464 {
465  invoke_send_msg(fd, INVOKER_MSG_EXEC);
466  invoke_send_str(fd, exec);
467 }
468 
469 static void invoker_send_args(int fd, int argc, char **argv)
470 {
471  int i;
472 
473  invoke_send_msg(fd, INVOKER_MSG_ARGS);
474  invoke_send_msg(fd, argc);
475  for (i = 0; i < argc; i++)
476  {
477  info("param %d %s \n", i, argv[i]);
478  invoke_send_str(fd, argv[i]);
479  }
480 }
481 
482 static void invoker_send_prio(int fd, int prio)
483 {
484  invoke_send_msg(fd, INVOKER_MSG_PRIO);
485  invoke_send_msg(fd, prio);
486 }
487 
488 // Sends booster respawn delay
489 static void invoker_send_delay(int fd, int delay)
490 {
491  invoke_send_msg(fd, INVOKER_MSG_DELAY);
492  invoke_send_msg(fd, delay);
493 }
494 
495 // Sends UID and GID
496 static void invoker_send_ids(int fd, int uid, int gid)
497 {
498  invoke_send_msg(fd, INVOKER_MSG_IDS);
499  invoke_send_msg(fd, uid);
500  invoke_send_msg(fd, gid);
501 }
502 
503 // Sends the environment variables
504 static void invoker_send_env(int fd)
505 {
506  int i, n_vars;
507 
508  // Count environment variables.
509  for (n_vars = 0; environ[n_vars] != NULL; n_vars++) ;
510 
511  invoke_send_msg(fd, INVOKER_MSG_ENV);
512  invoke_send_msg(fd, n_vars);
513 
514  for (i = 0; i < n_vars; i++)
515  {
516  invoke_send_str(fd, environ[i]);
517  }
518 
519  return;
520 }
521 
522 // Sends I/O descriptors
523 static void invoker_send_io(int fd)
524 {
525  struct msghdr msg;
526  struct cmsghdr *cmsg = NULL;
527  int io[3] = { 0, 1, 2 };
528  char buf[CMSG_SPACE(sizeof(io))];
529  struct iovec iov;
530  int dummy;
531 
532  memset(&msg, 0, sizeof(struct msghdr));
533 
534  iov.iov_base = &dummy;
535  iov.iov_len = 1;
536 
537  msg.msg_iov = &iov;
538  msg.msg_iovlen = 1;
539  msg.msg_control = buf;
540  msg.msg_controllen = sizeof(buf);
541 
542  cmsg = CMSG_FIRSTHDR(&msg);
543  cmsg->cmsg_len = CMSG_LEN(sizeof(io));
544  cmsg->cmsg_level = SOL_SOCKET;
545  cmsg->cmsg_type = SCM_RIGHTS;
546 
547  memcpy(CMSG_DATA(cmsg), io, sizeof(io));
548 
549  msg.msg_controllen = cmsg->cmsg_len;
550 
551  invoke_send_msg(fd, INVOKER_MSG_IO);
552  if (sendmsg(fd, &msg, 0) < 0)
553  {
554  warning("sendmsg failed in invoker_send_io: %s \n", strerror(errno));
555  }
556 
557  return;
558 }
559 
560 // Sends the END message
561 static void invoker_send_end(int fd)
562 {
563  invoke_send_msg(fd, INVOKER_MSG_END);
564  invoke_recv_ack(fd);
565 
566 }
567 
568 // Prints the usage and exits with given status
569 static void usage(int status)
570 {
571  printf("\nUsage: %s [options] [--type=TYPE] [file] [args]\n\n"
572  "Launch applications compiled as a shared library (-shared) or\n"
573  "a position independent executable (-pie) through mapplauncherd.\n\n"
574  "TYPE chooses the type of booster used. Qt-booster may be used to\n"
575  "launch anything. Possible values for TYPE:\n"
576  " qt5 Launch a Qt 5 application.\n"
577  " qtquick2 Launch a Qt Quick 2 (QML) application.\n"
578  " silica-qt5 Launch a Sailfish Silica application.\n"
579  " generic Launch any application, even if it's not a library.\n\n"
580  "The TYPE may also be a comma delimited list of boosters to try. The first available\n"
581  "booster will be used.\n\n"
582  "Options:\n"
583  " -d, --delay SECS After invoking sleep for SECS seconds\n"
584  " (default %d).\n"
585  " -r, --respawn SECS After invoking respawn new booster after SECS seconds\n"
586  " (default %d, max %d).\n"
587  " -w, --wait-term Wait for launched process to terminate (default).\n"
588  " -n, --no-wait Do not wait for launched process to terminate.\n"
589  " -G, --global-syms Places symbols in the application binary and its\n"
590  " libraries to the global scope.\n"
591  " See RTLD_GLOBAL in the dlopen manual page.\n"
592  " -s, --single-instance Launch the application as a single instance.\n"
593  " The existing application window will be activated\n"
594  " if already launched.\n"
595  " -o, --keep-oom-score Notify invoker that the launched process should inherit oom_score_adj\n"
596  " from the booster. The score is reset to 0 normally.\n"
597  " -T, --test-mode Invoker test mode. Also control file in root home should be in place.\n"
598  " -F, --desktop-file Desktop file of the application to notify lipstick of launching app.\n"
599  " -h, --help Print this help.\n\n"
600  "Example: %s --type=qt5 /usr/bin/helloworld\n\n",
601  PROG_NAME_INVOKER, EXIT_DELAY, RESPAWN_DELAY, MAX_RESPAWN_DELAY, PROG_NAME_INVOKER);
602 
603  exit(status);
604 }
605 
606 // Return delay as integer
607 static unsigned int get_delay(char *delay_arg, char *param_name,
608  unsigned int min_value, unsigned int max_value)
609 {
610  unsigned int delay = EXIT_DELAY;
611 
612  if (delay_arg)
613  {
614  errno = 0; // To distinguish success/failure after call
615  delay = strtoul(delay_arg, NULL, 10);
616 
617  // Check for various possible errors
618  if ((errno == ERANGE && delay == ULONG_MAX)
619  || delay < min_value
620  || delay > max_value)
621  {
622  report(report_error, "Wrong value of %s parameter: %s\n", param_name, delay_arg);
623  usage(1);
624  }
625  }
626 
627  return delay;
628 }
629 
630 static void notify_app_lauch(const char *desktop_file)
631 {
632  DBusConnection *connection;
633  DBusMessage *message;
634  DBusError error;
635 
636  dbus_error_init (&error);
637  connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
638 
639  if (connection) {
640  message = dbus_message_new_method_call("org.nemomobile.lipstick", "/LauncherModel",
641  "org.nemomobile.lipstick.LauncherModel", "notifyLaunching");
642  dbus_message_append_args(message, DBUS_TYPE_STRING, &desktop_file, DBUS_TYPE_INVALID);
643 
644  dbus_connection_send(connection, message, NULL);
645  dbus_message_unref(message);
646  dbus_connection_flush(connection);
647  } else {
648  info("Failed to connect to the DBus session bus: %s", error.message);
649  dbus_error_free(&error);
650  return;
651  }
652 }
653 
654 static int wait_for_launched_process_to_exit(int socket_fd)
655 {
656  int exit_status = EXIT_FAILURE;
657  int exit_signal = 0;
658 
659  // coverity[tainted_string_return_content]
660  g_invoked_pid = invoker_recv_pid(socket_fd);
661  info("Booster's pid is %d \n ", g_invoked_pid);
662 
663  // Setup signal handlers
664  sigs_init();
665 
666  for (;;) {
667  // Setup things for select()
668  fd_set readfds;
669  int ndfs = 0;
670 
671  FD_ZERO(&readfds);
672 
673  FD_SET(socket_fd, &readfds);
674  ndfs = (socket_fd > ndfs) ? socket_fd : ndfs;
675 
676  // sig_forwarder() handles signals.
677  // We only have to receive those here.
678  FD_SET(g_signal_pipe[0], &readfds);
679  ndfs = (g_signal_pipe[0] > ndfs) ? g_signal_pipe[0] : ndfs;
680 
681  // Wait for something appearing in the pipes.
682  if (select(ndfs + 1, &readfds, NULL, NULL, NULL) == -1) {
683  if (errno == EINTR || errno == EAGAIN)
684  continue;
685  warning("socket select failed: %m\n");
686  break;
687  }
688 
689  // Check if we got exit status from the invoked application
690  if (FD_ISSET(socket_fd, &readfds)) {
691  if (!invoker_recv_exit(socket_fd, &exit_status)) {
692  // connection to application was lost
693  exit_status = EXIT_FAILURE;
694  } else {
695  // there is no need to kill the application
696  g_invoked_pid = -1;
697  }
698  break;
699  }
700 
701  // Check if we got a UNIX signal.
702  if (FD_ISSET(g_signal_pipe[0], &readfds)) {
703  // Clean up the pipe
704  char signal_id = 0;
705  if (read(g_signal_pipe[0], &signal_id, 1) != 1) {
706  error("signal pipe read failure, terminating\n");
707  exit(EXIT_FAILURE);
708  }
709  exit_signal = signal_id;
710  if (exit_signal == SIGTERM)
711  exit_status = EXIT_SUCCESS;
712  break;
713  }
714  }
715 
716  // Restore default signal handlers
717  sigs_restore();
718 
719  if (exit_status != EXIT_SUCCESS)
720  warning("application (pid=%d) exit(%d) signal(%d)\n",
721  (int)g_invoked_pid, exit_status, exit_signal);
722  else
723  info("application (pid=%d) exit(%d) signal(%d)\n",
724  (int)g_invoked_pid, exit_status, exit_signal);
725 
726  if (socket_fd != -1) {
727  if (shutdown_socket(socket_fd))
728  g_invoked_pid = -1;
729  close(socket_fd),
730  socket_fd = -1;
731  if (g_invoked_pid != -1)
733  }
734 
735  return exit_status;
736 }
737 
738 typedef struct InvokeArgs {
740  char **prog_argv;
741  char *prog_name;
742  const char *app_type;
743  const char *app_name;
744  uint32_t magic_options;
745  bool wait_term;
746  unsigned int respawn_delay;
747  bool test_mode;
748  const char *desktop_file;
749  unsigned int exit_delay;
751 
752 #define INVOKE_ARGS_INIT {\
753  .prog_argc = 0,\
754  .prog_argv = NULL,\
755  .prog_name = NULL,\
756  .app_type = NULL,\
757  .app_name = "default",\
758  .magic_options = INVOKER_MSG_MAGIC_OPTION_WAIT,\
759  .wait_term = true,\
760  .respawn_delay = RESPAWN_DELAY,\
761  .test_mode = false,\
762  .desktop_file = NULL,\
763  .exit_delay = EXIT_DELAY,\
764 }
765 
766 // "normal" invoke through a socket connection
767 static int invoke_remote(int socket_fd, const InvokeArgs *args)
768 {
769  int exit_status = EXIT_FAILURE;
770 
771  // Get process priority
772  errno = 0;
773  int prog_prio = getpriority(PRIO_PROCESS, 0);
774  if (errno && prog_prio < 0)
775  {
776  prog_prio = 0;
777  }
778 
779  // Connection with launcher process is established,
780  // send the data.
781  invoker_send_magic(socket_fd, args->magic_options);
782  invoker_send_name(socket_fd, args->prog_name);
783  invoker_send_exec(socket_fd, args->prog_argv[0]);
784  invoker_send_args(socket_fd, args->prog_argc, args->prog_argv);
785  invoker_send_prio(socket_fd, prog_prio);
786  invoker_send_delay(socket_fd, args->respawn_delay);
787  invoker_send_ids(socket_fd, getuid(), getgid());
788  invoker_send_io(socket_fd);
789  invoker_send_env(socket_fd);
790  invoker_send_end(socket_fd);
791 
792  if (args->desktop_file)
794 
795  if (args->wait_term) {
796  exit_status = wait_for_launched_process_to_exit(socket_fd),
797  socket_fd = -1;
798  }
799 
800  if (socket_fd != -1)
801  close(socket_fd);
802 
803  return exit_status;
804 }
805 
806 static void invoke_fallback(const InvokeArgs *args)
807 {
808  // Connection with launcher is broken,
809  // try to launch application via execve
810  warning("Connection with launcher process is broken. \n");
811  error("Start application %s as a binary executable without launcher...\n", args->prog_name);
812 
813  // Fork if wait_term not set
814  if (!args->wait_term)
815  {
816  // Fork a new process
817  pid_t newPid = fork();
818 
819  if (newPid == -1)
820  {
821  error("Invoker failed to fork. \n");
822  exit(EXIT_FAILURE);
823  }
824  else if (newPid != 0) /* parent process */
825  {
826  return;
827  }
828  }
829 
830  // Exec the process image
831  execve(args->prog_name, args->prog_argv, environ);
832  perror("execve"); /* execve() only returns on error */
833  exit(EXIT_FAILURE);
834 }
835 
836 // Invokes the given application
837 static int invoke(InvokeArgs *args)
838 {
839  /* Note: Contents of 'args' are assumed to have been
840  * checked and sanitized before invoke() call.
841  */
842 
843  int status = EXIT_FAILURE;
844 
845  /* The app can be launched with a comma delimited list of
846  * booster types to attempt.
847  */
848  char **types = split(args->app_type, ",");
849 
850  int fd = -1;
851 
852  /* Session booster is a special case:
853  * - is never going to be application specific
854  * - can use and still uses legacy socket path
855  * - mutually exclusive with all other choises
856  * - no fallbacks should be utilized
857  */
858 
859  bool tried_session = false;
860  for (size_t i = 0; !tried_session && types[i]; ++i) {
861  if (strcmp(types[i], BOOSTER_SESSION))
862  continue;
863  tried_session = true;
864  fd = invoker_init(types[i], NULL);
865  }
866 
867  /* Application aware boosters
868  * - have fallback strategy, but it
869  * - must not cross application vs "default" boundary
870  */
871  if (fd == -1 && !tried_session) {
872  bool tried_generic = false;
873  for (size_t i = 0; fd == -1 && types[i]; ++i) {
874  if (!strcmp(types[i], BOOSTER_GENERIC))
875  tried_generic = true;
876  fd = invoker_init(types[i], args->app_name);
877  }
878  if (fd == -1 && !tried_generic)
880  }
881 
882  if (fd != -1) {
883  /* "normal" invoke through a socket connetion */
884  status = invoke_remote(fd, args),
885  fd = -1;
886  } else if (tried_session) {
887  warning("Launch failed, session booster is not available.\n");
888  } else if (strcmp(args->app_name, "default")) {
889  /* Boosters that deal explicitly with one application only
890  * must be assumed to run within sandbox -> skipping boosting
891  * would also skip sandboxing -> no direct launch fallback
892  */
893  warning("Launch failed, application specific booster is not available.\n");
894  } else {
895  /* Give up and start unboosted */
896  warning("Also fallback boosters failed, launch without boosting.\n");
897  invoke_fallback(args);
898  /* Returns only in case of: no-wait was specified and fork succeeded */
899  status = EXIT_SUCCESS;
900  }
901 
902  for (int i = 0; types[i]; ++i)
903  free(types[i]);
904  free(types);
905 
906  return status;
907 }
908 
909 int main(int argc, char *argv[])
910 {
912 
913  // Called with a different name (old way of using invoker) ?
914  if (!strstr(argv[0], PROG_NAME_INVOKER) )
915  {
916  die(1,
917  "Incorrect use of invoker, don't use symlinks. "
918  "Run invoker explicitly from e.g. a D-Bus service file instead.\n");
919  }
920 
921  // Options recognized
922  struct option longopts[] = {
923  {"help", no_argument, NULL, 'h'},
924  {"wait-term", no_argument, NULL, 'w'},
925  {"no-wait", no_argument, NULL, 'n'},
926  {"global-syms", no_argument, NULL, 'G'},
927  {"deep-syms", no_argument, NULL, 'D'},
928  {"single-instance", no_argument, NULL, 's'},
929  {"keep-oom-score", no_argument, NULL, 'o'},
930  {"daemon-mode", no_argument, NULL, 'o'}, // Legacy alias
931  {"test-mode", no_argument, NULL, 'T'},
932  {"type", required_argument, NULL, 't'},
933  {"application", required_argument, NULL, 'a'},
934  {"delay", required_argument, NULL, 'd'},
935  {"respawn", required_argument, NULL, 'r'},
936  {"splash", required_argument, NULL, 'S'},
937  {"splash-landscape", required_argument, NULL, 'L'},
938  {"desktop-file", required_argument, NULL, 'F'},
939  {"verbose", no_argument, NULL, 'v'},
940  {0, 0, 0, 0}
941  };
942 
943  // Parse options
944  // The use of + for POSIXLY_CORRECT behavior is a GNU extension, but avoids polluting
945  // the environment
946  int opt;
947  while ((opt = getopt_long(argc, argv, "+hvcwnGDsoTd:t:a:r:S:L:F:", longopts, NULL)) != -1)
948  {
949  switch(opt)
950  {
951  case 'h':
952  usage(0);
953  break;
954 
955  case 'v':
956  report_set_type(report_get_type() + 1);
957  break;
958 
959  case 'w':
960  // nothing to do, it's by default now
961  break;
962 
963  case 'o':
964  args.magic_options |= INVOKER_MSG_MAGIC_OPTION_OOM_ADJ_DISABLE;
965  break;
966 
967  case 'n':
968  args.wait_term = false;
969  args.magic_options &= (~INVOKER_MSG_MAGIC_OPTION_WAIT);
970  break;
971 
972  case 'G':
973  args.magic_options |= INVOKER_MSG_MAGIC_OPTION_DLOPEN_GLOBAL;
974  break;
975 
976  case 'D':
977  args.magic_options |= INVOKER_MSG_MAGIC_OPTION_DLOPEN_DEEP;
978  break;
979 
980  case 'T':
981  args.test_mode = true;
982  break;
983 
984  case 't':
985  args.app_type = optarg;
986  break;
987 
988  case 'a':
989  args.app_name = optarg;
990  break;
991 
992  case 'd':
993  args.exit_delay = get_delay(optarg, "delay", MIN_EXIT_DELAY, MAX_EXIT_DELAY);
994  break;
995 
996  case 'r':
997  args.respawn_delay = get_delay(optarg, "respawn delay",
999  break;
1000 
1001  case 's':
1002  args.magic_options |= INVOKER_MSG_MAGIC_OPTION_SINGLE_INSTANCE;
1003  break;
1004 
1005  case 'S':
1006  case 'L':
1007  // Removed splash support. Ignore.
1008  break;
1009 
1010  case 'F':
1011  args.desktop_file = optarg;
1012  break;
1013 
1014  case '?':
1015  usage(1);
1016  }
1017  }
1018 
1019  // Option processing stops as soon as application name is encountered
1020 
1021  args.prog_argc = argc - optind;
1022  args.prog_argv = &argv[optind];
1023 
1024  if (args.prog_argc < 1) {
1025  report(report_error, "No command line to invoke was given.\n");
1026  exit(EXIT_FAILURE);
1027  }
1028 
1029  // Force argv[0] of application to be the absolute path to allow the
1030  // application to find out its installation directory from there
1031  args.prog_argv[0] = search_program(args.prog_argv[0]);
1032 
1033  // Check if application exists
1034  struct stat file_stat;
1035  if (stat(args.prog_argv[0], &file_stat) == -1) {
1036  report(report_error, "%s: not found: %m\n", args.prog_argv[0]);
1038  }
1039 
1040  // Check that application is regular file (or symlink to such)
1041  if (!S_ISREG(file_stat.st_mode)) {
1042  report(report_error, "%s: not a file\n", args.prog_argv[0]);
1044  }
1045 
1046  // If it's a launcher, append its first argument to the name
1047  // (at this point, we have already checked if it exists and is a file)
1048  if (strcmp(args.prog_argv[0], "/usr/bin/sailfish-qml") == 0) {
1049  if (args.prog_argc < 2) {
1050  report(report_error, "%s: requires an argument\n", args.prog_argv[0]);
1052  }
1053 
1054  if (asprintf(&args.prog_name, "%s %s", args.prog_argv[0], args.prog_argv[1]) < 0)
1055  exit(EXIT_FAILURE);
1056  } else {
1057  if (!(args.prog_name = strdup(args.prog_argv[0])))
1058  exit(EXIT_FAILURE);
1059  }
1060 
1061  if (!args.app_type) {
1062  report(report_error, "Application type must be specified with --type.\n");
1063  usage(1);
1064  }
1065 
1066  if (!args.app_name) {
1067  report(report_error, "Application name must be specified with --application.\n");
1068  usage(1);
1069  }
1070 
1071  // If TEST_MODE_CONTROL_FILE doesn't exists switch off test mode
1072  if (args.test_mode && access(TEST_MODE_CONTROL_FILE, F_OK) != 0) {
1073  args.test_mode = false;
1074  info("Invoker test mode is not enabled.\n");
1075  }
1076 
1077  if (pipe(g_signal_pipe) == -1)
1078  {
1079  report(report_error, "Creating a pipe for Unix signals failed!\n");
1080  exit(EXIT_FAILURE);
1081  }
1082 
1083  // Send commands to the launcher daemon
1084  info("Invoking execution: '%s'\n", args.prog_name);
1085  int ret_val = invoke(&args);
1086 
1087  // Sleep for delay before exiting
1088  if (args.exit_delay) {
1089  // DBUS cannot cope some times if the invoker exits too early.
1090  info("Delaying exit for %d seconds..\n", args.exit_delay);
1091  sleep(args.exit_delay);
1092  }
1093 
1094  info("invoker exit(%d)\n", ret_val);
1095  return ret_val;
1096 }
void invoke_send_msg(int fd, uint32_t msg)
Definition: invokelib.c:42
bool invoke_recv_msg(int fd, uint32_t *msg)
Definition: invokelib.c:48
void invoke_send_str(int fd, const char *str)
Definition: invokelib.c:74
#define TEST_MODE_CONTROL_FILE
Definition: invokelib.h:34
static char * strip(char *str)
Definition: invoker.c:62
int main(int argc, char *argv[])
Definition: invoker.c:909
static void kill_application(pid_t pid)
Definition: invoker.c:286
static void invoker_send_exec(int fd, char *exec)
Definition: invoker.c:463
static void invoke_fallback(const InvokeArgs *args)
Definition: invoker.c:806
static void usage(int status)
Definition: invoker.c:569
static void invoker_send_magic(int fd, uint32_t options)
Definition: invoker.c:450
struct InvokeArgs InvokeArgs
static void invoker_send_prio(int fd, int prio)
Definition: invoker.c:482
static const unsigned int RESPAWN_DELAY
Definition: invoker.c:133
static void sigs_set(struct sigaction *sig)
Definition: invoker.c:173
static int invoke_remote(int socket_fd, const InvokeArgs *args)
Definition: invoker.c:767
static const unsigned int MIN_EXIT_DELAY
Definition: invoker.c:128
static void sigs_init(void)
Definition: invoker.c:180
#define INVOKE_ARGS_INIT
Definition: invoker.c:752
static int g_signal_pipe[2]
Pipe used to safely catch Unix signals.
Definition: invoker.c:149
static int invoker_init(const char *app_type, const char *app_name)
Definition: invoker.c:344
static char * slice(const char *pos, const char **ppos, const char *delim)
Definition: invoker.c:83
static void invoker_send_env(int fd)
Definition: invoker.c:504
static void invoker_send_name(int fd, const char *name)
Definition: invoker.c:457
static const unsigned int MAX_RESPAWN_DELAY
Definition: invoker.c:135
static pid_t g_invoked_pid
Definition: invoker.c:143
static void invoker_send_io(int fd)
Definition: invoker.c:523
static const unsigned int MAX_EXIT_DELAY
Definition: invoker.c:129
static const unsigned int EXIT_DELAY
Definition: invoker.c:127
char ** environ
static void invoker_send_delay(int fd, int delay)
Definition: invoker.c:489
static void sig_forwarder(int sig)
Definition: invoker.c:152
static void invoker_send_end(int fd)
Definition: invoker.c:561
static bool shutdown_socket(int socket_fd)
Definition: invoker.c:220
static int wait_for_launched_process_to_exit(int socket_fd)
Definition: invoker.c:654
static unsigned timestamp(void)
Definition: invoker.c:203
static unsigned int get_delay(char *delay_arg, char *param_name, unsigned int min_value, unsigned int max_value)
Definition: invoker.c:607
#define BOOSTER_SESSION
Definition: invoker.c:52
static bool invoker_recv_exit(int fd, int *status)
Definition: invoker.c:426
static uint32_t invoker_recv_pid(int fd)
Definition: invoker.c:408
static const unsigned int MIN_RESPAWN_DELAY
Definition: invoker.c:134
#define BOOSTER_GENERIC
Definition: invoker.c:53
static char ** split(const char *str, const char *delim)
Definition: invoker.c:99
static void sigs_restore(void)
Definition: invoker.c:192
static bool invoke_recv_ack(int fd)
Definition: invoker.c:329
static void invoker_send_args(int fd, int argc, char **argv)
Definition: invoker.c:469
static int invoke(InvokeArgs *args)
Definition: invoker.c:837
static void notify_app_lauch(const char *desktop_file)
Definition: invoker.c:630
static void invoker_send_ids(int fd, int uid, int gid)
Definition: invoker.c:496
static const unsigned char EXIT_STATUS_APPLICATION_NOT_FOUND
Definition: invoker.c:137
char * search_program(const char *progname)
Definition: search.c:43
char * prog_name
Definition: invoker.c:741
const char * app_name
Definition: invoker.c:743
bool wait_term
Definition: invoker.c:745
int prog_argc
Definition: invoker.c:739
uint32_t magic_options
Definition: invoker.c:744
unsigned int respawn_delay
Definition: invoker.c:746
bool test_mode
Definition: invoker.c:747
const char * desktop_file
Definition: invoker.c:748
unsigned int exit_delay
Definition: invoker.c:749
const char * app_type
Definition: invoker.c:742
char ** prog_argv
Definition: invoker.c:740