/* Copyright (c) 2008-2012 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" #endif #include #include "common-utils.h" #include "xlator.h" #include "graph-utils.h" struct gf_printer { ssize_t (*write) (struct gf_printer *gp, char *buf, size_t len); void *priv; int len; }; static ssize_t gp_write_file (struct gf_printer *gp, char *buf, size_t len) { FILE *f = gp->priv; if (fwrite (buf, len, 1, f) != 1) { gf_log ("graph-print", GF_LOG_ERROR, "fwrite failed (%s)", strerror (errno)); return -1; } return len; } static ssize_t gp_write_buf (struct gf_printer *gp, char *buf, size_t len) { struct iovec *iov = gp->priv; if (iov->iov_len < len) { gf_log ("graph-print", GF_LOG_ERROR, "buffer full"); return -1; } memcpy (iov->iov_base, buf, len); iov->iov_base += len; iov->iov_len -= len; return len; } static int gpprintf (struct gf_printer *gp, const char *format, ...) { va_list arg; char *str = NULL; int ret = 0; va_start (arg, format); ret = gf_vasprintf (&str, format, arg); va_end (arg); if (ret < 0) return ret; ret = gp->write (gp, str, ret); GF_FREE (str); return ret; } #define GPPRINTF(gp, fmt, ...) do { \ ret = gpprintf (gp, fmt, ## __VA_ARGS__); \ if (ret == -1) \ goto out; \ else \ gp->len += ret; \ } while (0) static int _print_volume_options (dict_t *d, char *k, data_t *v, void *tmp) { struct gf_printer *gp = tmp; int ret = 0; GPPRINTF (gp, " option %s %s\n", k, v->data); return 0; out: /* means, it is a failure */ return -1; } static int glusterfs_graph_print (struct gf_printer *gp, glusterfs_graph_t *graph) { xlator_t *trav = NULL; xlator_list_t *xch = NULL; int ret = 0; ssize_t len = 0; if (!graph->first) return 0; for (trav = graph->first; trav->next; trav = trav->next); for (; trav; trav = trav->prev) { GPPRINTF (gp, "volume %s\n type %s\n", trav->name, trav->type); ret = dict_foreach (trav->options, _print_volume_options, gp); if (ret) goto out; if (trav->children) { GPPRINTF (gp, " subvolumes"); for (xch = trav->children; xch; xch = xch->next) GPPRINTF (gp, " %s", xch->xlator->name); GPPRINTF (gp, "\n"); } GPPRINTF (gp, "end-volume\n"); if (trav != graph->first) GPPRINTF (gp, "\n"); } out: len = gp->len; if (ret == -1) { gf_log ("graph-print", GF_LOG_ERROR, "printing failed"); return -1; } return len; #undef GPPRINTF } int glusterfs_graph_print_file (FILE *file, glusterfs_graph_t *graph) { struct gf_printer gp = { .write = gp_write_file, .priv = file }; return glusterfs_graph_print (&gp, graph); } char * glusterfs_graph_print_buf (glusterfs_graph_t *graph) { FILE *f = NULL; struct iovec iov = {0,}; int len = 0; char *buf = NULL; struct gf_printer gp = { .write = gp_write_buf, .priv = &iov }; f = fopen ("/dev/null", "a"); if (!f) { gf_log ("graph-print", GF_LOG_ERROR, "cannot open /dev/null (%s)", strerror (errno)); return NULL; } len = glusterfs_graph_print_file (f, graph); fclose (f); if (len == -1) return NULL; buf = GF_CALLOC (1, len + 1, gf_common_mt_graph_buf); if (!buf) { return NULL; } iov.iov_base = buf; iov.iov_len = len; len = glusterfs_graph_print (&gp, graph); if (len == -1) { GF_FREE (buf); return NULL; } return buf; }