1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

replaced strap() and vstrap() functions by strcatf() and vstrcatf()

The new versions of those string concatenating functions are using realloc() to dynamically resize the string buffer if needed.
We don't use the stack anymore.
This commit is contained in:
Steffen Vogel 2015-09-22 12:58:37 +02:00
parent a5e2eb3f83
commit bfb0221ccf
25 changed files with 168 additions and 144 deletions

View file

@ -52,7 +52,7 @@ int file_init(int argc, char *argv[], struct settings *set);
int file_deinit();
/** @see node_vtable::print */
int file_print(struct node *n, char *buf, int len);
char * file_print(struct node *n);
/** @see node_vtable::parse */
int file_parse(config_setting_t *cfg, struct node *n);

View file

@ -60,7 +60,7 @@ int gtfpga_deinit();
int gtfpga_parse(config_setting_t *cfg, struct node *n);
/** @see node_vtable::print */
int gtfpga_print(struct node *n, char *buf, int len);
char * gtfpga_print(struct node *n);
/** @see node_vtable::open */
int gtfpga_open(struct node *n);

View file

@ -78,8 +78,11 @@ void hist_print(struct hist *h);
/** Print ASCII style plot of histogram */
void hist_plot(struct hist *h);
/** Dump histogram data in Matlab format to buf */
void hist_dump(struct hist *h, char *buf, int len);
/** Dump histogram data in Matlab format.
*
* @return The string containing the dump. The caller is responsible to free() the buffer.
*/
char * hist_dump(struct hist *h);
/** Prints Matlab struct containing all infos to file. */
void hist_matlab(struct hist *h, FILE *f);

View file

@ -66,7 +66,7 @@ int ngsi_deinit();
int ngsi_parse(config_setting_t *cfg, struct node *n);
/** @see node_vtable::print */
int ngsi_print(struct node *n, char *buf, int len);
char * ngsi_print(struct node *n);
/** @see node_vtable::open */
int ngsi_open(struct node *n);

View file

@ -28,7 +28,7 @@
/* Helper macros for virtual node type */
#define node_type(n) ((n)->vt->type)
#define node_print(n, b, l) ((n)->vt->print(n, b, l))
#define node_print(n) ((n)->vt->print(n))
#define node_read(n, p, ps, f, c) ((n)->vt->read(n, p, ps, f, c))
#define node_write(n, p, ps, f, c) ((n)->vt->write(n, p, ps, f, c))
@ -74,14 +74,12 @@ struct node_type {
*/
int (*parse)(config_setting_t *cfg, struct node *n);
/** Print details of socket connection
/** Returns a string with a textual represenation of this node.
*
* @param n A pointer to the node structure
* @param buf The character buffer to be filled.
* @param len The length of the supplied buffer.
* @return The length of the address.
* @return A pointer to a dynamically allocated string. Must be freed().
*/
int (*print)(struct node *n, char *buf, int len);
char * (*print)(struct node *n);
/** Create new socket and connect(), bind(), accept().
*

View file

@ -77,7 +77,7 @@ int opal_deinit();
int opal_parse(config_setting_t *cfg, struct node *n);
/** @see node_vtable::print */
int opal_print(struct node *n, char *buf, int len);
char * opal_print(struct node *n);
int opal_print_global(struct opal_global *g);

View file

@ -138,10 +138,9 @@ void path_print_stats(struct path *p);
* Format: source => [ dest1 dest2 dest3 ]
*
* @param p A pointer to the path structure.
* @param buf A pointer to the buffer which should be filled.
* @param len The length of buf in bytes.
* @return A pointer to a string containing a textual representation of the path.
*/
int path_print(struct path *p, char *buf, int len);
char * path_print(struct path *p);
/** Conditionally execute the hooks
*

View file

@ -81,19 +81,17 @@ int socket_read(struct node *n, struct msg *pool, int poolsize, int first, int c
int socket_parse(config_setting_t *cfg, struct node *n);
/** @see node_vtable::print */
int socket_print(struct node *n, char *buf, int len);
char * socket_print(struct node *n);
/** Generate printable socket address depending on the address family
*
* A IPv4 address is formatted as dotted decimals followed by the port/protocol number
* A link layer address is formatted in hexadecimals digits seperated by colons and the inferface name
*
* @param buf A buffer to be filled.
* @param len The length of the supplied buffer.
* @param sa A pointer to the socket address.
* @retur The length of the address in bytes.
* @return The buffer containing the textual representation of the address. The caller is responsible to free() this buffer!
*/
int socket_print_addr(char *buf, int len, struct sockaddr *sa);
char * socket_print_addr(struct sockaddr *saddr);
/** Parse a socket address depending on the address family
*

View file

@ -37,13 +37,10 @@ int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **ne);
/** Print network emulator (netem) setting into buffer.
*
* @param buf A character buffer to write to.
* @param len The length of the supplied buffer.
* @param tc A pointer to the libnl3 qdisc object where settings will be read from.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
* @return A pointer to a string which must be freed() by the caller.
*/
int tc_print(char *buf, size_t len, struct rtnl_qdisc *ne);
char * tc_print(struct rtnl_qdisc *ne);
/** Remove all queuing disciplines and filters.
*

View file

@ -84,14 +84,22 @@ double box_muller(float m, float s);
/** Double precission uniform random variable */
double randf();
/** Safely append a format string to an existing string.
/** Concat formatted string to an existing string.
*
* This function is similar to strlcat() from BSD.
* This function uses realloc() to resize the destination.
* Please make sure to only on dynamic allocated destionations!!!
*
* @param dest A pointer to a malloc() allocated memory region
* @param fmt A format string like for printf()
* @param ... Optional parameters like for printf()
* @retval The the new value of the dest buffer.
*/
int strap(char *dest, size_t size, const char *fmt, ...);
char * strcatf(char **dest, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
/** Variadic version of strap() */
int vstrap(char *dest, size_t size, const char *fmt, va_list va);
/** Variadic version of strcatv() */
char * vstrcatf(char **dest, const char *fmt, va_list va)
__attribute__ ((format(printf, 2, 0)));
/** Convert integer to cpu_set_t.
*

View file

@ -168,10 +168,10 @@ int config_parse_path(config_setting_t *cfg,
list_push(paths, p);
}
else {
char buf[128];
path_print(p, buf, sizeof(buf));
char *buf = path_print(p);
warn("Path %s is not enabled", buf);
free(buf);
path_destroy(p);
}

View file

@ -26,11 +26,12 @@ int file_deinit()
return 0; /* nothing todo here */
}
int file_print(struct node *n, char *buf, int len)
char * file_print(struct node *n)
{
struct file *f = n->file;
char *buf = NULL;
return snprintf(buf, len, "in=%s, out=%s, mode=%s, rate=%.1f, epoch_mode=%u, epoch=%.0f",
return strcatf(&buf, "in=%s, out=%s, mode=%s, rate=%.1f, epoch_mode=%u, epoch=%.0f",
f->path_in, f->path_out, f->file_mode, f->rate, f->epoch_mode, time_to_double(&f->epoch));
}

View file

@ -100,18 +100,19 @@ int gtfpga_parse(config_setting_t *cfg, struct node *n)
return 0;
}
int gtfpga_print(struct node *n, char *buf, int len)
char * gtfpga_print(struct node *n)
{
struct gtfpga *g = n->gtfpga;
char *buf = NULL;
if (g->dev) {
return snprintf(buf, len, "rate=%.1f slot=%04"PRIx16":%02"PRIx8":%02"PRIx8".%"PRIx8
return strcatf(&buf, "rate=%.1f slot=%04"PRIx16":%02"PRIx8":%02"PRIx8".%"PRIx8
" id=%04"PRIx16":%04"PRIx16" class=%04"PRIx16" irq=%d (%s)", g->rate,
g->dev->domain, g->dev->bus, g->dev->dev, g->dev->func, g->dev->vendor_id, g->dev->device_id,
g->dev->device_class, g->dev->irq, g->name);
}
else {
return snprintf(buf, len, "rate=%.1f slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16, g->rate,
return strcatf(&buf, "rate=%.1f slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16, g->rate,
g->filter.bus, g->filter.device, g->filter.func,
g->filter.vendor, g->filter.device);
}

View file

@ -115,9 +115,9 @@ void hist_print(struct hist *h)
if (h->total - h->higher - h->lower > 0) {
hist_plot(h);
char buf[(h->length + 1) * 8];
hist_dump(h, buf, sizeof(buf));
char *buf = hist_dump(h);
info(buf);
free(buf);
}
}
@ -145,22 +145,23 @@ void hist_plot(struct hist *h)
}
}
void hist_dump(struct hist *h, char *buf, int len)
char * hist_dump(struct hist *h)
{
*buf = 0;
strap(buf, len, "[ ");
char *buf = alloc(128);
strcatf(&buf, "[ ");
for (int i = 0; i < h->length; i++)
strap(buf, len, "%u ", h->data[i]);
strcatf(&buf, "%u ", h->data[i]);
strap(buf, len, "]");
strcatf(&buf, "]");
return buf;
}
void hist_matlab(struct hist *h, FILE *f)
{
char buf[h->length * 8];
hist_dump(h, buf, sizeof(buf));
char *buf = hist_dump(h);
fprintf(f, "%lu = struct( ", time(NULL));
fprintf(f, "'min', %f, 'max', %f, ", h->low, h->high);
@ -171,4 +172,6 @@ void hist_matlab(struct hist *h, FILE *f)
fprintf(f, "'stddev', %f, ", hist_stddev(h));
fprintf(f, "'hist', %s ", buf);
fprintf(f, "),\n");
free(buf);
}

View file

@ -107,12 +107,12 @@ int hook_restart(struct path *p)
{
if (p->current->sequence == 0 &&
p->previous->sequence <= UINT32_MAX - 32) {
char buf[33];
path_print(p, buf, sizeof(buf));
char *buf = path_print(p);
warn("Simulation for path %s restarted (prev->seq=%u, current->seq=%u)",
buf, p->previous->sequence, p->current->sequence);
free(buf);
path_reset(p);
path_reset(p);
}
return 0;

View file

@ -93,10 +93,10 @@ int if_start(struct interface *i, int affinity)
if (ret)
error("Failed to setup FW mark classifier: %s", nl_geterror(ret));
char buf[256];
tc_print(buf, sizeof(buf), s->tc_qdisc);
char *buf = tc_print(s->tc_qdisc);
debug(5, "Starting network emulation on interface '%s' for FW mark %u: %s",
rtnl_link_get_name(i->nl_link), s->mark, buf);
free(buf);
ret = tc_netem(i, &s->tc_qdisc, TC_HANDLE(0x1000+s->mark, 0), TC_HANDLE(1, s->mark));
if (ret)

View file

@ -71,30 +71,32 @@ void log_print(const char *lvl, const char *fmt, ...)
void log_vprint(const char *lvl, const char *fmt, va_list ap)
{
struct timespec ts;
char buf[512] = "";
char *buf = alloc(512);
/* Timestamp */
clock_gettime(CLOCK_REALTIME, &ts);
strap(buf, sizeof(buf), "%10.3f ", time_delta(&epoch, &ts));
strcatf(&buf, "%10.3f ", time_delta(&epoch, &ts));
/* Severity */
strap(buf, sizeof(buf), BLD("%5s "), lvl);
strcatf(&buf, "%5s ", lvl);
/* Indention */
#ifdef __GNUC__
for (int i = 0; i < indent; i++)
strap(buf, sizeof(buf), ACS_VERTICAL " ");
strap(buf, sizeof(buf), ACS_VERTRIGHT " ");
strcatf(&buf, ACS_VERTICAL " ");
strcatf(&buf, ACS_VERTRIGHT " ");
#endif
/* Format String */
vstrap(buf, sizeof(buf), fmt, ap);
vstrcatf(&buf, fmt, ap);
/* Output */
#ifdef ENABLE_OPAL_ASYNC
OpalPrint("S2SS: %s\n", buf);
#endif
fprintf(stderr, "\r%s\n", buf);
free(buf);
}
void line()
@ -148,23 +150,25 @@ void error(const char *fmt, ...)
void serror(const char *fmt, ...)
{
va_list ap;
char buf[1024];
char *buf = NULL;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
vstrcatf(&buf, fmt, ap);
va_end(ap);
log_print(ERROR, "%s: %m (%u)", buf, errno);
free(buf);
die();
}
void cerror(config_setting_t *cfg, const char *fmt, ...)
{
va_list ap;
char buf[1024];
char *buf = NULL;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
vstrcatf(&buf, fmt, ap);
va_end(ap);
log_print(ERROR, "%s in %s:%u", buf,
@ -172,5 +176,7 @@ void cerror(config_setting_t *cfg, const char *fmt, ...)
? config_setting_source_file(cfg)
: "(stdio)",
config_setting_source_line(cfg));
free(buf);
die();
}

View file

@ -235,11 +235,12 @@ int ngsi_parse(config_setting_t *cfg, struct node *n)
return 0;
}
int ngsi_print(struct node *n, char *buf, int len)
char * ngsi_print(struct node *n)
{
struct ngsi *i = n->ngsi;
return snprintf(buf, len, "endpoint=%s, timeout=%.3f secs",
char *buf = NULL;
return strcatf(&buf, "endpoint=%s, timeout=%.3f secs",
i->endpoint, i->timeout);
}

View file

@ -66,10 +66,9 @@ int node_start(struct node *n)
return -1;
}
char str[256];
node_print(n, str, sizeof(str));
debug(1, "Starting node '%s' of type '%s' (%s)", n->name, n->vt->name, str);
char *buf = node_print(n);
debug(1, "Starting node '%s' of type '%s' (%s)", n->name, n->vt->name, buf);
free(buf);
{ INDENT
return n->vt->open(n);

View file

@ -104,17 +104,21 @@ int opal_deinit()
int opal_print_global(struct opal_global *g)
{ INDENT
char sbuf[512] = "";
char rbuf[512] = "";
debug(2, "Controller ID: %u", og->params.controllerID);
char *sbuf = alloc(og->send_icons * 5);
char *rbuf = alloc(og->recv_icons * 5);
for (int i = 0; i < og->send_icons; i++)
strap(sbuf, sizeof(sbuf), "%u ", og->send_ids[i]);
strcatf(&sbuf, "%u ", og->send_ids[i]);
for (int i = 0; i < og->recv_icons; i++)
strap(rbuf, sizeof(rbuf), "%u ", og->recv_ids[i]);
strcatf(&rbuf, "%u ", og->recv_ids[i]);
debug(2, "Controller ID: %u", og->params.controllerID);
debug(2, "Send Blocks: %s", sbuf);
debug(2, "Receive Blocks: %s", rbuf);
free(sbuf);
free(rbuf);
debug(2, "Control Block Parameters:");
for (int i=0; i<GENASYNC_NB_FLOAT_PARAM; i++)
@ -147,13 +151,14 @@ int opal_parse(config_setting_t *cfg, struct node *n)
return 0;
}
int opal_print(struct node *n, char *buf, int len)
char * opal_print(struct node *n)
{
struct opal *o = n->opal;
char *buf = NULL;
/** @todo: Print send_params, recv_params */
return snprintf(buf, len, "send_id=%u, recv_id=%u, reply=%u",
return strcatf(&buf, "send_id=%u, recv_id=%u, reply=%u",
o->send_id, o->recv_id, o->reply);
}

View file

@ -115,10 +115,9 @@ static void * path_run(void *arg)
int path_start(struct path *p)
{ INDENT
char buf[33];
path_print(p, buf, sizeof(buf));
char *buf = path_print(p);
info("Starting path: %s (poolsize = %u)", buf, p->poolsize);
free(buf);
if (path_run_hook(p, HOOK_PATH_START))
return -1;
@ -145,10 +144,9 @@ int path_start(struct path *p)
int path_stop(struct path *p)
{ INDENT
char buf[33];
path_print(p, buf, sizeof(buf));
char *buf = path_print(p);
info("Stopping path: %s", buf);
free(buf);
pthread_cancel(p->recv_tid);
pthread_join(p->recv_tid, NULL);
@ -166,22 +164,22 @@ int path_stop(struct path *p)
return 0;
}
int path_print(struct path *p, char *buf, int len)
char * path_print(struct path *p)
{
*buf = 0;
strap(buf, len, "%s " MAG("=>"), p->in->name);
char *buf = alloc(32);
strcatf(&buf, "%s " MAG("=>"), p->in->name);
if (list_length(&p->destinations) > 1) {
strap(buf, len, " [");
strcatf(&buf, " [");
FOREACH(&p->destinations, it)
strap(buf, len, " %s", it->node->name);
strap(buf, len, " ]");
strcatf(&buf, " %s", it->node->name);
strcatf(&buf, " ]");
}
else
strap(buf, len, " %s", p->out->name);
strcatf(&buf, " %s", p->out->name);
return 0;
return buf;
}
int path_reset(struct path *p)

View file

@ -49,9 +49,9 @@ int socket_init(int argc, char * argv[], struct settings *set)
/* Determine outgoing interface */
if (if_get_egress((struct sockaddr *) &s->remote, &link)) {
char buf[128];
socket_print_addr(buf, sizeof(buf), (struct sockaddr *) &s->remote);
char *buf = socket_print_addr((struct sockaddr *) &s->remote);
error("Failed to get interface for socket address '%s'", buf);
free(buf);
}
int ifindex = rtnl_link_get_ifindex(link);
@ -79,24 +79,26 @@ int socket_deinit()
return 0;
}
int socket_print(struct node *n, char *buf, int len)
char * socket_print(struct node *n)
{
struct socket *s = n->socket;
char local[INET6_ADDRSTRLEN + 16];
char remote[INET6_ADDRSTRLEN + 16];
char *layer = NULL;
char *layer = NULL, *buf = NULL;
switch (s->layer) {
case LAYER_UDP: layer = "udp"; break;
case LAYER_IP: layer = "ip"; break;
case LAYER_ETH: layer = "eth"; break;
case LAYER_UDP: layer = "udp"; break;
case LAYER_IP: layer = "ip"; break;
case LAYER_ETH: layer = "eth"; break;
}
socket_print_addr(local, sizeof(local), (struct sockaddr *) &s->local);
socket_print_addr(remote, sizeof(remote), (struct sockaddr *) &s->remote);
char *local = socket_print_addr((struct sockaddr *) &s->local);
char *remote = socket_print_addr((struct sockaddr *) &s->remote);
return snprintf(buf, len, "layer=%s, local=%s, remote=%s", layer, local, remote);
strcatf(&buf, "layer=%s, local=%s, remote=%s", layer, local, remote);
free(local);
free(remote);
return buf;
}
int socket_open(struct node *n)
@ -319,24 +321,25 @@ int socket_parse(config_setting_t *cfg, struct node *n)
return 0;
}
int socket_print_addr(char *buf, int len, struct sockaddr *saddr)
char * socket_print_addr(struct sockaddr *saddr)
{
union sockaddr_union *sa = (union sockaddr_union *) saddr;
char *buf = alloc(64);
/* Address */
switch (sa->sa.sa_family) {
case AF_INET6:
inet_ntop(AF_INET6, &sa->sin6.sin6_addr, buf, len);
inet_ntop(AF_INET6, &sa->sin6.sin6_addr, buf, 64);
break;
case AF_INET:
inet_ntop(AF_INET, &sa->sin.sin_addr, buf, len);
inet_ntop(AF_INET, &sa->sin.sin_addr, buf, 64);
break;
case AF_PACKET:
snprintf(buf, len, "%02x", sa->sll.sll_addr[0]);
strcatf(&buf, "%02x", sa->sll.sll_addr[0]);
for (int i = 1; i < sa->sll.sll_halen; i++)
strap(buf, len, ":%02x", sa->sll.sll_addr[i]);
strcatf(&buf, ":%02x", sa->sll.sll_addr[i]);
break;
default:
@ -347,7 +350,7 @@ int socket_print_addr(char *buf, int len, struct sockaddr *saddr)
switch (sa->sa.sa_family) {
case AF_INET6:
case AF_INET:
strap(buf, len, ":%hu", ntohs(sa->sin.sin_port));
strcatf(&buf, ":%hu", ntohs(sa->sin.sin_port));
break;
case AF_PACKET: {
@ -356,13 +359,13 @@ int socket_print_addr(char *buf, int len, struct sockaddr *saddr)
if (!link)
error("Failed to get interface for index: %u", sa->sll.sll_ifindex);
strap(buf, len, "%%%s", rtnl_link_get_name(link));
strap(buf, len, ":%hu", ntohs(sa->sll.sll_protocol));
strcatf(&buf, "%%%s", rtnl_link_get_name(link));
strcatf(&buf, ":%hu", ntohs(sa->sll.sll_protocol));
break;
}
}
return 0;
return buf;
}
int socket_parse_addr(const char *addr, struct sockaddr *saddr, enum socket_layer layer, int flags)

View file

@ -21,11 +21,9 @@ void stats_header()
int stats_line(struct path *p)
{
char buf[33];
path_print(p, buf, sizeof(buf));
info("%-32s : %-8u %-8u %-8u %-8u %-8u", buf,
p->sent, p->received, p->dropped, p->skipped, p->invalid);
char *buf = path_print(p);
info("%-32s : %-8u %-8u %-8u %-8u %-8u", buf, p->sent, p->received, p->dropped, p->skipped, p->invalid);
free(buf);
return 0;
}

View file

@ -84,53 +84,53 @@ int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem)
return 0;
}
int tc_print(char *buf, size_t len, struct rtnl_qdisc *ne)
char * tc_print(struct rtnl_qdisc *ne)
{
*buf = 0; /* start from the beginning */
char *buf = NULL;
if (rtnl_netem_get_limit(ne) > 0)
strap(buf, len, "limit %upkts", rtnl_netem_get_limit(ne));
strcatf(&buf, "limit %upkts", rtnl_netem_get_limit(ne));
if (rtnl_netem_get_delay(ne) > 0) {
strap(buf, len, "delay %.2fms ", rtnl_netem_get_delay(ne) / 1000.0);
strcatf(&buf, "delay %.2fms ", rtnl_netem_get_delay(ne) / 1000.0);
if (rtnl_netem_get_jitter(ne) > 0) {
strap(buf, len, "jitter %.2fms ", rtnl_netem_get_jitter(ne) / 1000.0);
strcatf(&buf, "jitter %.2fms ", rtnl_netem_get_jitter(ne) / 1000.0);
if (rtnl_netem_get_delay_correlation(ne) > 0)
strap(buf, len, "%u%% ", rtnl_netem_get_delay_correlation(ne));
strcatf(&buf, "%u%% ", rtnl_netem_get_delay_correlation(ne));
}
}
if (rtnl_netem_get_loss(ne) > 0) {
strap(buf, len, "loss %u%% ", rtnl_netem_get_loss(ne));
strcatf(&buf, "loss %u%% ", rtnl_netem_get_loss(ne));
if (rtnl_netem_get_loss_correlation(ne) > 0)
strap(buf, len, "%u%% ", rtnl_netem_get_loss_correlation(ne));
strcatf(&buf, "%u%% ", rtnl_netem_get_loss_correlation(ne));
}
if (rtnl_netem_get_reorder_probability(ne) > 0) {
strap(buf, len, " reorder%u%% ", rtnl_netem_get_reorder_probability(ne));
strcatf(&buf, " reorder%u%% ", rtnl_netem_get_reorder_probability(ne));
if (rtnl_netem_get_reorder_correlation(ne) > 0)
strap(buf, len, "%u%% ", rtnl_netem_get_reorder_correlation(ne));
strcatf(&buf, "%u%% ", rtnl_netem_get_reorder_correlation(ne));
}
if (rtnl_netem_get_corruption_probability(ne) > 0) {
strap(buf, len, "corruption %u%% ", rtnl_netem_get_corruption_probability(ne));
strcatf(&buf, "corruption %u%% ", rtnl_netem_get_corruption_probability(ne));
if (rtnl_netem_get_corruption_correlation(ne) > 0)
strap(buf, len, "%u%% ", rtnl_netem_get_corruption_correlation(ne));
strcatf(&buf, "%u%% ", rtnl_netem_get_corruption_correlation(ne));
}
if (rtnl_netem_get_duplicate(ne) > 0) {
strap(buf, len, "duplication %u%% ", rtnl_netem_get_duplicate(ne));
strcatf(&buf, "duplication %u%% ", rtnl_netem_get_duplicate(ne));
if (rtnl_netem_get_duplicate_correlation(ne) > 0)
strap(buf, len, "%u%% ", rtnl_netem_get_duplicate_correlation(ne));
strcatf(&buf, "%u%% ", rtnl_netem_get_duplicate_correlation(ne));
}
return 0;
return buf;
}
int tc_prio(struct interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle, tc_hdl_t parent, int bands)

View file

@ -76,23 +76,29 @@ void die()
pthread_kill(_mtid, SIGINT);
}
int strap(char *dest, size_t size, const char *fmt, ...)
char * strcatf(char **dest, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vstrap(dest, size, fmt, ap);
vstrcatf(dest, fmt, ap);
va_end(ap);
return ret;
return *dest;
}
int vstrap(char *dest, size_t size, const char *fmt, va_list ap)
char * vstrcatf(char **dest, const char *fmt, va_list ap)
{
int len = strlen(dest);
char *tmp;
int n = *dest ? strlen(*dest) : 0;
int i = vasprintf(&tmp, fmt, ap);
return vsnprintf(dest + len, size - len, fmt, ap);
*dest = (char *)(realloc(*dest, n + i + 1));
if (*dest != NULL)
strncpy(*dest+n, tmp, i + 1);
free(tmp);
return *dest;
}
cpu_set_t to_cpu_set(int set)