2 Copyright (C) 2010 Proxmox Server Solutions GmbH
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
23 #endif /* HAVE_CONFIG_H */
30 #include <sys/types.h>
36 #include "cfs-utils.h"
38 static const char * hexchar
= "0123456789abcdef";
40 /* convert utf8 to json and syslog compatible ascii */
48 g_return_if_fail(buf
!= NULL
);
52 g_return_if_fail(bufsize
> 10);
56 char *end
= buf
+ bufsize
- 7;
58 if (!g_utf8_validate(msg
, -1, NULL
)) {
59 while (*p
&& d
< end
) {
61 if (c
== 34 && quotequote
) {
64 } else if (c
>= 0 && c
< 32) {
67 *(d
+1) = hexchar
[c
% 10]; c
= c
/ 10;
70 } else if (c
>= 32 && c
< 127) {
80 while (*p
&& d
< end
) {
81 gunichar u
= g_utf8_get_char(p
);
82 if (u
== 34 && quotequote
) {
85 } else if (u
< 32 || u
== 127) {
87 *(d
+2) = hexchar
[u
% 10]; u
= u
/ 10;
88 *(d
+1) = hexchar
[u
% 10]; u
= u
/ 10;
93 } else if (u
< 65536) {
96 *(d
+3) = hexchar
[u
&0xf]; u
= u
>> 4;
97 *(d
+2) = hexchar
[u
&0xf]; u
= u
>> 4;
98 *(d
+1) = hexchar
[u
&0xf]; u
= u
>> 4;
102 /* we simply ignore this */
104 p
= g_utf8_next_char(p
);
111 const gchar
*log_domain
,
112 GLogLevelFlags log_level
,
122 switch (log_level
& G_LOG_LEVEL_MASK
) {
123 case G_LOG_LEVEL_ERROR
:
127 case G_LOG_LEVEL_CRITICAL
:
131 case G_LOG_LEVEL_WARNING
:
135 case G_LOG_LEVEL_MESSAGE
:
139 case G_LOG_LEVEL_INFO
:
143 case G_LOG_LEVEL_DEBUG
:
156 va_start (args
, format
);
157 char *orgmsg
= g_strdup_vprintf (format
, args
);
161 utf8_to_ascii(msg
, sizeof(msg
), orgmsg
, FALSE
);
163 uint32_t tag
= g_quark_from_string(log_domain
);
165 qb_log_from_external_source(func
, file
, "%s", level
, line
, tag
, msg
);
170 // xml parser for cluster.conf - just good enough to extract version
178 parser_start_element (
179 GMarkupParseContext
*context
,
180 const gchar
*element_name
,
181 const gchar
**attribute_names
,
182 const gchar
**attribute_values
,
186 PVEClusterConfig
*data
= user_data
;
188 if (!data
->version
&& !strcmp(element_name
, "cluster")) {
189 const char **n
= attribute_names
;
190 const char **v
= attribute_values
;
192 while (n
&& v
&& *n
) {
193 if (!strcmp(*n
, "config_version")) {
195 guint64 ver
= strtoull(*v
, &e
, 10);
205 static GMarkupParser cluster_conf_parser
= {
206 .start_element
= parser_start_element
210 cluster_config_version(
211 const gpointer config_data
,
214 GMarkupParseContext
*ctx
;
218 PVEClusterConfig cfg
= { .version
= 0 };
219 if (!(ctx
= g_markup_parse_context_new(&cluster_conf_parser
, 0, &cfg
, NULL
))) {
220 cfs_critical("g_markup_parse_context_new failed");
224 if (!g_markup_parse_context_parse(ctx
, config_data
, config_length
, &err
)) {
225 cfs_critical("unable to parse cluster config - %s", err
->message
);
227 g_markup_parse_context_free(ctx
);
231 if (!g_markup_parse_context_end_parse(ctx
, &err
)) {
232 cfs_critical("unable to parse cluster config - %s", err
->message
);
234 g_markup_parse_context_free(ctx
);
238 g_markup_parse_context_free(ctx
);
251 n
= read(fd
, buf
, count
);
252 } while (n
< 0 && errno
== EINTR
);
270 n
= write(fd
, buf
, len
);
271 } while (n
< 0 && errno
== EINTR
);
286 const char *filename
,
292 g_return_val_if_fail(filename
!= NULL
, FALSE
);
293 g_return_val_if_fail(len
== 0 || data
!= NULL
, FALSE
);
297 char *tmp_name
= g_strdup_printf ("%s.XXXXXX", filename
);
298 int fd
= mkstemp(tmp_name
);
300 cfs_critical("Failed to create file '%s': %s", tmp_name
, g_strerror(errno
));
305 if (fchown(fd
, 0, gid
) == -1) {
306 cfs_critical("Failed to change group of file '%s': %s", tmp_name
, g_strerror(errno
));
311 if (fchmod(fd
, mode
) == -1) {
312 cfs_critical("Failed to change mode of file '%s': %s", tmp_name
, g_strerror(errno
));
317 if (len
&& !full_write(fd
, data
, len
)) {
318 cfs_critical("Failed to write file '%s': %s", tmp_name
, g_strerror(errno
));
323 if (close(fd
) == -1) {
324 cfs_critical("Failed to close file '%s': %s", tmp_name
, g_strerror(errno
));
328 if (rename(tmp_name
, filename
) == -1) {
329 cfs_critical("Failed to rename file from '%s' to '%s': %s",
330 tmp_name
, filename
, g_strerror(errno
));
347 path_is_private(const char *path
)
349 while (*path
== '/') path
++;
351 if ((strncmp(path
, "priv", 4) == 0) && (path
[4] == 0 || path
[4] == '/')) {
354 if (strncmp(path
, "nodes/", 6) == 0) {
355 const char *tmp
= path
+ 6;
356 while(*tmp
&& *tmp
!= '/') tmp
++;
358 (strncmp(tmp
, "/priv", 5) == 0) &&
359 (tmp
[5] == 0 || tmp
[5] == '/')) {
368 path_is_lockdir(const char *path
)
370 while (*path
== '/') path
++;
372 return (strncmp(path
, "priv/lock/", 10) == 0) && (strlen(path
) > 10);