int main(int argc, char *argv[])
{
    GOptionContext *context;
    GError *err = NULL;
    gboolean own_socket = TRUE;
    GIOChannel *si_io_channel = NULL;
    guint si_watch_id = 0;

    context = g_option_context_new(NULL);
    g_option_context_add_main_entries(context, cmd_entries, NULL);
    g_option_context_set_summary(context,
        "Spice guest agent daemon, version " VERSION);
    g_option_context_parse(context, &argc, &argv, &err);
    g_option_context_free(context);

    if (err) {
        g_printerr("Invalid arguments, %s\n", err->message);
        g_error_free(err);
        return 1;
    }

    if (portdev == NULL) {
        portdev = g_strdup(DEFAULT_VIRTIO_PORT_PATH);
    }
    if (vdagentd_socket == NULL) {
        vdagentd_socket = g_strdup(VDAGENTD_SOCKET);
    }
    if (uinput_device == NULL) {
        uinput_device = g_strdup(DEFAULT_UINPUT_DEVICE);
    }

    openlog("spice-vdagentd", do_daemonize ? 0 : LOG_PERROR, LOG_USER);

    /* Setup communication with vdagent process(es) */
    server = udscs_server_new(agent_connect, agent_read_complete,
                              agent_disconnect, debug);
#ifdef WITH_SYSTEMD_SOCKET_ACTIVATION
    int n_fds;
    /* try to retrieve pre-configured sockets from systemd */
    n_fds = sd_listen_fds(0);
    if (n_fds > 1) {
        syslog(LOG_CRIT, "Received too many sockets from systemd (%i)", n_fds);
        return 1;
    } else if (n_fds == 1) {
        udscs_server_listen_to_socket(server, SD_LISTEN_FDS_START, &err);
        own_socket = FALSE;
    } else
    /* systemd socket activation not enabled, create our own */
#endif /* WITH_SYSTEMD_SOCKET_ACTIVATION */
    {
        mode_t mode = umask(0111);
        udscs_server_listen_to_address(server, vdagentd_socket, &err);
        umask(mode);
    }

    if (err) {
        syslog(LOG_CRIT, "Fatal could not create the server socket %s: %s",
                         vdagentd_socket, err->message);
        g_error_free(err);
        udscs_destroy_server(server);
        return 1;
    }

#ifdef WITH_STATIC_UINPUT
    uinput = vdagentd_uinput_create(uinput_device, 1024, 768, NULL, 0,
                                    debug > 1, uinput_fake);
    if (!uinput) {
        udscs_destroy_server(server);
        return 1;
    }
#endif

    if (do_daemonize)
        daemonize();

    g_unix_signal_add(SIGINT, signal_handler, NULL);
    g_unix_signal_add(SIGHUP, signal_handler, NULL);
    g_unix_signal_add(SIGTERM, signal_handler, NULL);

    if (want_session_info)
        session_info = session_info_create(debug);
    if (session_info) {
        si_io_channel = g_io_channel_unix_new(session_info_get_fd(session_info));
        si_watch_id = g_io_add_watch(si_io_channel, G_IO_IN, si_io_channel_cb, NULL);
        g_io_channel_unref(si_io_channel);
    } else {
        syslog(LOG_WARNING, "no session info, max 1 session agent allowed");
    }

    active_xfers = g_hash_table_new(g_direct_hash, g_direct_equal);

    udscs_server_start(server);
    loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    release_clipboards();

    vdagentd_uinput_destroy(&uinput);
    if (si_watch_id > 0) {
        g_source_remove(si_watch_id);
    }
    g_clear_pointer(&session_info, session_info_destroy);
    g_clear_pointer(&server, udscs_destroy_server);
    if (virtio_port) {
        vdagent_connection_flush(VDAGENT_CONNECTION(virtio_port));
        g_clear_pointer(&virtio_port, vdagent_connection_destroy);
    }

    /* allow the VDAgentConnection(s) to finalize properly */
    g_main_context_iteration(NULL, FALSE);

    g_main_loop_unref(loop);

    /* leave the socket around if it was provided by systemd */
    if (own_socket) {
        if (unlink(vdagentd_socket) != 0)
            syslog(LOG_ERR, "unlink %s: %s", vdagentd_socket, strerror(errno));
    }
    syslog(LOG_INFO, "vdagentd quitting, returning status %d", retval);

    if (do_daemonize)
        unlink(pidfilename);

    g_free(portdev);
    g_free(vdagentd_socket);
    g_free(uinput_device);

    return retval;
}