blob: c7bdb4d28bb9037a6fe0ad9f0955dc25bab743ad [file] [log] [blame]
/*
* Helper functions for systemd generators in nfs-utils.
*
* Currently just systemd_escape().
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#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;
}