LCOV - code coverage report
Current view: top level - shared - serialize.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 88 114 77.2 %
Date: 2019-08-22 15:41:25 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <sys/mman.h>
       4             : 
       5             : #include "alloc-util.h"
       6             : #include "env-util.h"
       7             : #include "escape.h"
       8             : #include "fileio.h"
       9             : #include "missing.h"
      10             : #include "parse-util.h"
      11             : #include "process-util.h"
      12             : #include "serialize.h"
      13             : #include "strv.h"
      14             : #include "tmpfile-util.h"
      15             : 
      16          27 : int serialize_item(FILE *f, const char *key, const char *value) {
      17          27 :         assert(f);
      18          27 :         assert(key);
      19             : 
      20          27 :         if (!value)
      21           1 :                 return 0;
      22             : 
      23             :         /* Make sure that anything we serialize we can also read back again with read_line() with a maximum line size
      24             :          * of LONG_LINE_MAX. This is a safety net only. All code calling us should filter this out earlier anyway. */
      25          26 :         if (strlen(key) + 1 + strlen(value) + 1 > LONG_LINE_MAX) {
      26           7 :                 log_warning("Attempted to serialize overly long item '%s', refusing.", key);
      27           7 :                 return -EINVAL;
      28             :         }
      29             : 
      30          19 :         fputs(key, f);
      31          19 :         fputc('=', f);
      32          19 :         fputs(value, f);
      33          19 :         fputc('\n', f);
      34             : 
      35          19 :         return 1;
      36             : }
      37             : 
      38          22 : int serialize_item_escaped(FILE *f, const char *key, const char *value) {
      39          22 :         _cleanup_free_ char *c = NULL;
      40             : 
      41          22 :         assert(f);
      42          22 :         assert(key);
      43             : 
      44          22 :         if (!value)
      45           1 :                 return 0;
      46             : 
      47          21 :         c = cescape(value);
      48          21 :         if (!c)
      49           0 :                 return log_oom();
      50             : 
      51          21 :         return serialize_item(f, key, c);
      52             : }
      53             : 
      54           2 : int serialize_item_format(FILE *f, const char *key, const char *format, ...) {
      55             :         char buf[LONG_LINE_MAX];
      56             :         va_list ap;
      57             :         int k;
      58             : 
      59           2 :         assert(f);
      60           2 :         assert(key);
      61           2 :         assert(format);
      62             : 
      63           2 :         va_start(ap, format);
      64           2 :         k = vsnprintf(buf, sizeof(buf), format, ap);
      65           2 :         va_end(ap);
      66             : 
      67           2 :         if (k < 0 || (size_t) k >= sizeof(buf) || strlen(key) + 1 + k + 1 > LONG_LINE_MAX) {
      68           0 :                 log_warning("Attempted to serialize overly long item '%s', refusing.", key);
      69           0 :                 return -EINVAL;
      70             :         }
      71             : 
      72           2 :         fputs(key, f);
      73           2 :         fputc('=', f);
      74           2 :         fputs(buf, f);
      75           2 :         fputc('\n', f);
      76             : 
      77           2 :         return 1;
      78             : }
      79             : 
      80           0 : int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd) {
      81             :         int copy;
      82             : 
      83           0 :         assert(f);
      84           0 :         assert(key);
      85             : 
      86           0 :         if (fd < 0)
      87           0 :                 return 0;
      88             : 
      89           0 :         copy = fdset_put_dup(fds, fd);
      90           0 :         if (copy < 0)
      91           0 :                 return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
      92             : 
      93           0 :         return serialize_item_format(f, key, "%i", copy);
      94             : }
      95             : 
      96           3 : int serialize_usec(FILE *f, const char *key, usec_t usec) {
      97           3 :         assert(f);
      98           3 :         assert(key);
      99             : 
     100           3 :         if (usec == USEC_INFINITY)
     101           1 :                 return 0;
     102             : 
     103           2 :         return serialize_item_format(f, key, USEC_FMT, usec);
     104             : }
     105             : 
     106           0 : int serialize_dual_timestamp(FILE *f, const char *name, const dual_timestamp *t) {
     107           0 :         assert(f);
     108           0 :         assert(name);
     109           0 :         assert(t);
     110             : 
     111           0 :         if (!dual_timestamp_is_set(t))
     112           0 :                 return 0;
     113             : 
     114           0 :         return serialize_item_format(f, name, USEC_FMT " " USEC_FMT, t->realtime, t->monotonic);
     115             : }
     116             : 
     117           5 : int serialize_strv(FILE *f, const char *key, char **l) {
     118           5 :         int ret = 0, r;
     119             :         char **i;
     120             : 
     121             :         /* Returns the first error, or positive if anything was serialized, 0 otherwise. */
     122             : 
     123          21 :         STRV_FOREACH(i, l) {
     124          16 :                 r = serialize_item_escaped(f, key, *i);
     125          16 :                 if ((ret >= 0 && r < 0) ||
     126           2 :                     (ret == 0 && r > 0))
     127           3 :                         ret = r;
     128             :         }
     129             : 
     130           5 :         return ret;
     131             : }
     132             : 
     133           2 : int deserialize_usec(const char *value, usec_t *ret) {
     134             :         int r;
     135             : 
     136           2 :         assert(value);
     137             : 
     138           2 :         r = safe_atou64(value, ret);
     139           2 :         if (r < 0)
     140           0 :                 return log_debug_errno(r, "Failed to parse usec value \"%s\": %m", value);
     141             : 
     142           2 :         return 0;
     143             : }
     144             : 
     145           7 : int deserialize_dual_timestamp(const char *value, dual_timestamp *t) {
     146             :         uint64_t a, b;
     147             :         int r, pos;
     148             : 
     149           7 :         assert(value);
     150           7 :         assert(t);
     151             : 
     152           7 :         pos = strspn(value, WHITESPACE);
     153           7 :         if (value[pos] == '-')
     154           1 :                 return -EINVAL;
     155           6 :         pos += strspn(value + pos, DIGITS);
     156           6 :         pos += strspn(value + pos, WHITESPACE);
     157           6 :         if (value[pos] == '-')
     158           1 :                 return -EINVAL;
     159             : 
     160           5 :         r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
     161           5 :         if (r != 2)
     162           1 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     163             :                                        "Failed to parse dual timestamp value \"%s\".",
     164             :                                        value);
     165             : 
     166           4 :         if (value[pos] != '\0')
     167             :                 /* trailing garbage */
     168           1 :                 return -EINVAL;
     169             : 
     170           3 :         t->realtime = a;
     171           3 :         t->monotonic = b;
     172             : 
     173           3 :         return 0;
     174             : }
     175             : 
     176          17 : int deserialize_environment(const char *value, char ***list) {
     177          17 :         _cleanup_free_ char *unescaped = NULL;
     178             :         int r;
     179             : 
     180          17 :         assert(value);
     181          17 :         assert(list);
     182             : 
     183             :         /* Changes the *environment strv inline. */
     184             : 
     185          17 :         r = cunescape(value, 0, &unescaped);
     186          17 :         if (r < 0)
     187           2 :                 return log_error_errno(r, "Failed to unescape: %m");
     188             : 
     189          15 :         r = strv_env_replace(list, unescaped);
     190          15 :         if (r < 0)
     191           0 :                 return log_error_errno(r, "Failed to append environment variable: %m");
     192             : 
     193          15 :         unescaped = NULL; /* now part of 'list' */
     194          15 :         return 0;
     195             : }
     196             : 
     197          22 : int open_serialization_fd(const char *ident) {
     198             :         int fd;
     199             : 
     200          22 :         fd = memfd_create(ident, MFD_CLOEXEC);
     201          22 :         if (fd < 0) {
     202             :                 const char *path;
     203             : 
     204           0 :                 path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
     205           0 :                 fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
     206           0 :                 if (fd < 0)
     207           0 :                         return fd;
     208             : 
     209           0 :                 log_debug("Serializing %s to %s.", ident, path);
     210             :         } else
     211          22 :                 log_debug("Serializing %s to memfd.", ident);
     212             : 
     213          22 :         return fd;
     214             : }

Generated by: LCOV version 1.14