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