mock-service.c 3.09 KB
Newer Older
1
/* libsecret - GLib wrapper for Secret Service
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Copyright 2011 Red Hat Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2 of the licence or (at
 * your option) any later version.
 *
 * See the included COPYING file for more information.
 *
 * Author: Stef Walter <stefw@gnome.org>
 */


#include "config.h"

#include "mock-service.h"

20
#include "secret-private.h"
21 22 23

#include <errno.h>
#include <stdio.h>
24
#include <string.h>
25

26 27 28 29 30
#ifdef __linux
#include <sys/prctl.h>
#endif

static gchar *service_name = NULL;
31 32
static GPid pid = 0;

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
static void
on_python_child_setup (gpointer user_data)
{
#ifdef __linux
  prctl (PR_SET_PDEATHSIG, 15);
#endif
}

static gchar *
read_until_end (int fd,
                GError **error)
{
	GString *data;
	gsize len;
	gssize ret;
	gchar *pos;

	data = g_string_new ("");

	for (;;) {
		len = data->len;
		g_string_set_size (data, len + 256);
		ret = read (fd, data->str + len, 256);
		if (ret < 0) {
			if (errno != EAGAIN) {
				g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
				             "Couldn't read from mock service: %s", g_strerror (errno));
				g_string_free (data, TRUE);
				return NULL;
			}
		} else if (ret == 0) {
			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Remote closed the output");
			g_string_free (data, TRUE);
			return NULL;
		} else {
			data->len = len + ret;
			data->str[data->len] = '\0';
		}

		pos = strchr (data->str, '\n');
		if (pos) {
			g_string_set_size (data, pos - data->str);
			break;
		}
	}

	return g_string_free (data, FALSE);
}

static const gchar *
83 84
service_start (const gchar *mock_script,
               GError **error)
85 86 87
{
	GSpawnFlags flags;
	gboolean ret;
88
	gint output;
89 90

	gchar *argv[] = {
Dmitry Shachnev's avatar
Dmitry Shachnev committed
91
		"python3", (gchar *)mock_script,
92 93 94 95 96 97
		NULL
	};

	g_return_val_if_fail (mock_script != NULL, FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

98 99
	g_free (service_name);
	service_name = NULL;
100

101 102 103
	flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD;
	ret = g_spawn_async_with_pipes (SRCDIR, argv, NULL, flags, on_python_child_setup, NULL, &pid,
	                                NULL, &output, NULL, error);
104 105

	if (ret) {
106 107 108 109 110 111 112
		service_name = read_until_end (output, error);
		if (service_name) {
			g_strstrip (service_name);
			g_assert_cmpstr (service_name, !=, "");
			g_setenv ("SECRET_SERVICE_BUS_NAME", service_name, TRUE);
		}
		close (output);
113 114
	}

115
	return service_name;
116 117
}

118
const gchar *
119 120 121 122
mock_service_start (const gchar *mock_script,
                    GError **error)
{
	gchar *path;
123
	const gchar *name;
124 125

	path = g_build_filename (SRCDIR, "libsecret", mock_script, NULL);
126
	name = service_start (path, error);
127 128
	g_free (path);

129
	return name;
130 131
}

132 133 134
void
mock_service_stop (void)
{
135
	while (g_main_context_iteration (NULL, FALSE));
136

137 138 139 140 141
	if (pid) {
		if (kill (pid, SIGTERM) < 0) {
			if (errno != ESRCH)
				g_warning ("kill() failed: %s", g_strerror (errno));
		}
142

143 144
		g_spawn_close_pid (pid);
		pid = 0;
145 146
	}

147
	while (g_main_context_iteration (NULL, FALSE));
148
	g_unsetenv ("SECRET_SERVICE_BUS_NAME");
149
}