summaryrefslogtreecommitdiff
path: root/src/server/livedir_init.c
blob: f252dba90c78faaf1997657b0ef2c4682582b76c (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* ISC license. */

#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/stat.h>

#include <skalibs/strerr2.h>
#include <skalibs/djbunix.h>
#include <skalibs/webipc.h>

#include "s6rcd.h"

#ifdef NAME_MAX
# define S6RC_NAME_MAX NAME_MAX
#else
# define S6RC_NAME_MAX 63
#endif

static inline int mksubdirs (char *s)
{
  size_t n = strlen(s) ;
  size_t i = 0 ;
  for (; i < n ; i++)
  {
    if (s[i] == '/')
    {
      int r ;
      s[i] = 0 ;
      r = mkdir(s, 0755) ;
      s[i] = '/' ;
      if (r < 0 && errno != EEXIST) break ;
    }
  }
  return i >= n ;
}

int s6rcd_livedir_init (char const *livedir, char const *scandir, char const *prefix, char const *compiled, int *sock)
{
  size_t plen = strlen(prefix) ;
  size_t llen = strlen(livedir) ;
  struct stat st ;
  char ltmp[llen + 9] ;
  if (plen >= S6RC_NAME_MAX)
    strerr_dief1x(100, "prefix is too long") ;

  memcpy(ltmp, livedir, llen + 1) ;
  if (!mksubdirs(ltmp, len))
    strerr_diefu2sys(111, "create subdirectories of ", s) ;
  if (mkdir(ltmp, 0755) < 0 && errno != EEXIST)
    strerr_diefu2sys(111, "mkdir ", ltmp) ;

  memcpy(ltmp + llen, "/s", 3) ;
  *sock = ipc_stream() ;
  if (*sock < 0)
    strerr_diefu1sys(111, "create socket") ;
  if (ipc_bind_reuse(*sock, ltmp) < 0)
    strerr_diefu2sys(111, "bind to ", ltmp) ;

  memcpy(ltmp + llen + 1, "scandir", 8) ;
  if (lstat(ltmp, &st) < 0)
  {
    if (errno != ENOENT)
      strerr_diefu2sys(111, "lstat ", ltmp) ;
    if (symlink(scandir, ltmp) < 0)
      strerr_diefu4sys(111, "symlink ", ltmp, " to ", scandir) ;
  }
  else
  {
    size_t slen = strlen(scandir) ;
    char stmp[slen + 1] ;
    if (!S_ISLNK(st.st_mode))
      strerr_dief3x(100, "file ", ltmp, " exists and is not a symbolic link") ;
    if (readlink(ltmp, stmp, slen + 1) < 0)
      strerr_diefu2sys(111, "readlink ", ltmp) ;
    if (strncmp(scandir, stmp, slen + 1))
      strerr_dief4x(100, "provided scandir ", scandir, " does not match the contents of existing ", ltmp) ;
  }

  memcpy(ltmp + llen + 1, "prefix", 7) ;
  if (stat(ltmp, &st) < 0)
  {
    if (errno != ENOENT)
      strerr_diefu2sys(111, "stat ", ltmp) ;
    if (!openwritenclose_unsafe(ltmp, prefix, strlen(prefix)))
      strerr_diefu2sys(111, "write prefix to ", ltmp) ;
  }
  else
  {
    if (!S_IFREG(st.st_mode))
      strerr_dief3x(100, "file ", ltmp, " exists and is not a regular file") ;
    if (st.st_size != plen)
      strerr_dief4x(100, "provided prefix ", prefix, " does not match the contents of existing ", ltmp) ;
    {
      char stmp[plen] ;
      ssize_t r = openreadnclose(ltmp, ptmp, plen) ;
      if (r != plen)
        strerr_diefu2sys(111, "read ", ltmp) ;
      if (memcmp(ptmp, prefix, plen))
      strerr_dief4x(100, "provided prefix ", prefix, " does not match the contents of existing ", ltmp) ;
    }
  }

  memcpy(ltmp + llen + 1, "live", 5) ;
  if (lstat(ltmp, &st) < 0)
  {
    char name[12] ;
    if (errno != ENOENT) strerr_diefu2sys(111, "lstat ", ltmp) ;
    if (!s6rcd_livesubdir_create(name, live, compiled))
      strerr_diefu2sys(111, "create live subdirectory in ", live) ;
    if (symlink(name, ltmp) < 0)
      strerr_diefu4sys(111, "symlink ", ltmp, " to ", name) ;
    return 0 ;
  }
  if (!S_ISLNK(st.st_mode))
    strerr_dief3x(100, "livesubdir ", ltmp, " exists and is not a symbolic link") ;
  if (stat(ltmp, &st) < 0)
    strerr_diefu2sys(111, "stat ", ltmp) ;
  if (!S_ISDIR(st.st_mode))
    strerr_dief4x(100, "livesubdir ", ltmp, " exists and is not a symbolic link", " to a directory") ;
  return 1 ;
}