#include #include #include #include #include #include int BINARY_FORMAT = 1; // .h enum encoded_type_t { TYPE_KV, TYPE_STRING, TYPE_UINT32, TYPE_UINT16, MAX_TYPE }; struct buffer { size_t siz; uint16_t pos; void *buf; }; #define DEFAULT_BUF_SIZ 1024 struct buffer *log_start(); void log_end(struct buffer *buf); int buf_uint32(struct buffer *buf, uint32_t ui); int buf_uint16(struct buffer *buf, uint16_t ui); int buf_string(struct buffer *buf, const char *str); int buf_unsafestring(struct buffer *buf, const char *str); int buf_char(struct buffer *buf, const char c); void log_kv_uint32(struct buffer *buf, const char *key, uint32_t val); void log_kv_string(struct buffer *buf, const char *key, const char *val); void log_kv_unsafestring(struct buffer *buf, const char *key, const char *val); // end .h struct buffer *log_start() { struct buffer *b; b = malloc(sizeof(struct buffer)); if (b) { b->buf = malloc(DEFAULT_BUF_SIZ); b->siz = DEFAULT_BUF_SIZ; b->pos = (BINARY_FORMAT ? 2 : 0); /* binary: prefix length using uint16_t */ memset(b->buf, 0, b->siz); } return (b); } void log_end(struct buffer *buf) { FILE *fp; uint16_t tmppos; if (BINARY_FORMAT) { /* tmppos = buf->pos; buf->pos = 0; buf_uint16(buf, tmppos); buf->pos = tmppos; */ tmppos = htons(buf->pos); memcpy(buf->buf, &tmppos, 2); fp = popen("xxd", "w"); if (!fp) { perror("popen"); } else { fwrite(buf->buf, buf->pos, 1, fp); fclose(fp); } } else { printf("%s\n", (char *) buf->buf); } free(buf->buf); free(buf); } int buf_resize(struct buffer *buf, size_t siz) { size_t newsiz = siz > 2 * buf->siz ? siz : 2 * buf->siz; void *newbuf; newbuf = realloc(buf->buf, newsiz); if (!newbuf) return (-1); buf->buf = newbuf; buf->siz = newsiz; return (0); } int buf_vsprintf(struct buffer *buf, const char *format, va_list ap) { int rc; va_list bak; va_copy(bak, ap); rc = vsnprintf(buf->buf + buf->pos, buf->siz - buf->pos, format, ap); if (rc > buf->siz - buf->pos) { rc = buf_resize(buf, buf->siz + rc + 1); if (rc >= 0) { rc = vsnprintf(buf->buf + buf->pos, buf->siz - buf->pos, format, bak); } } if (rc > 0) buf->pos += rc; va_end(bak); return (rc); } int buf_sprintf(struct buffer *buf, const char *format, ...) { int rc; va_list ap; va_start(ap, format); rc = buf_vsprintf(buf, format, ap); va_end(ap); return (rc); } int buf_type(struct buffer *buf, enum encoded_type_t type) { if (buf->pos == buf->siz && buf_resize(buf, buf->siz + 1)) return (-1); /* assert type < uint8_max (256) */ memcpy(buf->buf + buf->pos++, &type, 1); return (0); } int buf_uint32(struct buffer *buf, uint32_t ui) { int rc = 0; ui = htonl(ui); if (BINARY_FORMAT) { buf_type(buf, TYPE_UINT32); if (buf->siz - buf->pos < sizeof(ui) && buf_resize(buf, buf->siz + sizeof(ui))) return (-1); memcpy(buf->buf + buf->pos, &ui, sizeof(ui)); buf->pos += sizeof(ui); } else { rc = buf_sprintf(buf, "%u", ui); } return (rc); } int buf_uint16(struct buffer *buf, uint16_t ui) { int rc = 0; ui = htons(ui); if (BINARY_FORMAT) { buf_type(buf, TYPE_UINT16); if (buf->siz - buf->pos < sizeof(ui) && buf_resize(buf, buf->siz + sizeof(ui))) return (-1); memcpy(buf->buf + buf->pos, &ui, sizeof(ui)); buf->pos += sizeof(ui); } else { rc = buf_sprintf(buf, "%hu", ui); } return (rc); } int buf_string(struct buffer *buf, const char *str) { int rc = 0; size_t len = strlen(str); uint16_t len16; if (BINARY_FORMAT) { buf_type(buf, TYPE_STRING); if (len > 0x0ffff) return (-1); len16 = len & 0x0ffff; /* +2 for the encoded length of the string */ if (len + 2 > buf->siz - buf->pos && buf_resize(buf, buf->siz + len + 2)) return (-1); len16 = htons(len16); memcpy(buf->buf + buf->pos, &len16, sizeof(len16)); memcpy(buf->buf + buf->pos + 2, str, len); buf->pos += (len + 2); } else { rc = buf_sprintf(buf, "%s", str); } return (rc); } int buf_unsafestring(struct buffer *buf, const char *str) { char ch = 0; char *temp; size_t i, pos, len = strlen(str); static char hex[16] = "0123456789ABCDEF"; static char encode[14] = { '0', // \0 0, 0, 0, 0, 0, 0, // 1-6 'a', 'b', 't', 'n', 'v', 'f', 'r' // 7-13 // BEL, BS, HT, LF, VT, FF, CR }; temp = malloc(3 * len + 1); if (!temp) return (-1); for(i = pos = 0; i < len; i++, pos++) { if (isprint(str[i]) && str[i] != '\'' && str[i] != '\\') { temp[pos] = str[i]; } else { temp[pos++] = '\\'; if (str[i] < 14) ch = encode[str[i]]; else if (str[i] == '\'') ch = '\''; else if (str[i] == '\\') ch = '\\'; if (ch) { temp[pos] = ch; } else { temp[pos++] = hex[(str[i] & 0xf0) >> 4]; temp[pos] = hex[str[i] & 0x0f]; } } } temp[pos] = '\0'; buf_string(buf, temp); free(temp); return (0); } int buf_char(struct buffer *buf, const char c) { if (buf->pos == buf->siz && buf_resize(buf, buf->siz + 1)) return (-1); memcpy(buf->buf + buf->pos++, &c, 1); return (0); } void log_kv_uint32(struct buffer *buf, const char *key, uint32_t val) { if (BINARY_FORMAT) { buf_type(buf, TYPE_KV); buf_string(buf, key); buf_uint32(buf, val); } else { buf_char(buf, ' '); buf_string(buf, key); buf_char(buf, '='); buf_uint32(buf, val); } } void log_kv_string(struct buffer *buf, const char *key, const char *val) { if (BINARY_FORMAT) { buf_type(buf, TYPE_KV); buf_string(buf, key); buf_string(buf, val); } else { /* check val for illegal characters? */ buf_char(buf, ' '); buf_string(buf, key); buf_char(buf, '='); buf_char(buf, '\''); buf_string(buf, val); buf_char(buf, '\''); } } void log_kv_unsafestring(struct buffer *buf, const char *key, const char *val) { if (BINARY_FORMAT) { buf_type(buf, TYPE_KV); buf_string(buf, key); buf_string(buf, val); } else { buf_char(buf, ' '); buf_string(buf, key); buf_char(buf, '='); buf_char(buf, '\''); buf_unsafestring(buf, val); buf_char(buf, '\''); } } int main(int argc, char *argv[]) { BINARY_FORMAT = argc % 2; struct buffer *buf = log_start(); log_kv_string(buf, "comm", "/usr/bin/foo"); log_kv_unsafestring(buf, "args", "--do-this how? --right-now --or-else 'the end of the world'"); log_kv_unsafestring(buf, "msg", "foo=bar cmd=deltree C:\\ user_said='where's my \x99\f\a\a stuff gone?\n'"); log_end(buf); return (0); }