Exemple #1
0
void
stop_server(void)
{
	DEBUG("Stopping the server...");

	if (sock_unix >= 0) {
		remove_fd_from_io_scheduler(&worker_unix, NULL);
		metautils_pclose(&sock_unix);
		unlink(unix_socket_path);
	}

	if (sock_inet >= 0) {
		remove_fd_from_io_scheduler(&worker_inet, NULL);
		metautils_pclose(&sock_inet);
	}

	DEBUG("The server is stopped.");
}
Exemple #2
0
void
stop_server(void)
{
	DEBUG("Stopping the server...");

	if (usock>=0) {
		remove_fd_from_io_scheduler(&worker_unix, NULL);
		metautils_pclose(&usock);
	}

	if (sock_inet>=0) {
		remove_fd_from_io_scheduler(&worker_inet, NULL);
		metautils_pclose(&sock_inet);
	}

	unlink(AGENT_SOCK_PATH);
	DEBUG("The server is stopped.");
}
static gboolean
_commit_attr_handle(struct attr_handle_s *attr_handle, GError ** error)
{
	GError *local_error = NULL;

	if (attr_handle == NULL) {
		SETERRCODE(error, EINVAL, "Invalid attr_handle argument");
		return FALSE;
	}

	/* try to write the chunk extended attributes */
	attr_handle->chunk_file_des = open(attr_handle->chunk_path, O_RDWR);
	if (attr_handle->chunk_file_des >= 0) {
		if (_write_attributes(attr_handle->attr_hash, attr_handle->chunk_file_des, _write_to_xattr,
			&local_error)) {
			metautils_pclose(&(attr_handle->chunk_file_des));
			return TRUE;
		}
		else {
			/*WARN("Failed to write attributes to chunk xattr : %s", local_error->message);*/
			metautils_pclose(&(attr_handle->chunk_file_des));
			g_clear_error(&local_error);
		}
	}

	/* Fallback to .attr file */
	attr_handle->attr_file_des = open(attr_handle->attr_path, O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (attr_handle->attr_file_des < 0) {
		SETERRCODE(error, errno, "File [%s] open failed : %s", attr_handle->attr_path, strerror(errno));
		return FALSE;
	}
	else {
		if (!_write_attributes(attr_handle->attr_hash, attr_handle->attr_file_des, _write_to_attr_file,
				&local_error)) {
			metautils_pclose(&(attr_handle->attr_file_des));
			SETERROR(error, "Failed to write attributes to chunk.attr : %s", local_error->message);
			g_clear_error(&local_error);
			return FALSE;
		}
		metautils_pclose(&(attr_handle->attr_file_des));
	}

	return TRUE;
}
Exemple #4
0
static void
_endpoint_close (struct endpoint_s *u)
{
	if (!u) return;
	if (u->fd >= 0) {
		if (_endpoint_is_UNIX (u))
			(void) unlink (u->url);
		metautils_pclose(&(u->fd));
	}
	u->port_real = 0;
}
/**
 * FIXME TODO XXX file load duplicated at cluster/lib/gridcluster.c : gba_read()
 */
static int
cpu_stat_task_worker(gpointer udata, GError ** error)
{
	char end_of_buffer = '\0';
	int fd = 0;
	ssize_t rl;
	char *procstat = NULL;
	GByteArray *buffer = NULL;
	char buff[DEFAULT_BUFFER_SIZE];
	proc_stat_t pstat;

	(void)udata;

	fd = open(PROC_STAT, O_RDONLY);
	if (fd < 0) {
		GSETERROR(error, "Failed to open file [%s] : %s", PROC_STAT, strerror(errno));
		task_done(TASK_ID);
		return 0;
	}

	buffer = g_byte_array_new();
	while ((rl = read(fd, buff, DEFAULT_BUFFER_SIZE)) > 0)
		buffer = g_byte_array_append(buffer, (guint8*)buff, rl);
	metautils_pclose(&fd);

	if (rl < 0) {
		GSETERROR(error, "Read file [%s] failed with error : %s", PROC_STAT, strerror(errno));
		g_byte_array_free(buffer, TRUE);
		task_done(TASK_ID);
		return 0;
	}

	/*ensure the statistics string is NULL-terminated */
	g_byte_array_append(buffer, (guint8*)&end_of_buffer, sizeof(end_of_buffer));
	procstat = (char*)g_byte_array_free(buffer, FALSE);

	memset(&pstat, 0, sizeof(proc_stat_t));

	if (sscanf(procstat, "cpu  %llu %llu %llu %llu %llu %llu %llu",
		&(pstat.user), &(pstat.nice), &(pstat.system), &(pstat.idle),
		&(pstat.io_wait), &(pstat.irq), &(pstat.soft_irq)) == 7) {

		memcpy(&(cpu_stat.previous), &(cpu_stat.current), sizeof(proc_stat_t));
		memcpy(&(cpu_stat.current), &pstat, sizeof(proc_stat_t));
		nb_loops++;
	}
	else {
		WARN("Failed to scan cpu in string [%s]", procstat);
	}

	g_free(procstat);
	task_done(TASK_ID);
	return (1);
}
Exemple #6
0
static int
check_socket_is_absent( struct working_parameter_s *pParam, GError **err )
{
	struct sockaddr_un sun;
	int attempts, fd, rc;
	struct stat lStat;

	for (attempts=3; attempts>0 ; attempts--) {
		if (-1==stat( pParam->path.ptr, &lStat )) {

			switch (errno) {
				case ENOTDIR:
				case EACCES:
				case ELOOP:
					GSETERROR(err,"cannot access the socket path : %s", strerror(errno));
					return -1;
				default:
					return 0;
			}

		} else {

			if (!S_ISSOCK(lStat.st_mode)) {
				GSETERROR(err,"path %s exists and is not a socket, remove it and restart the server", pParam->path.ptr);
				return -1;
			}

			if (-1==(fd = socket(PF_LOCAL, SOCK_STREAM, 0))) {
				GSETERROR(err,"socket error : %s", strerror(errno));
				return -1;
			}

			/*try to connect*/
			sun.sun_family = PF_LOCAL;
			strncpy(sun.sun_path, pParam->path.ptr, sizeof(sun.sun_path));
			rc = connect(fd,(struct sockaddr*)&sun,sizeof(sun));
			metautils_pclose(&fd);
			if (!rc) {
				GSETERROR(err,"Server socket already up at [%s]", pParam->path.ptr);
				return -1;
			} else if (-1==unlink(pParam->path.ptr)) {
				GSETERROR(err,"Cannot remove the socket at [%s] : %s", pParam->path.ptr, strerror(errno));
				return -1;
			} /*else the socket has been unlinked, we retry to connect*/
			NOTICE("Socket %s unlinked", pParam->path.ptr);

		}
	}

	GSETERROR(err, "Supposed socket [%s] could not be removed", pParam->path.ptr);
	return -1;
}
Exemple #7
0
static void
_destroy(struct gridd_client_pool_s *pool)
{
	if (!pool)
		return;
	EXTRA_ASSERT(pool->vtable == &VTABLE);

	pool->closed = ~0;

	if (pool->fd_in >= 0)
		metautils_pclose(&(pool->fd_in));
	if (pool->fd_out >= 0)
		metautils_pclose(&(pool->fd_out));
	if (pool->fdmon >= 0)
		metautils_pclose(&(pool->fdmon));

	if (pool->pending_clients) {
		struct event_client_s *ec;
		while (NULL != (ec = g_async_queue_try_pop(pool->pending_clients)))
			event_client_free(ec);
		g_async_queue_unref(pool->pending_clients);
		pool->pending_clients = NULL;
	}

	if (pool->active_clients) {
		for (int i=0; i<pool->active_clients_size ;i++) {
			struct event_client_s *ec = pool->active_clients[i];
			pool->active_clients[i] = NULL;
			if (ec)
				event_client_free(ec);
		}
		g_free(pool->active_clients);
		pool->active_clients = NULL;
	}

	g_free(pool);
}
Exemple #8
0
int
socket_nonblock(int domain, int type, int protocol)
{
	if (VTABLE.socket_nonblock)
		return VTABLE.socket_nonblock(domain, type, protocol);
#ifdef HAVE_SOCKET3
	return metautils_syscall_socket(domain, type|SOCK_NONBLOCK, protocol);
#else
	int fd = metautils_syscall_socket(domain, type, protocol);
	if (fd < 0)
		return fd;
	if (sock_set_non_blocking(fd, TRUE))
		return fd;
	metautils_pclose(&fd);
	return -1;
#endif
}
Exemple #9
0
static void
sighandler_config(int s)
{
	switch (s) {
	case SIGUSR1:
	case SIGUSR2:
	case SIGCHLD:
		break;
	case SIGPIPE:
		metautils_pclose(&fd_out);
		break;
	case SIGTERM:
	case SIGQUIT:
	case SIGINT:
		is_running = FALSE;
		break;
	}
	signal(s, sighandler_config);
}
Exemple #10
0
gs_error_t *
hc_get_content(gs_grid_storage_t *hc, struct hc_url_s *url, const char *local_path, int force, int cache, gchar *stgpol)
{
	gs_error_t *e = NULL;
	/* download a content */
	gs_download_info_t dl_info;
	int out = 0;

	memset(&dl_info, 0x00, sizeof(dl_info));

	if(_open_destination(local_path, force, &out)) {
		GRID_DEBUG("Destination file descriptor ready fd=%d path=%s\n", out, local_path ? local_path : "<stdout>");
		/*download the content */
		dl_info.offset = 0;
		dl_info.size = 0;
		dl_info.writer = _write_to_fd;
		dl_info.user_data = &out;
		e = hc_dl_content(hc, url, &dl_info, cache, stgpol);
		if (out >= 0) {
			metautils_pclose(&out);
		}
		if (e) {
			g_printerr("Cannot download %s from %s (into %s)\n",
					hc_url_get(url, HCURL_PATH),
					hc_url_get(url, HCURL_REFERENCE),
					local_path ? local_path : "<stdout>");
		} else {
			GRID_DEBUG("Download done from %s to %s\n",
					hc_url_get(url, HCURL_PATH),
					local_path ? local_path : "<stdout>");
		}
	} else {
		gchar tmp[256];
		bzero(tmp, sizeof(tmp));
		g_snprintf(tmp, sizeof(tmp), "Failed to open the destination file descriptor to path=%s\n", local_path ? local_path : "<stdout>");
		e = g_malloc0(sizeof(gs_error_t));
		e->code = 0;
		e->msg = g_strdup(tmp);
	}

	return e;
}
static void
_population_create(const gchar *basedir, struct citizen_s *population)
{
    for (; population->dirname ; ++population) {
        gchar *dn = g_strconcat(basedir, G_DIR_SEPARATOR_S,
                                population->dirname, NULL);
        if (0 != g_mkdir_with_parents(dn, 0700))
            g_error("Try error: mkdir(%s) : (%d) %s", dn, errno, strerror(errno));
        if (population->basename && population->basename[0]) {
            gchar *full = g_strconcat(dn, G_DIR_SEPARATOR_S,
                                      population->basename, NULL);
            int fd = open(full, O_CREAT|O_TRUNC|O_SYNC, 0600);
            if (fd < 0)
                g_error("Try error: open(%s) : (%d) %s", full, errno, strerror(errno));
            metautils_pclose(&fd);
            g_free(full);
        }
        g_free(dn);
    }
}
Exemple #12
0
static int
_uconnect_path(const gchar *path, GError **err)
{
    struct sockaddr_un local;
    memset(&local, 0x00, sizeof(local));
    local.sun_family = AF_UNIX;
    g_strlcpy(local.sun_path, path, sizeof(local.sun_path));

    int usock = socket_nonblock(PF_UNIX, SOCK_STREAM, 0);
    if (usock < 0) {
        GSETERROR(err, "socket(UNIX): (%d) %s", errno, strerror(errno));
        return -1;
    }

    if (0 > connect(usock, (struct sockaddr *) &local, sizeof(local))) {
        GSETERROR(err, "connect(%s): (%d) %s", path, errno, strerror(errno));
        metautils_pclose(&usock);
        return -1;
    }

    return usock;
}
static int
read_known_service_from_file(GArray *known_services, const char *file_name, GError **error) {
	int fd;
	guint8 buff[256];
	ssize_t r;
	GByteArray *data = NULL;
	int service_number = 0;
	struct grid_service_data *services = NULL;

	fd = open(file_name, O_RDONLY);
	if (fd < 0) {
		GSETERROR(error, "Failed to open file [%s] : %s", file_name, strerror(errno));
		return(0);
	}

	data = g_byte_array_new();

	while ((r = read(fd, buff, sizeof(buff))) > 0) {
		data = g_byte_array_append(data, buff, r);
	}

	metautils_pclose(&fd);

	if (r < 0) {
		GSETERROR(error, "Failed to read data from file [%s] : %s", file_name, strerror(errno));
		g_byte_array_free(data, TRUE);
		return(0);
	}

	service_number = ( data->len * sizeof(guint8) ) / sizeof(struct grid_service_data);
	services = (struct grid_service_data *)g_byte_array_free(data, FALSE);

	known_services = g_array_append_vals(known_services, services, service_number);

	g_free(services);

	return(1);
}
Exemple #14
0
static void
_client_clean(struct network_server_s *srv, struct network_client_s *clt)
{
	(void) srv;

	/* Notifies the upper layer the client is being exiting. */
	if (clt->transport.notify_error)
		clt->transport.notify_error(clt);

	EXTRA_ASSERT(clt->prev == NULL);
	EXTRA_ASSERT(clt->next == NULL);
	EXTRA_ASSERT(clt->fd >= 0);

	metautils_pclose(&(clt->fd));
	_cnx_notify_close(srv);

	clt->local_stats = NULL;
	clt->main_stats = NULL;
	clt->flags = clt->events = 0;
	memset(&(clt->time), 0, sizeof(clt->time));

	data_slab_sequence_clean_data(&(clt->input));
	data_slab_sequence_clean_data(&(clt->output));
	clt->input.first = clt->input.last = NULL;
	clt->output.first = clt->output.last = NULL;

	/* clean the transport, if any */
	struct network_transport_s *t = &(clt->transport);
	if (t->client_context && t->clean_context)
		t->clean_context(t->client_context);
	memset(t, 0x00, sizeof(*t));

	if (clt->current_error)
		g_clear_error(&(clt->current_error));

	SLICE_FREE(struct network_client_s, clt);
}
Exemple #15
0
gint
accept_close_servers (ACCEPT_POOL ap, GError **err)
{
	int *pSrv = NULL; 
	int max=0, nb_errors=0;

	if (!ap) {
		GSETERROR(err,"Invalid parameter");
		return 0;
	}

	g_rec_mutex_lock (&(ap->mut));
	if (ap->srv) {
		pSrv = ap->srv;
		max = ap->count;
	}
	ap->srv = NULL;
	ap->count = 0;
	g_rec_mutex_unlock (&(ap->mut));

	if (pSrv) {
		int i;
		for (i=0; i<max ;i++) {
			int fd = pSrv[ i ];
			if (fd>=0) {
				remove_unix_socket( fd );
				errno=0;
				metautils_pclose(&fd);
			}
			pSrv[ i ] = -1;
		}
	}

	g_free(pSrv);
	return nb_errors;
}
Exemple #16
0
int send_request(request_t *req, response_t *resp, GError **error) {
	int fd;
	size_t size_to_send, u_size_sent, u_size_read;
	gint size_sent, size_read;
	message_t message;
	void *buff = NULL;

	memset(&message, 0, sizeof(message_t));

       if (!build_message_from_request(&message, req, error)) {
                GSETERROR(error, "Failed to build message");
                return(0);
        }

        if (!connect_socket(&fd, error)) {
                GSETERROR(error, "Connection to agent failed");
                goto error_connect;
        }

        size_to_send = message.length + sizeof(message.length);
        buff = g_try_malloc0(size_to_send);
        if (buff == NULL) {
                GSETERROR(error, "Memory allocation failure");
                goto error_alloc_buff;
        }

        memcpy(buff, &(message.length), sizeof(message.length));
        memcpy(buff + sizeof(message.length), message.data, message.length);

	size_sent = sock_to_write(fd, CONNECT_TIMEOUT, buff, size_to_send, error);
	if (size_sent<0) {
                GSETERROR(error, "Failed to send all data to agent");
                goto error_write;
	}
        if ((u_size_sent=size_sent) < size_to_send) {
                GSETERROR(error, "Failed to send all data to agent");
                goto error_write;
        }

        /* Clean message to reuse it */
	message_clean( &message);
	size_read = sock_to_read_size(fd, SOCKET_TIMEOUT, &(message.length), sizeof(message.length), error);
        if ((u_size_read=size_read) < sizeof(message.length)) {
                GSETERROR(error, "Failed to read message size");
                goto error_read_size;
        }

        message.data = g_try_malloc0(message.length);
        if (message.data == NULL) {
                GSETERROR(error, "Memory allocation failure");
                goto error_alloc_data;
        }

	size_read = sock_to_read_size(fd, SOCKET_TIMEOUT, message.data, message.length, error);
        if ((u_size_read=size_read) < message.length) {
                GSETERROR(error, "Failed to read all data from agent");
                goto error_read;
        }

        if (!read_response_from_message(resp, &message, error)) {
                GSETERROR(error, "Failed to extract response from message");
                goto error_read_resp;
        }
	
	metautils_pclose(&fd);

	g_free(buff);

	message_clean( &message);
	return(1);

error_read_resp:
error_read:
error_alloc_data:
error_read_size:
error_write:
	if (buff)
		g_free(buff);
error_alloc_buff:
	metautils_pclose(&fd);
error_connect:
	message_clean( &message);
	return(0);
}
Exemple #17
0
static GError *
_endpoint_open(struct endpoint_s *u)
{
	EXTRA_ASSERT(u != NULL);

	struct sockaddr_storage ss;
	socklen_t ss_len = sizeof(ss);
	memset(&ss, 0, sizeof(ss));

	/* patch some socket preferences that make sense only for INET sockets */
	if (_endpoint_is_UNIX(u)) {
		u->port_real = 0;
		u->port_cfg = 0;
		u->flags &= ~(NETSERVER_THROUGHPUT|NETSERVER_LATENCY);
	}

	/* Get a socket of the right type */
	if (_endpoint_is_UNIX(u))
		u->fd = socket(AF_UNIX, SOCK_STREAM, 0);
	else if (_endpoint_is_INET6(u))
		u->fd = socket(AF_INET6, SOCK_STREAM, 0);
	else
		u->fd = socket(AF_INET, SOCK_STREAM, 0);
	if (u->fd < 0)
		return NEWERROR(errno, "socket() = '%s'", strerror(errno));

	if (_endpoint_is_INET(u))
		sock_set_reuseaddr (u->fd, TRUE);

	/* Bind the socket the right way according to its type */
	if (_endpoint_is_UNIX(u)) {
		struct sockaddr_un *sun = (struct sockaddr_un*) &ss;
		ss_len = sizeof(*sun);
		sun->sun_family = AF_UNIX;
		g_strlcpy(sun->sun_path, u->url, sizeof(sun->sun_path));
	} else if (_endpoint_is_INET6(u)) {
		struct sockaddr_in6 *s6 = (struct sockaddr_in6*) &ss;
		ss_len = sizeof(*s6);
		s6->sin6_family = AF_INET6;
		s6->sin6_port = htons(u->port_cfg);
		inet_pton(AF_INET6, u->url, &(s6->sin6_addr));
	} else {
		struct sockaddr_in *s4 = (struct sockaddr_in*) &ss;
		ss_len = sizeof(*s4);
		s4->sin_family = AF_INET;
		s4->sin_port = htons(u->port_cfg);
		inet_pton(AF_INET, u->url, &(s4->sin_addr));
	}
	if (0 > bind(u->fd, (struct sockaddr*)&ss, ss_len)) {
		int errsave = errno;
		u->port_real = 0;
		if (_endpoint_is_UNIX(u))
			metautils_pclose (&u->fd);
		return NEWERROR(errsave, "bind(%s) = '%s'", u->url, strerror(errsave));
	}

	/* for INET sockets, get the port really used */
	if (_endpoint_is_INET(u)) {
		memset(&ss, 0, sizeof(ss));
		ss_len = sizeof(ss);
		getsockname(u->fd, (struct sockaddr*)&ss, &ss_len);
		if (_endpoint_is_INET4(u))
			u->port_real = ntohs(((struct sockaddr_in*)&ss)->sin_port);
		else
			u->port_real = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
	}

	/* And finally set the mandatory fags. */
	sock_set_non_blocking(u->fd, TRUE);

	if (0 > listen(u->fd, 32768))
		return NEWERROR(errno, "listen() = '%s'", strerror(errno));

	return NULL;
}
Exemple #18
0
static GError *
_client_manage_reply(struct gridd_client_s *client, MESSAGE reply)
{
	GError *err;
	guint status = 0;
	gchar *message = NULL;

	if (NULL != (err = metaXClient_reply_simple(reply, &status, &message))) {
		g_prefix_error (&err, "reply: ");
		return err;
	}

	if (CODE_IS_NETWORK_ERROR(status)) {
		err = NEWERROR(status, "net error: %s", message);
		g_free(message);
		metautils_pclose(&(client->fd));
		client->step = STATUS_FAILED;
		return err;
	}

	if (status == CODE_TEMPORARY) {
		g_get_current_time(&(client->tv_step));
		client->step = REP_READING_SIZE;
		g_free(message);
		return NULL;
	}

	if (CODE_IS_OK(status)) {
		g_get_current_time(&(client->tv_step));
		client->step = (status==CODE_FINAL_OK) ? STATUS_OK : REP_READING_SIZE;
		if (client->step == STATUS_OK) {
			if (!client->keepalive)
				metautils_pclose(&(client->fd));
		}
		g_free(message);
		if (client->on_reply) {
			if (!client->on_reply(client->ctx, reply))
				return NEWERROR(CODE_INTERNAL_ERROR, "Handler error");
		}
		return NULL;
	}

	if (status == CODE_REDIRECT) {
		/* Reset the context */
		_client_reset_reply(client);
		_client_reset_cnx(client);
		client->sent_bytes = 0;

		if ((++ client->nb_redirects) > 7) {
			g_free(message);
			return NEWERROR(CODE_TOOMANY_REDIRECT, "Too many redirections");
		}

		/* Save the current URL to avoid looping, and check
		 * for a potential loop */
		g_string_append_c(client->past_url, '|');
		g_string_append(client->past_url, client->url);
		if (_client_looped(client, message)) {
			g_free(message);
			return NEWERROR(CODE_LOOP_REDIRECT, "Looping on redirections");
		}

		/* Replace the URL */
		memset(client->url, 0, sizeof(client->url));
		g_strlcpy(client->url, message, sizeof(client->url)-1);
		if (NULL != (err = _client_connect(client))) {
			g_free(message);
			g_prefix_error(&err, "Redirection error: Connect error: ");
			return err;
		}

		g_free(message);
		return NULL;
	}

	/* all other are considered errors */
	err = NEWERROR(status, "Request error: %s", message);
	g_free(message);
	if (!client->keepalive)
		_client_reset_cnx(client);
	_client_reset_reply(client);
	return err;
}
Exemple #19
0
int
uncompress_chunk2(const gchar* path, gboolean preserve, gboolean keep_pending,
		GError ** error)
{
	GError *local_error = NULL;
	int status = 0;
	TRACE("Uncompressing [%s]", path);
	gchar *tmp_path = NULL;
	gulong tmp_len;
	gint64 total_read;
	guint8* data = NULL;
	gint64 bufsize, nb_read;
	gint64 current_read;
	struct stat *buf = NULL;
	struct compressed_chunk_s *cp_chunk = NULL;
	struct compression_ctx_s *comp_ctx = NULL;
	

	FILE *dst = NULL;

	/* Check chunk exists */
	buf = g_malloc0(sizeof(struct stat));	

	DEBUG("Checking chunk exists");

	if(stat(path, buf) == -1) {
		GSETERROR (error, "stat() failed, chunk not found\n");
		goto end;
	}
	DEBUG("File [%s] found", path);
	
	GHashTable *compress_opt = NULL;
	compress_opt = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free);

	if(!get_compression_info_in_attr(path, error, &compress_opt)) {
		GSETERROR(error, "Failed to get compression info in attr, chunk may be not compressed");
		goto end;
	}
	
	gchar * compression = NULL;
	compression = (gchar*) g_hash_table_lookup(compress_opt, NS_COMPRESSION_OPTION);
	
	if (compression != NULL && g_ascii_strncasecmp(compression, NS_COMPRESSION_ON, strlen(compression)) != 0) {
		GSETERROR(error, "Chunk not compressed, cannot nothing to do");
		goto end;
	}

	/* init compression method according to algo choice */
	comp_ctx = g_malloc0(sizeof(struct compression_ctx_s));
	init_compression_ctx(comp_ctx, g_hash_table_lookup(compress_opt, NS_COMPRESS_ALGO_OPTION));
	cp_chunk = g_malloc0(sizeof(struct compressed_chunk_s));

	if (comp_ctx->chunk_initiator(cp_chunk, path) != 0) {
		GSETERROR(error, "Failed to init compressed chunk context");
		goto end;
	}
	

	DEBUG("Chunk check done");

	tmp_len = strlen(path) +sizeof(".pending");	
	tmp_path = g_malloc0(tmp_len);
	g_snprintf(tmp_path, tmp_len, "%s.pending", path);

	DEBUG("Checking chunk not busy");

	if(stat(tmp_path, buf) != -1) {
		DEBUG("Stats failed");
		GSETERROR (error, "stat() success on pending file, cannot process : busy chunk\n");
		goto end;
	}
	
	do {
	int fd;

	if((fd = open(tmp_path, O_WRONLY|O_CREAT|O_EXCL, 0644)) == -1) {
		GSETERROR(error, "Failed to create pending chunk file (%s)\n", strerror(errno));	
		goto end;
	}
	
	metautils_pclose(&fd);
	} while (0);

	if(!copy_fattr(path, tmp_path, error)) {
		GSETERROR(error, "Failed to copy extended attributes to destination file\n");
		goto end;
	}

	TRACE("xattr copied from src to dst");

	dst = fopen(tmp_path, "w");

	TRACE("Destination file opened");

	gint64 chunk_size;
	chunk_size = g_ascii_strtoll(cp_chunk->uncompressed_size, NULL, 10);

	total_read = 0;	

	DEBUG("Starting, total_read = %"G_GINT64_FORMAT", chunk_size = %"G_GINT64_FORMAT, total_read, chunk_size);

	while(total_read < chunk_size) {
		bufsize = MIN(DECOMPRESSION_MAX_BUFSIZE, (chunk_size - total_read));
		data = g_malloc0(bufsize);
		DEBUG("New buffer allocated sized %"G_GINT64_FORMAT" bytes", bufsize);
		nb_read = 0;
		current_read = 0;
		while(nb_read < bufsize) {
			current_read = comp_ctx->data_uncompressor(cp_chunk, 0, data + nb_read, bufsize - nb_read, &local_error);
			DEBUG("Currently read %"G_GINT64_FORMAT" bytes", current_read);
			if(current_read < 0) {
				if(local_error) {
					GSETERROR(error, "An error occured while decompressing chunk : %s", local_error->message);	
					g_clear_error(&local_error);
				} else
					GSETERROR(error, "An error occured while decompressing chunk\n"); 
				goto end;
			} else if (current_read == 0) {
				/* Premature end of file, will still write to pending */
				WARN("Read 0 bytes, original chunk may have been truncated");
				break;
			}
			nb_read += current_read;
		}
		TRACE("buffer filled");
		errno = 0;
		/* write buf to dst file */
		if(nb_read > 0 && fwrite(data, nb_read, 1, dst) != 1) {
			GSETERROR(error, "An error occured while writing data in destination file: %s",
					strerror(errno));
			goto end;
		}
		if (data) {
			g_free(data);
			data = NULL;
		}
		if (nb_read > 0)
			total_read += nb_read;
		else
			break;
	}

	if(!comp_ctx->integrity_checker(cp_chunk)) {
		GSETERROR(error, "Seems there is an error in decompression, invalid checksum\n");
		goto end;
	}

	status = 1;

end:
	if(dst) {
		if(fclose(dst) != 0)
			WARN("Failed to fclose destination file");
		dst = NULL;
	}
	
	if(status == 1) {
		if(preserve) {
			/* Need to set old file info in new file */
			TRACE("Updating Access / Modify / Change informations");
			struct utimbuf* ut = NULL;
			ut = g_malloc0(sizeof(struct utimbuf));
			ut->actime = buf->st_atime;
			ut->modtime = buf->st_mtime;
			if (0 > chown(tmp_path, buf->st_uid, buf->st_gid)) {
				GSETERROR(error, "chown error: (%d) %s", errno, strerror(errno));
				status = 0;
			}
			if(utime(tmp_path, ut) != 0) {
				GSETERROR(error, "Failed to set correct access time to new file");
				status = 0;
			}
			if(ut)
				g_free(ut);
			if(status == 1) {
				if(rename(tmp_path, path) != 0) {
					GSETERROR(error, "Failed to rename tmp file");
					status = 0;
				}
			} else if (keep_pending) {
				INFO("Temporary file kept: %s", tmp_path);
			} else {
				/* remove tmp file */
				DEBUG("Removing failed file");
				if(remove(tmp_path) != 0)
					WARN("Failed to remove tmp file [%s]", tmp_path);
			}
		} else {
			DEBUG("Renaming pending file\n");
			if(rename(tmp_path, path) != 0) {
				GSETERROR(error, "Failed to rename tmp file");
				status = 0;
			} 
		}
	} else if (keep_pending) {
		INFO("Temporary file kept: %s", tmp_path);
	} else {
		/* remove tmp file */
		DEBUG("Removing pending file\n");
		if(remove(tmp_path) != 0)
			WARN("Failed to remove tmp file [%s]", tmp_path);
	}

	if(compress_opt)
		g_hash_table_destroy(compress_opt);

	if(buf)
		g_free(buf);

	if(data)
		g_free(data);

	if(tmp_path)
		g_free(tmp_path);
	
	return status;
}
Exemple #20
0
int
main_http_config(const gchar *hn, int fd)
{
	int rc;
	GError *error = NULL;
	GByteArray *gba_services = NULL;
	GByteArray *gba_files = NULL;
	ne_session *http_session;

	set_sighandlers();
	fd_out = fd;

	DEBUG("Starting a new configuration process");
	rc = -1;

	bzero(hostname, sizeof(hostname));
	if (!hn)
		gethostname(hostname,sizeof(hostname));
	else
		g_strlcpy(hostname, hn, sizeof(hostname)-1);

	http_session = ne_session_create("http", gridconf_host, gridconf_port);
	ne_set_connect_timeout(http_session, 1);
	ne_set_read_timeout(http_session, 4);

	/*downlaod each file*/
	if (!is_running)
		goto label_error;

	gba_files = download_file_list(http_session, &error);
	if (!gba_files) {
		ERROR("Failed to get the files list file : %s", gerror_get_message(error));
		goto label_error;
	}
	
	if (!is_running)
		goto label_error;
	
	gba_services = download_file_services(http_session, &error);
	if (!gba_services) {
		ERROR("Failed to get the services definition file : %s", gerror_get_message(error));
		goto label_error;
	}
	
	if (!is_running)
		goto label_error;
	
	if (!download_each_configuration_file(http_session, gba_files, &error)) {
		ERROR("Failed to download a configuration file : %s", gerror_get_message(error));
		goto label_error;
	}

	if (!is_running)
		goto label_error;

	if (!dump_gba(gba_services, fd_out, &error)) {
		ERROR("Failed to dump the configuration to fd=%d : %s", fd_out, gerror_get_message(error));
		goto label_error;
	}

	rc = 0;
label_error:
	ne_session_destroy(http_session);
	metautils_pclose(&fd_out);
	if (gba_services)
		g_byte_array_free(gba_services, TRUE);
	if (gba_files)
		g_byte_array_free(gba_files, TRUE);
	DEBUG("http_config child pid=%d exiting with rc=%d", getpid(), rc);
	return rc;
}
Exemple #21
0
gint
accept_add_local (ACCEPT_POOL ap, const gchar *l, GError **err)
{
	struct working_parameter_s wrkParam;
	struct sockaddr_un sun;
	int srv = -1;
	
	if (!l || !(*l))
	{
		GSETERROR(err,"invalid parameter");
		goto errorLabel;
	}

	/*parse the URL*/
	init_socket_options_defaults( l, &wrkParam );
	parse_socket_options( &wrkParam );

	/*try to stat the file*/
	if (-1 == check_socket_is_absent( &wrkParam, err )) {
		GSETERROR(err,"A socket seems already present at [%s]", wrkParam.path.ptr);
	}

	/*open and bind the socket*/

	if (-1==(srv=socket(PF_UNIX, SOCK_STREAM, 0)))
	{
		GSETERROR(err,"Cannot open a new socket PF_UNIX : %s", strerror(errno));
		goto errorLabel;
	}
	
	if (!sock_set_reuseaddr(srv, TRUE)) {
		GSETERROR(err,"Cannot set SO_REUSEADDR on %d [%s] (%s)", srv, l, strerror(errno));
		goto errorLabel;
	}

	fcntl(srv, F_SETFL, O_NONBLOCK|fcntl(srv, F_GETFL));

	sun.sun_family = PF_LOCAL;
	strncpy(sun.sun_path, wrkParam.path.ptr, sizeof(sun.sun_path));

	if (-1==bind (srv, (struct sockaddr*) &sun, sizeof(struct sockaddr_un)))
	{
		GSETERROR(err,"cannot bind srv=%d to %s (%s)", srv, l, strerror(errno));
		goto errorLabel;
	}
	
	if (-1==listen (srv,AP_BACKLOG))
	{
		GSETERROR(err,"cannot listen to inbound connections : %s",  strerror(errno));
		goto errorLabel;
	}
	
	if (!accept_add_any(ap,srv,err))
	{
		GSETERROR(err,"Cannot monitor the local server");
		goto errorLabel;
	}

	/*change socket rights*/
	if (0 != chmod(wrkParam.path.ptr,wrkParam.mode)) {
		int errsav = errno;
		ERROR("Failed to set mode [%o] on UNIX socket [%s] : %s", wrkParam.mode, wrkParam.path.ptr, strerror(errsav));
		SRV_SEND_WARNING("server","UNIX socket might be not accessible : failed to set mode [%o] on UNIX socket [%s] (%s)",
			wrkParam.mode, wrkParam.path.ptr, strerror(errsav));
	}
	
	INFO("socket srv=%d %s now monitored", srv, _get_family_name(FAMILY(&sun)));

	return 1;
errorLabel:
	if (srv>=0)
		metautils_pclose(&srv);
	return 0;
}
Exemple #22
0
static struct network_client_s *
_endpoint_manage_event(struct network_server_s *srv, struct endpoint_s *e)
{
	int fd;
	struct sockaddr_storage ss;
	socklen_t ss_len;

retry:
	memset(&ss, 0, sizeof(ss));
	ss_len = sizeof(ss);
	fd = accept_nonblock(e->fd, (struct sockaddr*)&ss, &ss_len);

	if (0 > fd) {
		if (errno == EINTR)
			goto retry;
		if (errno != EAGAIN && errno != EWOULDBLOCK)
			GRID_WARN("fd=%d ACCEPT error (%d %s)", e->fd, errno, strerror(errno));
		return NULL;
	}

	switch (e->flags) {
		case NETSERVER_THROUGHPUT:
			sock_set_cork(fd, TRUE);
			break;
		case NETSERVER_LATENCY:
			sock_set_linger_default(fd);
			sock_set_nodelay(fd, TRUE);
			sock_set_tcpquickack(fd, TRUE);
			break;
		default:
			break;
	}

	struct network_client_s *clt = SLICE_NEW0(struct network_client_s);
	if (NULL == clt) {
		metautils_pclose(&fd);
		_cnx_notify_close(srv);
		return NULL;
	}

	switch (_cnx_notify_accept(srv)) {
		case EXCESS_SOFT:
			clt->current_error = NEWERROR(CODE_UNAVAILABLE, "Server overloaded.");
		case EXCESS_NONE:
			break;
		case EXCESS_HARD:
			metautils_pclose(&fd);
			_cnx_notify_close(srv);
			return NULL;
	}

	clt->main_stats = srv->stats;
	clt->server = srv;
	clt->fd = fd;
	grid_sockaddr_to_string((struct sockaddr*)&ss,
			clt->peer_name, sizeof(clt->peer_name));
	_client_sock_name(fd, clt->local_name, sizeof(clt->local_name));
	clt->time.cnx = network_server_bogonow(srv);
	clt->events = CLT_READ;

	clt->input.first = clt->input.last = NULL;
	clt->output.first = clt->output.last = NULL;

	if (e->factory_hook)
		e->factory_hook(e->factory_udata, clt);
	return clt;
}
Exemple #23
0
int
compress_chunk(const gchar* path, const gchar* algo, const gint64 blocksize, gboolean preserve, GError ** error)
{

	GError *local_error = NULL;
	int status = 0;
	gchar *tmp_path = NULL;
	gulong tmp_len;
	guint32 compressed_size = 0;
	struct compression_ctx_s* comp_ctx = NULL;
 	struct stat *stat_buf = NULL;

	guint8* buf = NULL;
	gsize nb_read;
	gsize nb_write;
	GByteArray *gba = NULL;

	gulong checksum = 0;

	FILE *src = NULL;
	FILE *dst = NULL;

	/* Sanity check */	
	if(!path || ! algo) {
		GSETERROR(error, "Invalid parameter %p\n", path);
		return status;
	}
	
	if(!check_uncompressed_chunk(path, &local_error)) {
		if(local_error) {
			GSETERROR(error, "Chunk check failed :\n%s", local_error->message);
			g_clear_error(&local_error);
		} else
			GSETERROR(error, "Chunk check failed : no error\n");
		return status;
	}

	tmp_len = strlen(path) +sizeof(".pending");	
	tmp_path = g_malloc0(tmp_len);
	g_snprintf(tmp_path, tmp_len, "%s.pending", path);

	comp_ctx = g_malloc0(sizeof(struct compression_ctx_s));

	if(!init_compression_ctx(comp_ctx, algo)) {
		GSETERROR(error, "Failed to init compression context\n");
		goto end;
	}

	if(!comp_ctx->checksum_initiator(&checksum)) {
		GSETERROR(error, "Failed to init compression checksum\n");
		goto end;
        }
	
        stat_buf = g_malloc0(sizeof(struct stat));
        if(stat(tmp_path, stat_buf) != -1) {
                GSETERROR (error, "stat() success on pending file, cannot process : chunk busy\n");
                goto end;
        }

	
	do {
	int fd;

	if((fd = open(tmp_path, O_WRONLY|O_CREAT|O_EXCL, 0644)) == -1) {
		GSETERROR(error, "Failed to create pending chunk file (%s)\n", strerror(errno));	
		goto end;
	}
	
	metautils_pclose(&fd);
	} while (0);

	if(!copy_fattr(path, tmp_path, &local_error)) {
		if(local_error) {
			GSETERROR(error, "Failed to copy extended attributes to destination file:\n%s",local_error->message);
			g_clear_error(&local_error);
		}
		else
			GSETERROR(error, "Failed to copy extended attributes to destination file\n");
		goto end;
	}
	DEBUG("Extended attributes copied from src to dst\n");
	
	if(!set_compress_attr(tmp_path, algo, blocksize, &local_error)) {
		if(local_error) {
			GSETERROR(error, "Error while adding compression attibutes :\n %s", local_error->message);
			g_clear_error(&local_error);
		}
		goto end;
	}
	
	DEBUG("Compression extended attributes successfully added\n");

	src = fopen(path, "r");
	dst = fopen(tmp_path, "w");

	guint32 bsize32 = blocksize;
	if(comp_ctx->header_writer(dst, bsize32, &checksum, &compressed_size) != 0) {
		GSETERROR(error, "Failed to compress source file\n");
		goto end;
	}
	
	int src_fd = fileno(src);

	gsize bsize = blocksize;
	buf = g_malloc0(blocksize);

	while(1) {
		nb_read = 0;
		nb_read = read(src_fd, buf, bsize);
		if(nb_read != bsize) {
			/* check if we hit eof */
			if(!feof(src) && ferror(src)) {
				GSETERROR(error, "An error occured while reading data from source file\n");
				goto end;	
			} else {
				if(nb_read > 0) {
					gba = g_byte_array_new();
					/* process data */
					if(0 != comp_ctx->data_compressor(buf, nb_read, gba, &checksum)) {
						GSETERROR(error, "Error while compressing data\n");
						goto end;
					}
					/* write compressed data */
					nb_write = 0;
					if ((nb_write = fwrite(gba->data, gba->len, 1, dst)) != 1) {
						GSETERROR(error, "An error occured while writing data in destination file\n");
						goto end;
					}

					compressed_size+=gba->len;
					if(gba) {
						g_byte_array_free(gba, TRUE);
						gba = NULL;
					}
				}
				break; 
			}
		} else {
			gba = g_byte_array_new();
			/* process data */
			if(0 != comp_ctx->data_compressor(buf, nb_read, gba, &checksum)) {
				GSETERROR(error, "Error while compressing data\n");
				goto end;
			}

			/* write compressed data */
			nb_write = 0;
			if ((nb_write = fwrite(gba->data, gba->len, 1, dst)) != 1) {
				GSETERROR(error, "An error occured while writing data in destination file\n");
				goto end;
			}
			
			compressed_size+=gba->len;
			if(gba) {
				g_byte_array_free(gba, TRUE);
				gba = NULL;
			}
		}
		
	}	
	
	DEBUG("Chunk compressed");

	if(comp_ctx->eof_writer(dst, checksum, &compressed_size) != 0) {
		GSETERROR(error, "Failed to write compressed file EOF marker and checksum\n");
		goto end;
	}

	if(!set_chunk_compressed_size_in_attr(tmp_path, error, compressed_size)) {
		GSETERROR(error, "Failed to set compression information in extended attributes\n");
		goto end;
	}

	DEBUG("Compression footers successfully wrote");
	
	status = 1;

end:
	if(src) {
		if(fclose(src) != 0)
			WARN("Failed to fclose source file");
		src = NULL;
	}
	if(dst) {
		if(fclose(dst) != 0)
			WARN("Failed to fclose destination file");
		dst = NULL;
	}
	
	if(status == 1) {
		/* TODO: stat old file, rename, paste stat*/
		if(preserve) {
			/* Need to set old file info in new file */
			TRACE("Renaming and setting good informations to new file...");	
			if(stat_buf)
				g_free(stat_buf);
			stat_buf = g_malloc0(sizeof(struct stat));
			if(stat(path, stat_buf) == -1) {
				GSETERROR (error, "Failed to stat old file, cannot keep old file information, abort\n");
				/* remove tmp file */	
				DEBUG("Removing failed file");
				if(remove(tmp_path) != 0)
					WARN("Failed to remove tmp file [%s]", tmp_path);
				status = 0;
			} else {
				TRACE("Updating Access / Modify / Change informations");
				struct utimbuf* ut = NULL;
				ut = g_malloc0(sizeof(struct utimbuf));
				ut->actime = stat_buf->st_atime;
				ut->modtime = stat_buf->st_mtime;
				if (0 > chown(tmp_path, stat_buf->st_uid, stat_buf->st_gid)) {
					GSETERROR(error, "chown error: (%d) %s", errno, strerror(errno));
					status = 0;
				}
				if(utime(tmp_path, ut) != 0) {
					GSETERROR(error, "Failed to set correct access time to new file");
					status = 0;
				}
				if(ut)
					g_free(ut);
				if(status == 1) {
					if(rename(tmp_path, path) != 0) {
						GSETERROR(error, "Failed to rename tmp file");
						status = 0;
					}
				} else {
					/* remove tmp file */	
					DEBUG("Removing failed file");
					if(remove(tmp_path) != 0)
						WARN("Failed to remove tmp file [%s]", tmp_path);
				}
			}
		} else {
			TRACE("Renaming pending file...");
			if(rename(tmp_path, path) != 0) {
				GSETERROR(error, "Failed to rename tmp file");
				status = 0;
			}
			TRACE("Renaming done");
		}
	} else {
		/* remove tmp file */	
		DEBUG("Removing failed file");
		if(remove(tmp_path) != 0)
			WARN("Failed to remove tmp file [%s]", tmp_path);
	}

	if(stat_buf)	
		g_free(stat_buf);

	if(buf)	
		g_free(buf);
	if(gba)
		g_byte_array_free(gba, TRUE);

	if(tmp_path)
		g_free(tmp_path);
	
	return status;

}
Exemple #24
0
static GError *
_client_manage_reply(struct gridd_client_s *client, MESSAGE reply)
{
	GError *err;
	guint status = 0;
	gchar *message = NULL;

	if (NULL != (err = metaXClient_reply_simple(reply, &status, &message))) {
		g_prefix_error (&err, "reply: ");
		return err;
	}
	STRING_STACKIFY(message);

	if (CODE_IS_NETWORK_ERROR(status)) {
		err = NEWERROR(status, "net error: %s", message);
		metautils_pclose(&(client->fd));
		client->step = STATUS_FAILED;
		return err;
	}

	if (status == CODE_TEMPORARY) {
		client->step = REP_READING_SIZE;
		return NULL;
	}

	if (CODE_IS_OK(status)) {
		client->step = (status==CODE_FINAL_OK) ? STATUS_OK : REP_READING_SIZE;
		if (client->step == STATUS_OK) {
			if (!client->keepalive)
				metautils_pclose(&(client->fd));
		}
		if (client->on_reply) {
			if (!client->on_reply(client->ctx, reply))
				return NEWERROR(CODE_INTERNAL_ERROR, "Handler error");
		}
		return NULL;
	}

	if (status == CODE_REDIRECT && !client->forbid_redirect) {
		/* Reset the context */
		_client_reset_reply(client);
		_client_reset_cnx(client);
		client->sent_bytes = 0;

		if ((++ client->nb_redirects) > 3)
			return NEWERROR(CODE_TOOMANY_REDIRECT, "Too many redirections");

		/* Replace the URL */
		g_strlcpy(client->url, message, URL_MAXLEN);
		if (NULL != (err = _client_connect(client)))
			g_prefix_error(&err, "Redirection error: Connect error: ");
		return err;
	}

	/* all other are considered errors */
	if (status != CODE_REDIRECT)
		err = NEWERROR(status, "Request error: %s", message);
	else
		err = NEWERROR(status, "%s", message);

	if (!client->keepalive)
		_client_reset_cnx(client);
	_client_reset_reply(client);
	return err;
}
Exemple #25
0
static GError *
_client_manage_reply(struct gridd_client_s *client, MESSAGE reply)
{
	GError *err;
	gint status = 0;
	gchar *message = NULL;

	if (!metaXClient_reply_simple(reply, &status, &message, NULL))
		return NEWERROR(500, "Invalid reply");

	switch (status / 100) {

		case 0:
			err = NEWERROR(status, "net error: %s", message);
			g_free(message);
			metautils_pclose(&(client->fd));
			client->step = STATUS_FAILED;
			return err;

		case 1: /* Informational reply :  */
			g_get_current_time(&(client->tv_step));
			client->step = REP_READING_SIZE;
			g_free(message);
			return NULL;

		case 2:
			g_get_current_time(&(client->tv_step));
			client->step = (status==200) ? STATUS_OK : REP_READING_SIZE;
			if (client->step == STATUS_OK) {
				if (!client->keepalive)
					metautils_pclose(&(client->fd));
			}
			g_free(message);
			if (client->on_reply) {
				if (!client->on_reply(client->ctx, reply))
					return NEWERROR(500, "Handler error");
			}
			return NULL;

		case 3: /* redirection */
			if (status == CODE_REDIRECT) {
				/* Reset the context */
				_client_reset_reply(client);
				_client_reset_cnx(client);
				client->sent_bytes = 0;

				if ((++ client->nb_redirects) > 7) {
					g_free(message);
					return NEWERROR(CODE_TOOMANY_REDIRECT,
							"Too many redirections");
				}

				/* Save the current URL to avoid looping, and check
				 * for a potential loop */
				g_string_append_c(client->past_url, '|');
				g_string_append(client->past_url, client->url);
				if (_client_looped(client, message)) {
					g_free(message);
					return NEWERROR(CODE_LOOP_REDIRECT,
							"Looping on redirections");
				}

				/* Replace the URL */
				memset(client->url, 0, sizeof(client->url));
				g_strlcpy(client->url, message, sizeof(client->url)-1);
				if (NULL != (err = _client_connect(client))) {
					g_free(message);
					g_prefix_error(&err, "Redirection error: Connect error: ");
					return err;
				}

				g_free(message);
				return NULL;
			}
			/* FALLTHROUGH */

		default: /* all other are considered errors */
			err = NEWERROR(status, "Request error: %s", message);
			g_free(message);
			if (!client->keepalive)
				_client_reset_cnx(client);
			_client_reset_reply(client);
			return err;
	}
}
Exemple #26
0
static void
parse_output(const gchar *cmd, service_info_t *si)
{
	int fd;
	FILE *stream_in;
	gchar line[1024];
	gchar cmd_with_args[4096] = {0,0,0};

	g_snprintf(cmd_with_args, sizeof(cmd_with_args), "%s %s", cmd, svc_id);
	INFO("Executing [%s]", cmd_with_args);
	if (0 > (fd = command_get_pipe(cmd_with_args))) {
		WARN("Exec failed: %s", strerror(errno));
		return;
	}

	if (!(stream_in = fdopen(fd, "r"))) {
		WARN("fdopen failed: %s", strerror(errno));
		metautils_pclose(&fd);
		return;
	}

	while (!feof(stream_in) && !ferror(stream_in)) {
		GMatchInfo *mi = NULL;

		bzero(line, sizeof(line));
		if (!fgets(line, sizeof(line), stream_in)) {
			break;
		}

		/* chomp the line */
		my_chomp(line);

		if (!g_regex_match(regex_tag, line, 0, &mi)) {
			NOTICE("Unrecognized pattern for output line [%s]", line);
		} else {
			struct service_tag_s *tag;
			gchar *str_type, *str_name, *str_value;

			str_name = g_match_info_fetch(mi, 1);
			str_type = g_match_info_fetch(mi, 2);
			str_value = g_match_info_fetch(mi, 4);

			if (!g_ascii_strcasecmp(str_type, "tag")) {
				tag = service_info_ensure_tag(si->tags, str_name);
				service_tag_set_value_string(tag, str_value);
			}
			else if (!g_ascii_strcasecmp(str_type, "stat")) {
				gdouble dval;

				dval = g_ascii_strtod(str_value, NULL);
				tag = service_info_ensure_tag(si->tags, str_name);
				service_tag_set_value_float(tag, dval);
			}

			g_free(str_value);
			g_free(str_type);
			g_free(str_name);
		}
		g_match_info_free(mi);
	}

	fclose(stream_in);
}