diff options
Diffstat (limited to 'libreport/src/lib/get_cmdline.c')
-rw-r--r-- | libreport/src/lib/get_cmdline.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/libreport/src/lib/get_cmdline.c b/libreport/src/lib/get_cmdline.c new file mode 100644 index 00000000..04254660 --- /dev/null +++ b/libreport/src/lib/get_cmdline.c @@ -0,0 +1,150 @@ +/* + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "libreport.h" + +/* If s is a string with only printable ASCII chars + * and has no spaces, ", ', and \, copy it verbatim. + * Else, encapsulate it in single quotes, and + * encode ', " and \ with \c escapes. + * Control chars are encoded as \r, \n, \t, or \xNN. + * In all cases, terminating NUL is added + * and the pointer to it is returned. + */ +static char *append_escaped(char *start, const char *s) +{ + char *dst = start; + const unsigned char *p = (unsigned char *)s; + + while (1) + { + const unsigned char *old_p = p; + while (*p > ' ' && *p <= 0x7e && *p != '\"' && *p != '\'' && *p != '\\') + p++; + if (dst == start) + { + if (p != (unsigned char *)s && *p == '\0') + { + /* entire word does not need escaping and quoting */ + strcpy(dst, s); + dst += strlen(s); + return dst; + } + *dst++ = '\''; + } + + strncpy(dst, (char *)old_p, (p - old_p)); + dst += (p - old_p); + + if (*p == '\0') + { + *dst++ = '\''; + *dst = '\0'; + return dst; + } + + char hex_char_buf[5]; + const char *a; + switch (*p) + { + case '\r': a = "\\r"; break; + case '\n': a = "\\n"; break; + case '\t': a = "\\t"; break; + case '\'': a = "\\\'"; break; + case '\"': a = "\\\""; break; + case '\\': a = "\\\\"; break; + case ' ': a = " "; break; + default: + /* Build \xNN string */ + hex_char_buf[0] = '\\'; + hex_char_buf[1] = 'x'; + hex_char_buf[2] = "0123456789abcdef"[*p >> 4]; + hex_char_buf[3] = "0123456789abcdef"[*p & 0xf]; + hex_char_buf[4] = '\0'; + a = hex_char_buf; + } + strcpy(dst, a); + dst += strlen(a); + p++; + } +} + +static char* get_escaped(const char *path, char separator) +{ + char *escaped = NULL; + + int fd = open(path, O_RDONLY); + if (fd >= 0) + { + char *dst = NULL; + unsigned total_esc_len = 0; + while (total_esc_len < 1024 * 1024) /* paranoia check */ + { + /* read and escape one block */ + char buffer[4 * 1024 + 1]; + int len = read(fd, buffer, sizeof(buffer) - 1); + if (len <= 0) + break; + buffer[len] = '\0'; + + /* string CC can expand into '\xNN\xNN' and thus needs len*4 + 3 bytes, + * including terminating NUL. + * We add +1 for possible \n added at the very end. + */ + escaped = xrealloc(escaped, total_esc_len + len*4 + 4); + char *src = buffer; + dst = escaped + total_esc_len; + while (1) + { + /* escape till next NUL char */ + char *d = append_escaped(dst, src); + total_esc_len += (d - dst); + dst = d; + src += strlen(src) + 1; + if ((src - buffer) >= len) + break; + *dst++ = separator; + } + + } + + if (dst) + { + if (separator == '\n') + *dst++ = separator; + *dst = '\0'; + } + + close(fd); + } + + return escaped; +} + +char* get_cmdline(pid_t pid) +{ + char path[sizeof("/proc/%lu/cmdline") + sizeof(long)*3]; + sprintf(path, "/proc/%lu/cmdline", (long)pid); + return get_escaped(path, ' '); +} + +char* get_environ(pid_t pid) +{ + char path[sizeof("/proc/%lu/environ") + sizeof(long)*3]; + sprintf(path, "/proc/%lu/environ", (long)pid); + return get_escaped(path, '\n'); +} |