s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

s6_fdholder_setdump.c (2967B)


      1 /* ISC license. */
      2 
      3 #include <sys/uio.h>
      4 #include <stdint.h>
      5 #include <string.h>
      6 #include <errno.h>
      7 
      8 #include <skalibs/uint32.h>
      9 #include <skalibs/allreadwrite.h>
     10 #include <skalibs/bytestr.h>
     11 #include <skalibs/error.h>
     12 #include <skalibs/tai.h>
     13 #include <skalibs/unixmessage.h>
     14 
     15 #include <s6/fdholder.h>
     16 
     17 #include <skalibs/posixishard.h>
     18 
     19 int s6_fdholder_setdump (s6_fdholder_t *a, s6_fdholder_fd_t const *list, unsigned int ntot, tain const *deadline, tain *stamp)
     20 {
     21   uint32_t trips ;
     22   if (!ntot) return 1 ;
     23   unsigned int i = 0 ;
     24   for (; i < ntot ; i++)
     25   {
     26     size_t zpos = byte_chr(list[i].id, S6_FDHOLDER_ID_SIZE + 1, 0) ;
     27     if (!zpos || zpos >= S6_FDHOLDER_ID_SIZE + 1) return (errno = EINVAL, 0) ;
     28   }
     29   {
     30     char pack[5] = "!" ;
     31     unixmessage m = { .s = pack, .len = 5, .fds = 0, .nfds = 0 } ;
     32     uint32_pack_big(pack+1, ntot) ;
     33     if (!unixmessage_put(&a->connection.out, &m)) return 0 ;
     34     if (!unixmessage_sender_timed_flush(&a->connection.out, deadline, stamp)) return 0 ;
     35     if (sanitize_read(unixmessage_timed_receive(&a->connection.in, &m, deadline, stamp)) < 0) return 0 ;
     36     if (!m.len || m.nfds) { unixmessage_drop(&m) ; return (errno = EPROTO, 0) ; }
     37     if (m.s[0]) return (errno = (unsigned char)m.s[0], 0) ;
     38     if (m.len != 5) return (errno = EPROTO, 0) ;
     39     uint32_unpack_big(m.s + 1, &trips) ;
     40     if (trips != 1 + (ntot-1) / UNIXMESSAGE_MAXFDS) return (errno = EPROTO, 0) ;
     41   }
     42   for (i = 0 ; i < trips ; i++, ntot -= UNIXMESSAGE_MAXFDS)
     43   {
     44     {
     45       unsigned int n = ntot > UNIXMESSAGE_MAXFDS ? UNIXMESSAGE_MAXFDS : ntot ;
     46       unsigned int j = 0 ;
     47       struct iovec v[1 + (n<<1)] ;
     48       int fds[n] ;
     49       unixmessagev m = { .v = v, .vlen = 1 + (n<<1), .fds = fds, .nfds = n } ;
     50       char pack[n * (TAIN_PACK+1)] ;
     51       v[0].iov_base = "." ; v[0].iov_len = 1 ;
     52       for (; j < n ; j++, list++, ntot--)
     53       {
     54         size_t len = strlen(list->id) ;
     55         v[1 + (j<<1)].iov_base = pack + j * (TAIN_PACK+1) ;
     56         v[1 + (j<<1)].iov_len = TAIN_PACK + 1 ;
     57         tain_pack(pack + j * (TAIN_PACK+1), &list->limit) ;
     58         pack[j * (TAIN_PACK+1) + TAIN_PACK] = (unsigned char)len ;
     59         v[2 + (j<<1)].iov_base = (char *)list->id ;
     60         v[2 + (j<<1)].iov_len = len + 1 ;
     61         fds[j] = list->fd ;
     62       }
     63       if (!unixmessage_putv(&a->connection.out, &m)) return 0 ;
     64     }
     65     if (!unixmessage_sender_timed_flush(&a->connection.out, deadline, stamp)) return 0 ;
     66     {
     67       unixmessage m ;
     68       if (sanitize_read(unixmessage_timed_receive(&a->connection.in, &m, deadline, stamp)) < 0) return 0 ;
     69       if (m.len != 1 || m.nfds)
     70       {
     71         unixmessage_drop(&m) ;
     72         return (errno = EPROTO, 0) ;
     73       }
     74       if (!error_isagain((unsigned char)m.s[0]) && i < trips-1)
     75         return errno = m.s[0] ? (unsigned char)m.s[0] : EPROTO, 0 ;
     76       if (i == trips - 1 && m.s[0])
     77         return errno = error_isagain((unsigned char)m.s[0]) ? EPROTO : (unsigned char)m.s[0], 0 ;
     78     }
     79   }
     80   return 1 ;
     81 }