File: systemd.c

package info (click to toggle)
nfs-utils 1%3A2.8.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,380 kB
  • sloc: ansic: 52,371; sh: 5,775; python: 2,166; makefile: 973
file content (146 lines) | stat: -rw-r--r-- 3,329 bytes parent folder | download
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);
}