Ejemplo n.º 1
0
/*
 * Saves the session address in session file. Returns TRUE on
 * success, FALSE if an error occurs.
 */
static int
set_address_in_file (char *address, pid_t pid, Window wid)
{
  char *session_file;
  FILE *f;

  ensure_session_directory ();
  session_file = get_session_file();
  if (session_file == NULL)
    return FALSE;

  f = fopen (session_file, "w");
  if (f == NULL)
    return FALSE;               /* some kind of error */
  fprintf (f,
           "# This file allows processes on the machine with id %s using \n"
           "# display %s to find the D-Bus session bus with the below address.\n"
           "# If the DBUS_SESSION_BUS_ADDRESS environment variable is set, it will\n"
           "# be used rather than this file.\n"
           "# See \"man dbus-launch\" for more details.\n"
           "DBUS_SESSION_BUS_ADDRESS=%s\n"
           "DBUS_SESSION_BUS_PID=%ld\n"
           "DBUS_SESSION_BUS_WINDOWID=%ld\n",
           get_machine_uuid (),
           getenv ("DISPLAY"),
           address, (long)pid, (long)wid);

  fclose (f);
  free (session_file);

  return TRUE;
}
Ejemplo n.º 2
0
static int
init_x_atoms (Display *display)
{
  static const char selection_prefix[] = "_DBUS_SESSION_BUS_SELECTION_";
  static const char address_prefix[] = "_DBUS_SESSION_BUS_ADDRESS";
  static const char pid_prefix[] = "_DBUS_SESSION_BUS_PID";
  static int init = FALSE;
  char *atom_name;
  const char *machine;
  char *user_name;
  struct passwd *user;

  if (init)
    return TRUE;

  machine = get_machine_uuid ();
  if (machine == NULL)
    return FALSE;

  user = getpwuid (getuid ());
  if (user == NULL)
    {
      verbose ("Could not determine the user informations; aborting X11 integration.\n");
      return FALSE;
    }
  user_name = xstrdup(user->pw_name);

  atom_name = malloc (strlen (machine) + strlen (user_name) + 2 +
                      MAX (strlen (selection_prefix),
                           MAX (strlen (address_prefix),
                                strlen (pid_prefix))));
  if (atom_name == NULL)
    {
      verbose ("Could not create X11 atoms; aborting X11 integration.\n");
      free (user_name);
      return FALSE;
    }

  /* create the selection atom */
  strcpy (atom_name, selection_prefix);
  strcat (atom_name, user_name);
  strcat (atom_name, "_");
  strcat (atom_name, machine);
  selection_atom = XInternAtom (display, atom_name, FALSE);

  /* create the address property atom */
  strcpy (atom_name, address_prefix);
  address_atom = XInternAtom (display, atom_name, FALSE);

  /* create the PID property atom */
  strcpy (atom_name, pid_prefix);
  pid_atom = XInternAtom (display, atom_name, FALSE);

  free (atom_name);
  free (user_name);
  init = TRUE;
  return TRUE;
}
Ejemplo n.º 3
0
int
main (int argc, char **argv)
{
  const char *prev_arg;
  const char *shname;
  const char *runprog = NULL;
  int remaining_args = 0;
  int exit_with_session;
  int binary_syntax = FALSE;
  int c_shell_syntax = FALSE;
  int bourne_shell_syntax = FALSE;
  int auto_shell_syntax = FALSE;
  int autolaunch = FALSE;
  int requires_arg = FALSE;
  int close_stderr = FALSE;
  int i;  
  int ret;
  int bus_pid_to_launcher_pipe[2];
  int bus_pid_to_babysitter_pipe[2];
  int bus_address_to_launcher_pipe[2];
  char *config_file;
  
  exit_with_session = FALSE;
  config_file = NULL;
  
  prev_arg = NULL;
  i = 1;
  while (i < argc)
    {
      const char *arg = argv[i];
 
      if (strcmp (arg, "--help") == 0 ||
          strcmp (arg, "-h") == 0 ||
          strcmp (arg, "-?") == 0)
        usage (0);
      else if (strcmp (arg, "--auto-syntax") == 0)
        auto_shell_syntax = TRUE;
      else if (strcmp (arg, "-c") == 0 ||
               strcmp (arg, "--csh-syntax") == 0)
        c_shell_syntax = TRUE;
      else if (strcmp (arg, "-s") == 0 ||
               strcmp (arg, "--sh-syntax") == 0)
        bourne_shell_syntax = TRUE;
      else if (strcmp (arg, "--binary-syntax") == 0)
        binary_syntax = TRUE;
      else if (strcmp (arg, "--version") == 0)
        version ();
      else if (strcmp (arg, "--exit-with-session") == 0)
        exit_with_session = TRUE;
      else if (strcmp (arg, "--close-stderr") == 0)
        close_stderr = TRUE;
      else if (strstr (arg, "--autolaunch=") == arg)
        {
          const char *s;

          if (autolaunch)
            {
              fprintf (stderr, "--autolaunch given twice\n");
              exit (1);
            }
          
          autolaunch = TRUE;

          s = strchr (arg, '=');
          ++s;

          save_machine_uuid (s);
        }
      else if (prev_arg &&
               strcmp (prev_arg, "--autolaunch") == 0)
        {
          if (autolaunch)
            {
              fprintf (stderr, "--autolaunch given twice\n");
              exit (1);
            }
          
          autolaunch = TRUE;

          save_machine_uuid (arg);
	  requires_arg = FALSE;
        }
      else if (strcmp (arg, "--autolaunch") == 0)
	requires_arg = TRUE;
      else if (strstr (arg, "--config-file=") == arg)
        {
          const char *file;

          if (config_file != NULL)
            {
              fprintf (stderr, "--config-file given twice\n");
              exit (1);
            }
          
          file = strchr (arg, '=');
          ++file;

          config_file = xstrdup (file);
        }
      else if (prev_arg &&
               strcmp (prev_arg, "--config-file") == 0)
        {
          if (config_file != NULL)
            {
              fprintf (stderr, "--config-file given twice\n");
              exit (1);
            }

          config_file = xstrdup (arg);
	  requires_arg = FALSE;
        }
      else if (strcmp (arg, "--config-file") == 0)
	requires_arg = TRUE;
      else if (arg[0] == '-')
        {
          if (strcmp (arg, "--") != 0)
            {
              fprintf (stderr, "Option `%s' is unknown.\n", arg);
              exit (1);
            }
          else
            {
              runprog = argv[i+1];
              remaining_args = i+2;
              break;
            }
        }
      else
	{
	  runprog = arg;
	  remaining_args = i+1;
	  break;
	}
      
      prev_arg = arg;
      
      ++i;
    }
  if (requires_arg)
    {
      fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg);
      exit (1);
    }

  if (auto_shell_syntax)
    {
      if ((shname = getenv ("SHELL")) != NULL)
       {
         if (!strncmp (shname + strlen (shname) - 3, "csh", 3))
           c_shell_syntax = TRUE;
         else
           bourne_shell_syntax = TRUE;
       }
      else
       bourne_shell_syntax = TRUE;
    }  

  if (exit_with_session)
    verbose ("--exit-with-session enabled\n");

  if (autolaunch)
    {      
#ifndef DBUS_BUILD_X11
      fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
	       "Cannot continue.\n");
      exit (1);
#else
      char *address;
      pid_t pid;
      long wid;
      
      if (get_machine_uuid () == NULL)
        {
          fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n");
          exit (1);
        }

      /* FIXME right now autolaunch always does print_variables(), but it should really
       * exec the child program instead if a child program was specified. For now
       * we just exit if this conflict arises.
       */
      if (runprog)
        {
          fprintf (stderr, "Currently --autolaunch does not support running a program\n");
          exit (1);
        }
      
      verbose ("Autolaunch enabled (using X11).\n");
      if (!exit_with_session)
	{
	  verbose ("--exit-with-session automatically enabled\n");
	  exit_with_session = TRUE;
	}

      if (!x11_init ())
	{
	  fprintf (stderr, "Autolaunch error: X11 initialization failed.\n");
	  exit (1);
	}

      if (!x11_get_address (&address, &pid, &wid))
	{
	  fprintf (stderr, "Autolaunch error: X11 communication error.\n");
	  exit (1);
	}

      if (address != NULL)
	{          
	  verbose ("dbus-daemon is already running. Returning existing parameters.\n");
	  print_variables (address, pid, wid, c_shell_syntax,
			   bourne_shell_syntax, binary_syntax);
	  exit (0);
	}
#endif
    }

  if (pipe (bus_pid_to_launcher_pipe) < 0 ||
      pipe (bus_address_to_launcher_pipe) < 0 ||
      pipe (bus_pid_to_babysitter_pipe) < 0)
    {
      fprintf (stderr,
               "Failed to create pipe: %s\n",
               strerror (errno));
      exit (1);
    }

  ret = fork ();
  if (ret < 0)
    {
      fprintf (stderr, "Failed to fork: %s\n",
               strerror (errno));
      exit (1);
    }

  if (ret == 0)
    {
      /* Child */
#define MAX_FD_LEN 64
      char write_pid_fd_as_string[MAX_FD_LEN];
      char write_address_fd_as_string[MAX_FD_LEN];

      if (close_stderr)
	do_close_stderr ();

      verbose ("=== Babysitter's intermediate parent created\n");

      /* Fork once more to create babysitter */
      
      ret = fork ();
      if (ret < 0)
        {
          fprintf (stderr, "Failed to fork: %s\n",
                   strerror (errno));
          exit (1);
        }
      
      if (ret > 0)
        {
          /* In babysitter */
          verbose ("=== Babysitter's intermediate parent continues\n");
          
          close (bus_pid_to_launcher_pipe[READ_END]);
	  close (bus_pid_to_launcher_pipe[WRITE_END]);
          close (bus_address_to_launcher_pipe[READ_END]);
          close (bus_address_to_launcher_pipe[WRITE_END]);
          close (bus_pid_to_babysitter_pipe[WRITE_END]);
          
          /* babysit() will fork *again*
           * and will also reap the pre-forked bus
           * daemon
           */
          babysit (exit_with_session, ret,
                   bus_pid_to_babysitter_pipe[READ_END]);
          exit (0);
        }

      verbose ("=== Bus exec process created\n");
      
      /* Now we are the bus process (well, almost;
       * dbus-daemon itself forks again)
       */
      close (bus_pid_to_launcher_pipe[READ_END]);
      close (bus_address_to_launcher_pipe[READ_END]);
      close (bus_pid_to_babysitter_pipe[READ_END]);
      close (bus_pid_to_babysitter_pipe[WRITE_END]);

      sprintf (write_pid_fd_as_string,
               "%d", bus_pid_to_launcher_pipe[WRITE_END]);

      sprintf (write_address_fd_as_string,
               "%d", bus_address_to_launcher_pipe[WRITE_END]);

      verbose ("Calling exec()\n");
 
#ifdef DBUS_BUILD_TESTS 
      /* exec from testdir */
      if (getenv("DBUS_USE_TEST_BINARY") != NULL)
        {
          execl (TEST_BUS_BINARY,
                 TEST_BUS_BINARY,
                 "--fork",
                 "--print-pid", write_pid_fd_as_string,
                 "--print-address", write_address_fd_as_string,
                 config_file ? "--config-file" : "--session",
                 config_file, /* has to be last in this varargs list */
                 NULL); 

          fprintf (stderr,
                   "Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n",
                   TEST_BUS_BINARY, strerror (errno));
        }
 #endif /* DBUS_BUILD_TESTS */

      execl (DBUS_DAEMONDIR"/dbus-daemon",
             DBUS_DAEMONDIR"/dbus-daemon",
             "--fork",
             "--print-pid", write_pid_fd_as_string,
             "--print-address", write_address_fd_as_string,
             config_file ? "--config-file" : "--session",
             config_file, /* has to be last in this varargs list */
             NULL);

      fprintf (stderr,
               "Failed to execute message bus daemon %s: %s.  Will try again without full path.\n",
               DBUS_DAEMONDIR"/dbus-daemon", strerror (errno));
      
      /*
       * If it failed, try running without full PATH.  Note this is needed
       * because the build process builds the run-with-tmp-session-bus.conf
       * file and the dbus-daemon will not be in the install location during
       * build time.
       */
      execlp ("dbus-daemon",
              "dbus-daemon",
              "--fork",
              "--print-pid", write_pid_fd_as_string,
              "--print-address", write_address_fd_as_string,
              config_file ? "--config-file" : "--session",
              config_file, /* has to be last in this varargs list */
              NULL);

      fprintf (stderr,
               "Failed to execute message bus daemon: %s\n",
               strerror (errno));
      exit (1);
    }
  else
    {
      /* Parent */
#define MAX_PID_LEN 64
      pid_t bus_pid;  
      char bus_address[MAX_ADDR_LEN];
      char buf[MAX_PID_LEN];
      char *end;
      long wid = 0;
      long val;
      int ret2;

      verbose ("=== Parent dbus-launch continues\n");
      
      close (bus_pid_to_launcher_pipe[WRITE_END]);
      close (bus_address_to_launcher_pipe[WRITE_END]);
      close (bus_pid_to_babysitter_pipe[READ_END]);

      verbose ("Waiting for babysitter's intermediate parent\n");
      
      /* Immediately reap parent of babysitter
       * (which was created just for us to reap)
       */
      if (do_waitpid (ret) < 0)
        {
          fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n",
                   strerror (errno));
          exit (1);
        }

      verbose ("Reading address from bus\n");
      
      /* Read the pipe data, print, and exit */
      switch (read_line (bus_address_to_launcher_pipe[READ_END],
                         bus_address, MAX_ADDR_LEN))
        {
        case READ_STATUS_OK:
          break;
        case READ_STATUS_EOF:
          fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
          exit (1);
          break;
        case READ_STATUS_ERROR:
          fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
                   strerror (errno));
          exit (1);
          break;
        }
        
      close (bus_address_to_launcher_pipe[READ_END]);

      verbose ("Reading PID from daemon\n");
      /* Now read data */
      switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN))
	{
	case READ_STATUS_OK:
	  break;
	case READ_STATUS_EOF:
	  fprintf (stderr, "EOF reading PID from bus daemon\n");
	  exit (1);
	  break;
	case READ_STATUS_ERROR:
	  fprintf (stderr, "Error reading PID from bus daemon: %s\n",
		   strerror (errno));
	  exit (1);
	  break;
	}

      end = NULL;
      val = strtol (buf, &end, 0);
      if (buf == end || end == NULL)
	{
	  fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
		   buf, strerror (errno));
	  exit (1);
	}

      bus_pid = val;

      close (bus_pid_to_launcher_pipe[READ_END]);

#ifdef DBUS_BUILD_X11
      /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus,
       * instead of just doing print_variables() if there's an existing bus.
       */
      if (xdisplay != NULL && runprog == NULL)
        {
          ret2 = x11_save_address (bus_address, bus_pid, &wid);
          if (ret2 == 0)
            {
              /* another window got added. Return its address */
              char *address;
              pid_t pid;
              long wid;
              
              if (x11_get_address (&address, &pid, &wid) && address != NULL)
                {
                  verbose ("dbus-daemon is already running. Returning existing parameters.\n");
                  print_variables (address, pid, wid, c_shell_syntax,
                                   bourne_shell_syntax, binary_syntax);
                  free (address);
                  
                  bus_pid_to_kill = bus_pid;
                  kill_bus_and_exit (0);
                }
              
              /* if failed, fall through */
            }
          if (ret2 <= 0)
            {
              fprintf (stderr, "Error saving bus information.\n");
              bus_pid_to_kill = bus_pid;
              kill_bus_and_exit (1);
            }
        }
#endif

      /* Forward the pid to the babysitter */
      write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid);
      close (bus_pid_to_babysitter_pipe[WRITE_END]);

      if (runprog)
	{
	  char *envvar;
	  char **args;

	  envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1);
	  args = malloc (sizeof (char *) * ((argc-remaining_args)+2));

	  if (envvar == NULL || args == NULL)
	    goto oom;

	  args[0] = xstrdup (runprog);
	  if (!args[0])
	    goto oom;
	  for (i = 1; i <= (argc-remaining_args); i++)
	    {
	      size_t len = strlen (argv[remaining_args+i-1])+1;
	      args[i] = malloc (len);
	      if (!args[i])
		goto oom;
	      strncpy (args[i], argv[remaining_args+i-1], len);
	    }
	  args[i] = NULL;

	  strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
	  strcat (envvar, bus_address);
	  putenv (envvar);

	  execvp (runprog, args);
	  fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
	  exit (1);
	}
      else
	{
	  print_variables (bus_address, bus_pid, wid, c_shell_syntax,
			   bourne_shell_syntax, binary_syntax);
	}
	  
      verbose ("dbus-launch exiting\n");

      fflush (stdout);
      fflush (stderr);
      close (1);
      close (2);
      
      exit (0);
    } 
  
  return 0;
 oom:
  fprintf (stderr, "Out of memory!");
  exit (1);
}
Ejemplo n.º 4
0
static char *
get_session_file (void)
{
  static const char prefix[] = "/" DBUS_DIR "/" DBUS_SESSION_BUS_DIR "/";
  const char *machine;
  const char *home;
  char *display;
  char *result;
  char *p;

  machine = get_machine_uuid ();
  if (machine == NULL)
    return NULL;

  display = xstrdup (getenv ("DISPLAY"));
  if (display == NULL)
    {
      verbose ("X11 integration disabled because X11 is not running\n");
      return NULL;
    }

  /* remove the screen part of the display name */
  p = strrchr (display, ':');
  if (p != NULL)
    {
      for ( ; *p; ++p)
        {
          if (*p == '.')
            {
              *p = '\0';
              break;
            }
        }
    }

  /* Note that we leave the hostname in the display most of the
   * time. The idea is that we want to be per-(machine,display,user)
   * triplet to be extra-sure we get a bus we can connect to. Ideally
   * we'd recognize when the hostname matches the machine we're on in
   * all cases; we do try to drop localhost and localhost.localdomain
   * as a special common case so that alternate spellings of DISPLAY
   * don't result in extra bus instances.
   *
   * We also kill the ":" if there's nothing in front of it. This
   * avoids an ugly double underscore in the filename.
   */
  remove_prefix (display, "localhost.localdomain:");
  remove_prefix (display, "localhost:");
  remove_prefix (display, ":");

  /* replace the : in the display with _ if the : is still there.
   * use _ instead of - since it can't be in hostnames.
   */
  for (p = display; *p; ++p)
    {
      if (*p == ':')
        *p = '_';
    }
  
  home = get_homedir ();
  
  result = malloc (strlen (home) + strlen (prefix) + strlen (machine) +
                   strlen (display) + 2);
  if (result == NULL)
    {
      /* out of memory */
      free (display);
      return NULL;
    }

  strcpy (result, home);
  strcat (result, prefix);
  strcat (result, machine);
  strcat (result, "-");
  strcat (result, display);
  free (display);

  verbose ("session file: %s\n", result);
  return result;
}