Last active
January 19, 2022 04:32
-
-
Save ilyakurdyukov/db5e81b87a7be5ac38813104c111799f to your computer and use it in GitHub Desktop.
Helper function for escaping special characters from user-provided strings to be used in calls to system().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SAFESYS_H | |
#define SAFESYS_H | |
#include <stdlib.h> | |
#include <stdarg.h> | |
#ifndef SAFESYS_NOMEM | |
#include <errno.h> | |
#define SAFESYS_NOMEM ENOMEM | |
#endif | |
static int safesys(const char *format, ...) { | |
va_list va; size_t size = 0; | |
const char *next, *p, *f, *esc; | |
char *d, *cmd, c; int ret, nquot; | |
esc = "\t\n\r !\"#$&()*;<=>?[\\]^`{|}~"; | |
va_start(va, format); | |
f = format; | |
while ((c = *f++)) if (c == '%') { | |
p = next = va_arg(va, const char*); | |
nquot = 0; | |
while ((c = *p++)) | |
nquot = c == '\'' ? | |
size += nquot > 1 ? 3 : nquot + 1, 0 : | |
nquot + !!strchr(esc, c); | |
size += (nquot > 1 ? 2 : nquot) + (p - next) - 2; | |
} | |
va_end(va); | |
size += f - format; | |
cmd = malloc(size); | |
if (!cmd) return SAFESYS_NOMEM; | |
#define SAFESYS_COPY \ | |
if (nquot > 1) *d++ = '\''; \ | |
while (next < p - 1) { \ | |
c = *next++; \ | |
if (nquot == 1 && strchr(esc, c)) \ | |
*d++ = '\\', nquot = 0; \ | |
*d++ = c; \ | |
} \ | |
if (nquot > 1) *d++ = '\''; | |
d = cmd; | |
va_start(va, format); | |
f = format; | |
while ((c = *f++)) | |
if (c != '%') *d++ = c; | |
else { | |
p = next = va_arg(va, const char*); | |
nquot = 0; | |
while ((c = *p++)) | |
if (c == '\'') { | |
SAFESYS_COPY | |
nquot = 0; next++; | |
*d++ = '\\'; *d++ = '\''; | |
} else nquot += !!strchr(esc, c); | |
SAFESYS_COPY | |
} | |
va_end(va); | |
*d = 0; | |
puts(cmd); | |
ret = system(cmd); | |
free(cmd); | |
return ret; | |
} | |
#endif // SAFESYS_H |
@lcn2
It's written as a concept because you'll rewrite it anyway.
But there is a working code for escaping single quotes that suits the needs of mkiocccentry.
cd ~/tmp && wc -l -- __unsafe_arg__
is done like this:
safesys("cd ~/tmp && wc -l -- %", __unsafe_arg__);
mkiocccentry does not require double quotes escaping, because if one wants to use $FOO on the command line to invoke mkiocccentry, those variables will be expanded by the shell before mkiocccentry is run.
You might wish to have the code simply return a malloced string that is "safe" and let the caller pass it to system() or popen()
This can be done very simply:
-static int safesys(const char *format, ...) {
+static char* cmdprintf(const char *format, ...) {
- if (!cmd) return SAFESYS_NOMEM;
+ if (!cmd) return cmd;
- puts(cmd);
- ret = system(cmd);
- free(cmd);
- return ret;
+ return cmd;
I just want to keep system() in this gist as an example.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Minor suggestion:
You might wish to split the code into a safesys.c and a safesys.h to make is easier to link with and to make is less awkward other code to use in more than one .c file.
Again this code is an excellent concept that is, I believe, worthy of refinement.