aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs6/s6_supervise_lock_mode.c
blob: b6b0829a7080318ec89c3d91687a9f4ae1b9d56c (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
/* ISC license. */

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

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

#include <s6/s6-supervise.h>

#ifdef PATH_MAX
# define S6_PATH_MAX PATH_MAX
#else
# define S6_PATH_MAX 4096
#endif

int s6_supervise_lock_mode (char const *subdir, unsigned int subdirmode, unsigned int controlmode)
{
  size_t subdirlen = strlen(subdir) ;
  int fdctl, fdctlw, fdlock ;
  char control[subdirlen + 9] ;
  char lock[subdirlen + 6] ;
  memcpy(control, subdir, subdirlen) ;
  memcpy(control + subdirlen, "/control", 9) ;
  memcpy(lock, subdir, subdirlen) ;
  memcpy(lock + subdirlen, "/lock", 6) ;
  if (mkdir(subdir, (mode_t)subdirmode) == -1)
  {
    if (errno != EEXIST) strerr_diefu2sys(111, "mkdir ", subdir) ;
    else
    {
      char buf[S6_PATH_MAX] ;
      ssize_t r = readlink(subdir, buf, S6_PATH_MAX) ;
      if (r < 0)
      {
        errno = EEXIST ;
        strerr_diefu2sys(111, "mkdir ", subdir) ;
      }
      if (r == S6_PATH_MAX)
      {
        errno = ENAMETOOLONG ;
        strerr_diefu2sys(111, "readlink ", subdir) ;
      }
      buf[r] = 0 ;
      if (mkdir(buf, (mode_t)subdirmode) == -1)
        strerr_diefu2sys(111, "mkdir ", buf) ;
    }
  }
  if (mkfifo(control, controlmode) < 0)
  {
    struct stat st ;
    if (errno != EEXIST)
      strerr_diefu2sys(111, "mkfifo ", control) ;
    if (stat(control, &st) < 0)
      strerr_diefu2sys(111, "stat ", control) ;
    if (!S_ISFIFO(st.st_mode))
      strerr_diefu2x(100, control, " is not a FIFO") ;
  }
  fdlock = openc_create(lock) ;
  if (fdlock < 0)
    strerr_diefu2sys(111, "open_create ", lock) ;
  if (lock_ex(fdlock) < 0)
    strerr_diefu2sys(111, "lock ", lock) ;
  fdctlw = openc_write(control) ;
  if (fdctlw >= 0) strerr_dief1x(100, "directory already locked") ;
  if (errno != ENXIO)
    strerr_diefu2sys(111, "open_write ", control) ;
  fdctl = openc_read(control) ;
  if (fdctl < 0)
    strerr_diefu2sys(111, "open_read ", control) ;
  fdctlw = openc_write(control) ;
  if (fdctlw < 0)
    strerr_diefu2sys(111, "open_write ", control) ;
  fd_close(fdlock) ;

  return fdctl ;
  /* we leak fdctlw but it's coe. */
}