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 135 136 137 138 139 140 141 142 143 144 145 146
|
/*
* Helper functions for systemd generators in nfs-utils.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.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;
}
/*
* check if the system is running in the initrd, following the same logic as
* systemd, described in os-release(5):
*
* In the initrd[2] and exitrd, /etc/initrd-release plays the same role as
* os-release in the main system. Additionally, the presence of that file
* means that the system is in the initrd/exitrd phase.
*/
int systemd_in_initrd(void)
{
return (access("/etc/initrd-release", F_OK) >= 0);
}
|