/* * Helper functions for systemd generators in nfs-utils. * * Currently just systemd_escape(). */ #include #include #include #include #include "systemd.h" static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', }; /* * determine length of the string that systemd_escape() needs to allocate */ static int systemd_len(char *path) { char *p; int len = 0; p = path; while (*p == '/') /* multiple leading "/" are ignored */ p++; if (!*p) /* root directory "/" becomes is encoded as a single "-" */ return 1; if (*p == '.') /* * replace "." with "\x2d" escape sequence if * it's the first character in escaped path * */ len += 4; while (*p) { unsigned char c = *p++; if (c == '/') { /* multiple non-trailing slashes become '-' */ while (*p == '/') p++; if (*p) len++; } else if (isalnum(c) || c == ':' || c == '.' || c == '_') /* these characters are not replaced */ len++; else /* replace with "\x2d" escape sequence */ len += 4; } return len; } /* * convert c to "\x2d" escape sequence and append to string * at position p, advancing p */ static char *hexify(unsigned char c, char *p) { *p++ = '\\'; *p++ = 'x'; *p++ = hex[c >> 4]; *p++ = hex[c & 0xf]; return p; } /* * convert a path to a unit name according to the logic in systemd.unit(5): * * Basically, given a path, "/" is replaced by "-", and all other * characters which are not ASCII alphanumerics are replaced by C-style * "\x2d" escapes (except that "_" is never replaced and "." is only * replaced when it would be the first character in the escaped path). * The root directory "/" is encoded as single dash, while otherwise the * initial and ending "/" are removed from all paths during * transformation. * * NB: Although the systemd.unit(5) doesn't mention it, the ':' character * is not escaped. */ char *systemd_escape(char *path, char *suffix) { char *result; char *p; int len; len = systemd_len(path); result = malloc(len + strlen(suffix) + 1); p = result; while (*path == '/') /* multiple leading "/" are ignored */ path++; if (!*path) { /* root directory "/" becomes is encoded as a single "-" */ *p++ = '-'; goto out; } if (*path == '.') /* * replace "." with "\x2d" escape sequence if * it's the first character in escaped path * */ p = hexify(*path++, p); while (*path) { unsigned char c = *path++; if (c == '/') { /* multiple non-trailing slashes become '-' */ while (*path == '/') path++; if (*path) *p++ = '-'; } else if (isalnum(c) || c == ':' || c == '.' || c == '_') /* these characters are not replaced */ *p++ = c; else /* replace with "\x2d" escape sequence */ p = hexify(c, p); } out: sprintf(p, "%s", suffix); return result; }