1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
/*
* 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;
}
|