Project

General

Profile

Review #751 » 0002-Move-BIP-commands-to-bip_strcat-f-_fit-memccpy-wrapp.patch

Do not truncate output - Loïc Gomez, 2022-01-10 19:21

View differences:

src/bip.c
#define RET_STR_LEN 256
#define LINE_SIZE_LIM 70
void adm_print_connection(struct link_client *ic, struct link *lnk,
struct bipuser *bu)
{
hash_iterator_t lit;
char buf[RET_STR_LEN + 1];
int t_written = 0;
char buf[LINE_SIZE_LIM + 1];
char *bufpos = buf;
size_t remaining = LINE_SIZE_LIM;
if (!bu)
bu = lnk->user;
......
(lnk->connect_nick ? lnk->connect_nick : bu->default_nick),
(lnk->username ? lnk->username : bu->default_username));
t_written = snprintf(buf, RET_STR_LEN, " Options:");
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcat_fit(&remaining, bufpos, " Options:");
// This should not happen, unless LINE_SIZE_LIM is too low
if (!bufpos)
goto limittoolow;
if (lnk->follow_nick) {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, " follow_nick");
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcat_fit(&remaining, bufpos, " follow_nick");
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcat_fit(&remaining, bufpos, " follow_nick");
if (!bufpos)
goto limittoolow;
}
}
if (lnk->ignore_first_nick) {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, " ignore_first_nick");
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcat_fit(&remaining, bufpos, " ignore_first_nick");
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcat_fit(&remaining, bufpos, " ignore_first_nick");
if (!bufpos)
goto limittoolow;
}
}
if (lnk->away_nick) {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, " away_nick=%s",
lnk->away_nick);
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcatf_fit(&remaining, bufpos, " away_nick=%s", lnk->away_nick);
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcatf_fit(&remaining, bufpos, " away_nick=%s", lnk->away_nick);
if (!bufpos)
goto limittoolow;
}
}
if (lnk->no_client_away_msg) {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, " no_client_away_msg=%s",
lnk->no_client_away_msg);
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcatf_fit(&remaining, bufpos, " no_client_away_msg=%s", lnk->no_client_away_msg);
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcatf_fit(&remaining, bufpos, " no_client_away_msg=%s", lnk->no_client_away_msg);
if (!bufpos)
goto limittoolow;
}
}
if (lnk->vhost) {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, " vhost=%s",
lnk->vhost);
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcatf_fit(&remaining, bufpos, " vhost=%s", lnk->vhost);
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcatf_fit(&remaining, bufpos, " vhost=%s", lnk->vhost);
if (!bufpos)
goto limittoolow;
}
}
if (lnk->bind_port) {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, " bind_port=%u",
lnk->bind_port);
if (t_written >= RET_STR_LEN)
goto noroom;
}
noroom: /* that means the line is larger that RET_STR_LEN. We're not likely to
even read such a long line */
buf[RET_STR_LEN] = 0;
bufpos = bip_strcatf_fit(&remaining, bufpos, " bind_port=%s", lnk->bind_port);
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcatf_fit(&remaining, bufpos, " bind_port=%s", lnk->bind_port);
if (!bufpos)
goto limittoolow;
}
}
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = buf;
list_iterator_t itocs;
for (list_it_init(&lnk->on_connect_send, &itocs);
list_it_item(&itocs); ) {
bufpos = bip_strcatf_fit(&remaining, bufpos, "%s",
(char *)list_it_item(&itocs));
if (!bufpos) {
// if oversized, print and reset
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = buf;
continue;
} else {
// if ok, go to next item
list_it_next(&itocs);
}
}
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = buf;
// TODO: on_connect_send
// TODO : check channels struct
t_written = snprintf(buf, RET_STR_LEN, " Channels (* with key, ` no backlog)");
if (t_written >= RET_STR_LEN)
goto noroomchan;
bufpos = bip_strcat_fit(&remaining, bufpos, " Channels (* with key, ` no backlog)");
if (!bufpos)
goto limittoolow;
for (hash_it_init(&lnk->chan_infos, &lit); hash_it_item(&lit);
hash_it_next(&lit)) {
struct chan_info *ch = hash_it_item(&lit);
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written, " %s%s%s",
bufpos = bip_strcatf_fit(&remaining, bufpos, "%s%s%s",
ch->name, (ch->key ? "*" : ""),
(ch->backlog ? "" : "`"));
if (t_written > LINE_SIZE_LIM) {
buf[RET_STR_LEN] = 0;
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
t_written = 0;
remaining = LINE_SIZE_LIM;
bufpos = buf;
}
}
noroomchan:
buf[RET_STR_LEN] = 0;
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = buf;
t_written = snprintf(buf, RET_STR_LEN, " Status: ");
if (t_written >= RET_STR_LEN)
goto noroomstatus;
bufpos = bip_strcat_fit(&remaining, bufpos, " Status: ");
if (!bufpos)
goto limittoolow;
switch (lnk->s_state) {
case IRCS_NONE:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
"not started");
if (t_written >= RET_STR_LEN)
goto noroomstatus;
bufpos = bip_strcat_fit(&remaining, bufpos, "not started");
if (!bufpos)
goto limittoolow;
break;
case IRCS_CONNECTING:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
bufpos = bip_strcatf_fit(&remaining, bufpos,
"connecting... attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
if (t_written >= RET_STR_LEN)
if (!bufpos)
goto noroomstatus;
break;
case IRCS_CONNECTED:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
"connected !");
if (t_written >= RET_STR_LEN)
goto noroomstatus;
bufpos = bip_strcat_fit(&remaining, bufpos, "connected !");
if (!bufpos)
goto limittoolow;
break;
case IRCS_WAS_CONNECTED:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
bufpos = bip_strcatf_fit(&remaining, bufpos,
"disconnected, attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
if (t_written >= RET_STR_LEN)
if (!bufpos)
goto noroomstatus;
break;
case IRCS_RECONNECTING:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
bufpos = bip_strcatf_fit(&remaining, bufpos,
"reconnecting... attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
if (t_written >= RET_STR_LEN)
if (!bufpos)
goto noroomstatus;
break;
case IRCS_TIMER_WAIT:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
bufpos = bip_strcatf_fit(&remaining, bufpos,
"waiting to reconnect, attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
if (t_written >= RET_STR_LEN)
if (!bufpos)
goto noroomstatus;
break;
default:
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
"unknown");
if (t_written >= RET_STR_LEN)
goto noroomstatus;
bufpos = bip_strcat_fit(&remaining, bufpos, "unknown");
if (!bufpos)
goto limittoolow;
break;
// s_conn_attempt recon_timer last_connection_attempt
}
noroomstatus:
buf[RET_STR_LEN] = 0;
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
return;
noroomstatus:
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%stoo long to print", buf);
return;
limittoolow:
bip_notify(ic, "cannot print connection, LINE_SIZE_LIM(%d) "
"is too low (please recompile)", LINE_SIZE_LIM);
return;
}
void adm_list_all_links(struct link_client *ic)
......
void adm_info_user(struct link_client *ic, const char *name)
{
struct bipuser *u;
char buf[RET_STR_LEN + 1];
int t_written = 0;
bip_notify(ic, "-- User '%s' info", name);
u = hash_get(&_bip->users, name);
......
return;
}
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
"user: %s", u->name);
if (t_written >= RET_STR_LEN)
goto noroom;
if (u->admin) {
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
", is bip admin");
if (t_written >= RET_STR_LEN)
goto noroom;
}
noroom:
buf[RET_STR_LEN] = 0;
bip_notify(ic, "%s", buf);
bip_notify(ic, "user: %s%s", u->name, (u->admin ? ", is bip admin" : ""));
#ifdef HAVE_LIBSSL
if (u->ssl_check_store) {
......
{
hash_iterator_t it;
hash_iterator_t lit;
char buf[RET_STR_LEN + 1];
char buf[LINE_SIZE_LIM + 1];
size_t remaining = LINE_SIZE_LIM;
bip_notify(ic, "-- User list");
for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
hash_it_next(&it)) {
struct bipuser *u = hash_it_item(&it);
int first = 1;
int t_written = 0;
char *bufpos = buf;
buf[RET_STR_LEN] = 0;
t_written += snprintf(buf, RET_STR_LEN, "* %s%s:", u->name,
bufpos = bip_strcatf_fit(&remaining, bufpos, "* %s%s:", u->name,
(u->admin ? "(admin)": ""));
if (t_written >= RET_STR_LEN)
goto noroom;
for (hash_it_init(&u->connections, &lit); hash_it_item(&lit);
hash_it_next(&lit)) {
// this should not happen or LINE_SIZE_LIM is really low...
if (!bufpos)
goto limittoolow;
for (hash_it_init(&u->connections, &lit); hash_it_item(&lit); ) {
struct link *lnk = hash_it_item(&lit);
if (first) {
first = 0;
} else {
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written, ",");
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcat_fit(&remaining, bufpos, ",");
// if this is too long for a comma, print and prefix with spaces
if (!bufpos) {
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = bip_strcat_fit(&remaining, buf, " ");;
// this should not happen or LINE_SIZE_LIM is really low...
if (!bufpos)
goto limittoolow;
}
}
t_written += snprintf(buf + t_written,
RET_STR_LEN - t_written,
" %s", lnk->name);
if (t_written >= RET_STR_LEN)
goto noroom;
if (t_written > LINE_SIZE_LIM) {
buf[RET_STR_LEN] = 0;
bufpos = bip_strcatf_fit(&remaining, bufpos, " %s", lnk->name);
if (!bufpos) {
// if this is too long, print and reset
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
t_written = 0;
remaining = LINE_SIZE_LIM;
bufpos = bip_strcat_fit(&remaining, buf, " ");;
// this should not happen or LINE_SIZE_LIM is really low...
if (!bufpos)
goto limittoolow;
} else {
// if all good, go to next entry
hash_it_next(&lit);
}
}
noroom:
buf[RET_STR_LEN] = 0;
buf[LINE_SIZE_LIM] = 0;
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = buf;
}
bip_notify(ic, "-- End of User list");
return;
limittoolow:
bip_notify(ic, "cannot print users, LINE_SIZE_LIM(%d) "
"is too low (please recompile)", LINE_SIZE_LIM);
}
void adm_list_networks(struct link_client *ic)
......
for (hash_it_init(&_bip->networks, &it); hash_it_item(&it);
hash_it_next(&it)) {
struct network *n = hash_it_item(&it);
int t_written = 0;
int i;
char *bufpos = buf;
size_t remaining = RET_STR_LEN;
buf[RET_STR_LEN] = 0;
#ifdef HAVE_LIBSSL
if (n->ssl) {
t_written += snprintf(buf, RET_STR_LEN, "- %s*:",
bufpos = bip_strcatf_fit(&remaining, bufpos, "- %s*:",
n->name);
if (t_written >= RET_STR_LEN)
goto noroom;
} else {
#endif
t_written += snprintf(buf, RET_STR_LEN, "- %s:", n->name);
if (t_written >= RET_STR_LEN)
goto noroom;
bufpos = bip_strcatf_fit(&remaining, bufpos, "- %s:",
n->name);
#ifdef HAVE_LIBSSL
}
#endif
for (i = 0; i < n->serverc; i++) {
// if we've reached max length, print name and reset
// honestly, this should not happen, but for the sake of cleanliness...
if (!bufpos) {
#ifdef HAVE_LIBSSL
if (n->ssl) {
bip_notify(ic, "- %s*:", n->name);
} else {
#endif
bip_notify(ic, "- %s:", n->name);
#ifdef HAVE_LIBSSL
}
#endif
bufpos = buf;
remaining = RET_STR_LEN;
}
for (i = 0; i < n->serverc; ) {
struct server *serv = i+n->serverv;
t_written += snprintf(buf + t_written, RET_STR_LEN
- t_written, " %s:%d", serv->host,
serv->port);
if (t_written >= RET_STR_LEN)
goto noroom;
if (t_written > LINE_SIZE_LIM) {
bufpos = bip_strcatf_fit(&remaining, bufpos, " %s:%d",
serv->host, serv->port);
if (!bufpos) {
// if line is too long, print and reset
buf[RET_STR_LEN] = 0;
bip_notify(ic, "%s", buf);
t_written = 0;
remaining = RET_STR_LEN;
bufpos = buf;
i--;
} else {
// if ok, go to next server
i++;
}
}
noroom:
buf[RET_STR_LEN] = 0;
bip_notify(ic, "%s", buf);
}
......
void adm_on_connect_send(struct link_client *ic, struct line *line,
unsigned int privmsg)
{
size_t remaining = ON_CONNECT_MAX_STRSIZE;
char buf[ON_CONNECT_MAX_STRSIZE];
int t_written = 0;
char *bufpos = buf;
int i;
if (!line) {
......
return;
}
if (irc_line_includes(line, 2))
if (!irc_line_includes(line, 2)) {
mylog(LOG_DEBUG, "[%s] not enough parameters on /BIP on_connect_send",
LINK(ic)->user->name);
return;
}
for (i = privmsg + 2; i < irc_line_count(line); i++) {
if (t_written) {
t_written += snprintf(buf,
ON_CONNECT_MAX_STRSIZE - 1 - t_written,
" %s", irc_line_elem(line, i));
if (t_written >= ON_CONNECT_MAX_STRSIZE)
goto noroom;
} else {
t_written = snprintf(buf, ON_CONNECT_MAX_STRSIZE - 1,
"%s", irc_line_elem(line, i));
if (t_written >= ON_CONNECT_MAX_STRSIZE)
goto noroom;
mylog(LOG_DEBUG, "[%s] processing item %d, remaining %ld, %s",
LINK(ic)->user->name, i, remaining, buf);
if ((unsigned int)i > privmsg + 2)
bufpos = bip_strcatf_fit(&remaining, bufpos, " %s",
irc_line_elem(line, i));
else
bufpos = bip_strcat_fit(&remaining, bufpos,
(char *)irc_line_elem(line, i));
mylog(LOG_DEBUG, "[%s] processed item %d, remaining %ld, %s",
LINK(ic)->user->name, i, remaining, buf);
if (!bufpos) {
bip_notify(ic, "on connect send string too big, not changing.");
return;
}
}
ok:
buf[ON_CONNECT_MAX_STRSIZE - 1] = 0;
set_on_connect_send(ic, buf);
return;
noroom:
bip_notify(ic, "on connect send string too big, truncated");
goto ok;
}
void adm_away_nick(struct link_client *ic, const char *val)
......
mylog(LOG_INFO, "/BIP %s from %s", irc_line_elem(line, privmsg + 1),
LINK(ic)->user->name);
if (strcasecmp(irc_line_elem(line, privmsg + 1), "RELOAD") == 0) {
if (irc_line_elem_case_equals(line, privmsg + 1, "RELOAD")) {
if (!admin) {
bip_notify(ic, "-- You're not allowed to reload bip");
return OK_FORGET;
......
bip_notify(ic, "-- Reloading bip...");
bip->reloading_client = ic;
sighup = 1;
} else if (strcasecmp(irc_line_elem(line, privmsg + 1), "LIST") == 0) {
} else if (irc_line_elem_case_equals(line, privmsg + 1, "LIST")) {
if (irc_line_count(line) != privmsg + 3) {
bip_notify(ic, "-- LIST command needs one argument");
return OK_FORGET;
......
} else {
bip_notify(ic, "-- Invalid LIST request");
}
} else if (strcasecmp(irc_line_elem(line, privmsg + 1), "INFO") == 0) {
if (!irc_line_includes(line, privmsg + 2)) {
bip_notify(ic, "-- INFO command needs at least one "
"argument");
} else if (irc_line_elem_case_equals(line, privmsg + 1, "INFO")) {
if (!irc_line_includes(line, privmsg + 3)) {
bip_notify(ic, "-- INFO command needs at least two "
"arguments");
return OK_FORGET;
}
src/util.c
return r;
}
char *bip_strcat_fit(size_t *remaining, char *str, char *str2)
{
char *res;
if (!remaining || !str || !str2) {
mylog(LOG_DEBUGVERB, "bip_strcat_fit: got NULL pointer");
return NULL;
}
res = memccpy(str, str2, '\0', *remaining);
if (!res) {
mylog(LOG_DEBUGTOOMUCH, "bip_strcat_fit: memccpy() failed, remaining %lu",
*remaining);
return NULL;
}
res--;
if (res < str) {
mylog(LOG_DEBUG, "bip_strcat_fit: memccpy res < str");
return NULL;
}
(*remaining) -= (size_t)(res - str);
return res;
}
char *bip_strcatf_fit(size_t *remaining, char *str, char *fmt, ...)
{
va_list ap;
char str2[*remaining];
size_t written;
char *res = NULL;
if (!remaining || !str || !fmt) {
mylog(LOG_DEBUGVERB, "bip_strcatf_fit: NULL pointer");
return NULL;
}
va_start(ap, fmt);
written = vsnprintf(str2, *remaining, fmt, ap);
if (written >= *remaining) {
mylog(LOG_DEBUGVERB, "bip_strcatf_fit,vsnprintf: no space left");
goto end;
}
res = memccpy(str, str2, '\0', *remaining);
if (!res) {
mylog(LOG_DEBUGTOOMUCH, "bip_strcatf_fit: memccpy() failed, remaining %lu",
*remaining);
goto end;
}
if (res < str) {
mylog(LOG_DEBUG, "bip_strcatf_fit: memccpy res < str");
goto end;
}
res--;
(*remaining) -= (size_t)(res - str);
end:
va_end(ap);
return res;
}
/*
* <nick> ::= <letter> { <letter> | <number> | <special> }
* <special> ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
src/util.h
void *bip_calloc(size_t nmemb, size_t size);
void *bip_realloc(void *ptr, size_t size);
char *bip_strdup(const char *str);
char *bip_strcat_fit(size_t *remaining, char *str, char *str2);
char *bip_strcatf_fit(size_t *remaining, char *str, char *str2, ...);
#define array_each(a, idx, ptr) for ((idx) = 0; \
(idx) < (a)->elemc && (((ptr) = array_get((a), (idx))) || 1); \
(idx)++)
(3-3/4)