Пример #1
0
static void dump_services( int fd )
{
   unsigned u ;

   /*
    * Dump the current configuration (services + defaults)
    */
   Sprint( fd, "Services + defaults:\n" ) ;
   sc_dump( DEFAULTS( ps ), fd, 0, TRUE ) ;

   for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
      svc_dump( SP( pset_pointer( SERVICES( ps ), u ) ), fd ) ;
}
Пример #2
0
/*
 * Release the specified connection.
 * Certain actions may be performed before doing this:
 *      - drain of a single UDP packet if the socket type is SOCK_DGRAM
 */
void conn_free( connection_s *cp, int release_mem )
{
   struct service *sp ;

   if( cp == NULL )
      return;
      if( debug.on )
         msg( LOG_INFO, "conn_free", "freeing connection") ;

   sp = cp->co_sp ;

   if( (SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM) && (SVC_IS_ACTIVE( sp )) )
      drain( cp->co_descriptor ) ;

   if ( SVC_RELE( sp ) == 0 ) {
      pset_remove( SERVICES( ps ), sp ) ;
      svc_release( sp );
   }
   cp->co_sp = NULL;

   if ( CONN_DESCRIPTOR( cp ) > 0 )
      CONN_CLOSE( cp ) ;

   CLEAR( *cp ) ;
   if (release_mem) {
      FREE_CONN( cp ) ;
   }
}
Пример #3
0
static gboolean
handle_list_services (CockpitServices *object,
                      GDBusMethodInvocation *invocation)
{
  Services *services = SERVICES (object);

  if (services->systemd == NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
                                             "systemd not running");
      return TRUE;
    }

  ListServicesData *data = g_new0(ListServicesData, 1);
  data->services = services;
  data->invocation = invocation;

  g_dbus_proxy_call (services->systemd,
                     "ListUnits",
                     NULL,
                     G_DBUS_CALL_FLAGS_NONE,
                     G_MAXINT,
                     NULL,
                     on_list_units_done,
                     data);
  return TRUE;
}
Пример #4
0
static void
services_finalize (GObject *object)
{
  Services *services = SERVICES (object);

  g_hash_table_destroy (services->delayed_unit_news);

  if (G_OBJECT_CLASS (services_parent_class)->finalize != NULL)
    G_OBJECT_CLASS (services_parent_class)->finalize (object);
}
Пример #5
0
static gboolean
handle_get_service_info (CockpitServices *object,
                         GDBusMethodInvocation *invocation,
                         const gchar *arg_name)
{
  Services *services = SERVICES (object);

  if (services->systemd == NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
                                             "systemd not running");
      return TRUE;
    }

  GetServiceInfoData *data = g_new0(GetServiceInfoData, 1);
  data->services = services;
  data->invocation = invocation;

  gchar *t = strchr ((gchar *)arg_name, '@');
  gchar *s = strrchr ((gchar *)arg_name, '.');

  if (t > 0 && t + 1 == s)
    {
      // A template
      data->name = g_strdup (arg_name);
      g_dbus_proxy_call (services->systemd,
                         "GetUnitFileState",
                         g_variant_new ("(s)", arg_name),
                         G_DBUS_CALL_FLAGS_NONE,
                         G_MAXINT,
                         NULL,
                         on_get_unit_file_state_done,
                         data);
    }
  else
    g_dbus_proxy_call (services->systemd,
                       "LoadUnit",
                       g_variant_new ("(s)", arg_name),
                       G_DBUS_CALL_FLAGS_NONE,
                       G_MAXINT,
                       NULL,
                       on_load_unit_done,
                       data);
  return TRUE;
}
Пример #6
0
/*
 * This function closes all service descriptors. This should be called 
 * for all child processes that fork, but do not exec. This includes
 * redirect, builtins, and tcpmux. The close on exec flag takes care of
 * child processes that call exec. Without calling this, the listening 
 * fd's are not closed and reconfig will fail.
 */
void close_all_svc_descriptors(void)
{
   psi_h                     iter ;
   struct service            *osp ;

   /* Have to close all other descriptors here */
   iter = psi_create( SERVICES( ps ) ) ;
   if ( iter == NULL )
   {
        out_of_memory( "close_all_svc_descriptors" ) ;
        exit( 1 );
   }

   for ( osp = SP( psi_start( iter ) ) ; osp ; osp = SP( psi_next( iter ) ) )
        (void) Sclose( SVC_FD( osp ) ) ;
  
   psi_destroy( iter ) ;
}
Пример #7
0
static void
services_get_property (GObject *object,
                       guint prop_id,
                       GValue *value,
                       GParamSpec *pspec)
{
  Services *services = SERVICES (object);

  switch (prop_id)
    {
    case PROP_DAEMON:
      g_value_set_object (value, services_get_daemon (services));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}
Пример #8
0
static void
services_set_property (GObject *object,
                       guint prop_id,
                       const GValue *value,
                       GParamSpec *pspec)
{
  Services *services = SERVICES (object);

  switch (prop_id)
    {
    case PROP_DAEMON:
      g_assert (services->daemon == NULL);
      services->daemon = g_value_dup_object (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}
Пример #9
0
static gboolean
handle_service_action (CockpitServices *object,
                       GDBusMethodInvocation *invocation,
                       const gchar *arg_name,
                       const gchar *arg_action)
{
  GError *error;
  Services *services = SERVICES (object);
  const gchar *argv[6];
  int i;
  gint status;

  const gchar *method = arg_action;
  gboolean force = FALSE;

  if (g_str_has_prefix (arg_action, "force-"))
    {
      force = TRUE;
      method = arg_action + strlen ("force-");
    }

  i = 0;
  argv[i++] = "pkexec";
  argv[i++] = "systemctl";
  if (force)
    argv[i++] = "--force";
  argv[i++] = method;
  argv[i++] = arg_name;
  argv[i++] = NULL;

  error = NULL;
  if (g_spawn_sync (NULL, (gchar**)argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &status, &error))
    g_spawn_check_exit_status (status, &error);

  if (error)
    end_invocation_take_gerror (invocation, error);
  else
    cockpit_services_complete_service_action (COCKPIT_SERVICES (services), invocation);

  return TRUE;
}
Пример #10
0
static void consistency_check( enum check_type type )
{
   int         fd ;
   fd_set      socket_mask_copy ;
   unsigned    u ;
   int         errors ;
   unsigned    total_running_servers        = 0 ;
   unsigned    total_retry_servers          = 0 ;
   unsigned    error_count                  = 0 ;
   bool_int    service_count_check_failed   = FALSE ;
   const char  *func                        = "consistency_check" ;

   socket_mask_copy = ps.rws.socket_mask ;

   for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
   {
      register struct service *sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
      char *sid = SVC_ID( sp ) ;
      unsigned   running_servers ;
      unsigned   retry_servers ;

      error_count += refcount_check( sp, &running_servers, &retry_servers ) ;

      if ( SVC_IS_AVAILABLE( sp ) || SVC_IS_DISABLED ( sp ) )
      {
         /*
          * In this case, there may be some servers running
          */
         if ( FD_ISSET( SVC_FD( sp ), &socket_mask_copy ) )
         {
            if ( SVC_IS_DISABLED( sp ) )
            {
               msg( LOG_ERR, func,
                  "fd of disabled service %s still in socket mask", sid ) ;
               error_count++ ;
            }
            FD_CLR( SVC_FD( sp ), &socket_mask_copy ) ;
         }
         error_count += thread_check( sp, running_servers, retry_servers ) ;

         errors = service_count_check( sp, running_servers, retry_servers ) ;
         if ( ! errors && ! service_count_check_failed )
         {
            total_retry_servers += retry_servers ;
            total_running_servers += running_servers ;
         }
         if ( errors )
         {
            service_count_check_failed = TRUE ;
            error_count += errors ;
         }

         if ( SVC_IS_DISABLED( sp ) && SVC_RUNNING_SERVERS( sp ) == 0 )
         {
            msg( LOG_ERR, func,
               "disabled service %s has 0 running servers\n", sid ) ;
            error_count++ ;
            continue ;
         }
      }
      else
      {
         msg( LOG_ERR, func, "service %s not started", SVC_ID( sp ) ) ;
         error_count++ ;
      }
   }

   if ( ! service_count_check_failed )
   {
      if ( total_running_servers != pset_count( SERVERS( ps ) ) )
      {
         msg( LOG_ERR, func,
            "total running servers (%d) != number of running servers (%d)",
               total_running_servers, pset_count( SERVERS( ps ) ) ) ;
         error_count++ ;
      }
      if ( total_retry_servers != pset_count( RETRIES( ps ) ) )
      {
         msg( LOG_ERR, func,
            "total retry servers (%d) != number of retry servers (%d)",
               total_retry_servers, pset_count( RETRIES( ps ) ) ) ;
         error_count++ ;
      }
   }

   /*
    * Check if there are any descriptors set in socket_mask_copy
    */
   for ( fd = 0 ; fd < ps.ros.max_descriptors ; fd++ )
      if ( FD_ISSET( fd, &socket_mask_copy ) && ((fd != signals_pending[0]) && fd != signals_pending[1]))
      {
         msg( LOG_ERR, func,
            "descriptor %d set in socket mask but there is no service for it",
               fd ) ;
         error_count++ ;
      }

   if ( error_count != 0 )
      msg( LOG_WARNING, func,
            "Consistency check detected %d errors", error_count ) ;
   else
      if ( type == USER_REQUESTED || debug.on )
         msg( LOG_INFO, func, "Consistency check passed" ) ;

   if( type == PERIODIC ) 
      if ( xtimer_add( periodic_check, ps.ros.cc_interval ) == -1 )
         msg( LOG_ERR, func, "Failed to start consistency timer" ) ;
}
Пример #11
0
static gboolean
handle_service_action (CockpitServices *object,
                       GDBusMethodInvocation *invocation,
                       const gchar *arg_name,
                       const gchar *arg_action)
{
  Services *services = SERVICES (object);

  if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
    return TRUE;

  if (services->systemd == NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
                                             "systemd not running");
      return TRUE;
    }

  const gchar *method = NULL;
  int flags = 0;

  for (int i = 0; action_methods[i].action; i++)
    {
      if (strcmp (action_methods[i].action, arg_action) == 0)
        {
          method = action_methods[i].method;
          flags = action_methods[i].flags;
          break;
        }
    }

  if (method == NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
                                             "Unsupported action: %s",
                                             arg_action);
      return TRUE;
    }

  const gchar *mode = (flags & ISOLATE) ? "isolate" : "replace";

  ServiceActionData *data = g_new0(ServiceActionData, 1);
  data->services = services;
  data->invocation = invocation;
  data->flags = flags;

  GVariant *args;
  if (flags & FOR_FILES)
    {
      const gchar *files[] = { arg_name, NULL };
      if ((flags & FORCE) || (flags & NO_FORCE))
        args = g_variant_new ("(^asbb)", files, FALSE, flags & FORCE);
      else
        args = g_variant_new ("(^asb)", files, FALSE);
    }
  else
    args = g_variant_new ("(ss)", arg_name, mode);

  g_dbus_proxy_call (services->systemd,
                     method,
                     args,
                     G_DBUS_CALL_FLAGS_NONE,
                     G_MAXINT,
                     NULL,
                     on_service_action_done,
                     data);
  return TRUE;
}
Пример #12
0
static void
services_constructed (GObject *_object)
{
  Services *services = SERVICES (_object);
  GDBusConnection *connection;

  services->systemd = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
                                                     0,
                                                     NULL,
                                                     "org.freedesktop.systemd1",
                                                     "/org/freedesktop/systemd1",
                                                     "org.freedesktop.systemd1.Manager",
                                                     NULL,
                                                     NULL);

  connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
  if (connection)
    {
      g_dbus_connection_signal_subscribe (connection,
                                          "org.freedesktop.systemd1",
                                          "org.freedesktop.systemd1.Manager",
                                          "UnitFilesChanged",
                                          "/org/freedesktop/systemd1",
                                          NULL, G_DBUS_SIGNAL_FLAGS_NONE,
                                          on_unit_files_changed_signal, services, NULL);
      g_dbus_connection_signal_subscribe (connection,
                                          "org.freedesktop.systemd1",
                                          "org.freedesktop.DBus.Properties",
                                          "PropertiesChanged",
                                          NULL,
                                          NULL, G_DBUS_SIGNAL_FLAGS_NONE,
                                          on_systemd_properties_changed, services, NULL);
      g_dbus_connection_signal_subscribe (connection,
                                          "org.freedesktop.systemd1",
                                          "org.freedesktop.systemd1.Manager",
                                          "UnitNew",
                                          "/org/freedesktop/systemd1",
                                          NULL, G_DBUS_SIGNAL_FLAGS_NONE,
                                          on_unit_new_signal, services, NULL);
      g_dbus_connection_signal_subscribe (connection,
                                          "org.freedesktop.systemd1",
                                          "org.freedesktop.systemd1.Manager",
                                          "UnitRemoved",
                                          "/org/freedesktop/systemd1",
                                          NULL, G_DBUS_SIGNAL_FLAGS_NONE,
                                          on_unit_removed_signal, services, NULL);
    }

  if (services->systemd)
    g_dbus_proxy_call (services->systemd,
                       "Subscribe",
                       NULL,
                       G_DBUS_CALL_FLAGS_NONE,
                       G_MAXINT,
                       NULL,
                       on_subscribe_done,
                       NULL);

  services->delayed_unit_news = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_delayed_unit_new);

  if (G_OBJECT_CLASS (services_parent_class)->constructed != NULL)
    G_OBJECT_CLASS (services_parent_class)->constructed (_object);
}
Пример #13
0
static void tcpmux_handler( const struct server *serp )
{
   char      svc_name[ BUFFER_SIZE ] ;
   int       cc ;
   int       descriptor = SERVER_FD( serp ) ;
   const     struct service *svc = SERVER_SERVICE( serp ) ;
   unsigned  u;
   struct    service *sp = NULL;
   struct    server server, *nserp;
   struct    service_config *scp = NULL;

   close_all_svc_descriptors();

   /*  Read in the name of the service in the format "svc_name\r\n".
    *
    *  XXX: should loop on partial reads (could probably use Sread() if
    *  it wasn't thrown out of xinetd source code a few revisions back).
    */
   do
   {
      cc = read( descriptor, svc_name, sizeof( svc_name ) ) ;
   } while (cc == -1 && errno == EINTR);

   if ( cc <= 0 )
   {
      msg(LOG_ERR, "tcpmux_handler", "read failed");
      exit(0);
   }

   if ( ( cc <= 2 ) ||
        ( ( svc_name[cc - 1] != '\n' ) || ( svc_name[cc - 2] != '\r' ) ) )
   {
      if ( debug.on )
         msg(LOG_DEBUG, "tcpmux_handler", "Invalid service name format.");
      
      exit(0);
   }

   svc_name[cc - 2] = '\0';  /*  Remove \r\n for compare */

   if ( debug.on )
   {
      msg(LOG_DEBUG, "tcpmux_handler", "Input (%d bytes) %s as service name.",
          cc, svc_name);
   }

   /*  Search the services for the a match on name.
    */

   for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
   {
      sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;

      if ( strcasecmp( svc_name, SC_NAME( SVC_CONF( sp ) ) ) == 0 )
      {
         /*  Found the pointer. Validate its type.
          */
         scp = SVC_CONF( sp );
/*
         if ( ! SVC_IS_MUXCLIENT( sp ) )
         {
            if ( debug.on )
            {
               msg(LOG_DEBUG, "tcpmux_handler", "Non-tcpmux service name: %s.",
                   svc_name);
            }
            exit(0);
         }
*/

         /*  Send the accept string if we're a PLUS (+) client.
          */

         if ( SVC_IS_MUXPLUSCLIENT( sp ) )
         {
            if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) !=
                 sizeof( TCPMUX_ACK ) )
            {
                msg(LOG_ERR, "tcpmux_handler", "Ack write failed for %s.",
		    svc_name);
                exit(0);
            }
         }
         break;  /*  Time to get on with the service */
      }
      continue;  /*  Keep looking */
   }

   if ( u >= pset_count( SERVICES( ps ) ) )
   {
      if ( debug.on )
      {
         msg(LOG_DEBUG, "tcpmux_handler", "Service name %s not found.",
             svc_name);
      }
      exit(0);
   }

   if( SVC_WAITS( svc ) ) /* Service forks, so close it */
      Sclose(descriptor);

   server.svr_sp = sp;
   server.svr_conn = SERVER_CONNECTION(serp);
   nserp = server_alloc(&server);
   if( SC_IS_INTERNAL( scp ) ) {
      SC_INTERNAL(scp, nserp);
   } else {
      exec_server(nserp);
   }
}