summaryrefslogtreecommitdiffstats
path: root/src/util/safe-format-string.h
blob: 2f4796de7cea66d9ff0cd808e9e7c33de053feb8 (plain)
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
/*
 * This file originated in the realmd project
 *
 * Copyright 2013 Red Hat Inc
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2 of the licence or (at
 * your option) any later version.
 *
 * See the included COPYING file for more information.
 *
 * Author: Stef Walter <stefw@redhat.com>
 */

#include "config.h"

#ifndef __SAFE_FORMAT_STRING_H__
#define __SAFE_FORMAT_STRING_H__

#include <stdlib.h>

/*
 * This is a neutered printf variant that can be used with user-provided
 * format strings.
 *
 * Not only are the normal printf functions not safe to use on user-provided
 * input (ie: can crash, be abused, etc), they're also very brittle with
 * regards to positional arguments: one must consume them all or printf will
 * just abort(). This is because arguments of different sizes are accepted
 * in the varargs. So obviously the positional code cannot know the offset
 * of the relevant varargs if some are not consumed (ie: tagged with a
 * field type).
 *
 * Thus the only accepted field type here is 's'. It's all we need.
 *
 * In general new code should use a better syntax than printf format strings
 * for configuration options. This code is here to facilitate robust processing
 * of the full_name_format syntax we already have, which has been documented as
 * "printf(3) compatible".
 *
 * Features:
 * - Only string 's' fields are supported
 * - All the varargs should be strings, followed by a NULL argument
 * - Both positional '%$1s' and non-positional '%s' are supported
 * - Field widths '%8s' work as expected
 * - Precision '%.8s' works, but precision cannot be read from a field
 * - Left alignment flag is supported '%-8s'.
 * - The space flag '% 8s' has no effect (it's the default for string fields).
 * - No more than six digits are supported for widths, precisions, etc.
 * - Percent signs are to be escaped as usual '%%'
 *
 * Use of other flags or field types will cause the relevant printf call to
 * return -1. Using too many arguments or incorrect positional arguments
 * will also cause the call to fail.
 *
 * Functions return -1 on failure and set errno. Otherwise they return
 * the full length of the string that would be formatted, with the same
 * semantics as snprintf().
 */

#ifndef GNUC_NULL_TERMINATED
#if __GNUC__ >= 4
#define GNUC_NULL_TERMINATED __attribute__((__sentinel__))
#else
#define GNUC_NULL_TERMINATED
#endif
#endif

int        safe_format_string    (char *str,
                                  size_t len,
                                  const char *format,
                                  ...) GNUC_NULL_TERMINATED;

int        safe_format_string_cb (void (* callback) (void *data, const char *piece, size_t len),
                                  void *data,
                                  const char *format,
                                  const char * const args[],
                                  int num_args);

#endif /* __SAFE_FORMAT_STRING_H__ */