summaryrefslogtreecommitdiff
path: root/src/mdevd/mdevd_uevent_read.c
blob: 2f318929092ea174e18a7b3700164945b5d147ff (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
82
83
84
85
86
87
/* ISC license. */

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <errno.h>
#include <string.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <linux/netlink.h>

#include <skalibs/types.h>
#include <skalibs/allreadwrite.h>
#include <skalibs/strerr2.h>

#include "mdevd-internal.h"

static inline ssize_t fd_recvmsg (int fd, struct msghdr *hdr)
{
  ssize_t r ;
  do r = recvmsg(fd, hdr, 0) ;
  while ((r == -1) && (errno == EINTR)) ;
  return r ;
}

static inline size_t netlink_read (int fd, char *s, uint32_t options, unsigned int verbosity)
{
  struct sockaddr_nl nl;
  struct iovec v = { .iov_base = s, .iov_len = UEVENT_MAX_SIZE } ;
  struct msghdr msg =
  {
    .msg_name = &nl,
    .msg_namelen = sizeof(struct sockaddr_nl),
    .msg_iov = &v,
    .msg_iovlen = 1,
    .msg_control = 0,
    .msg_controllen = 0,
    .msg_flags = 0
  } ;
  ssize_t r = sanitize_read(fd_recvmsg(fd, &msg)) ;
  if (r < 0)
    strerr_diefu1sys(111, "receive netlink message") ;
  if (!r) return 0 ;
  if (msg.msg_flags & MSG_TRUNC)
    strerr_diefu1x(111, "buffer too small for netlink message") ;
  if (options & 1 && nl.nl_pid)
  {
    if (verbosity >= 3)
    {
      char fmt[PID_FMT] ;
      fmt[pid_fmt(fmt, nl.nl_pid)] = 0 ;
      strerr_warnw2x("received netlink message from userspace process ", fmt) ;
    }
    return 0 ;
  }
  if (s[r-1])
  {
    if (verbosity) strerr_warnw2x("received invalid event: ", "improperly terminated") ;
    return 0 ;
  }
  if (!strstr(s, "@/"))
  {
    if (verbosity) strerr_warnw2x("received invalid event: ", "bad initial summary") ;
    return 0 ;
  }
  return r ;
}

int mdevd_uevent_read (int fd, struct uevent_s *event, uint32_t options, unsigned int verbosity)
{
  unsigned short len = 0 ;
  event->len = netlink_read(fd, event->buf, options, verbosity) ;
  if (!event->len) return 0 ;
  event->varn = 0 ;
  while (len < event->len)
  {
    if (event->varn >= UEVENT_MAX_VARS)
    {
      if (verbosity) strerr_warnw2x("received invalid event: ", "too many variables") ;
      return 0 ;
    }
    event->vars[event->varn++] = len ;
    len += strlen(event->buf + len) + 1 ;
  }
  return 1 ;
}