summary refs log tree commit diff
path: root/src/runsvchdir.c
blob: fb83645b182266544e41d2e412eceeb5ee603ee7 (plain) (blame)
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
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include "strerr.h"
#include "error.h"
#include "buffer.h"

#define USAGE " dir"
#define SVDIR "/etc/runit/runsvdir"

#define VERSION "$Id"

char *progname;
char *new;

void usage () { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); }

void fatal(char *m1, char *m2) {
  strerr_die5sys(111, progname, ": fatal: ", m1, m2, ": ");
}
void fatalx(char *m1, char *m2) {
  strerr_die4x(111, progname, ": fatal: ", m1, m2);
}
void warn(char *m1, char *m2) {
  strerr_warn5(progname, ": fatal: ", m1, m2, ": ", &strerr_sys);
}

int main (int argc, char **argv) {
  struct stat s;
  int dev;
  int ino;

  progname =*argv++;
  if (! argv || ! *argv) usage();

  new =*argv;
  if (new[0] == '.') fatalx(new, ": must not start with a dot.");
  if (chdir(SVDIR) == -1) fatal("unable to chdir: ", SVDIR);

  if (stat(new, &s) == -1) {
    if (errno == error_noent) fatal(new, 0);
    fatal("unable to stat: ", new);
  }
  if (! S_ISDIR(s.st_mode)) fatalx(new, "not a directory.");
  ino =s.st_ino;
  dev =s.st_dev;
  if (stat("current", &s) == -1) fatal("unable to stat: ", "current");
  if ((s.st_ino == ino) && (s.st_dev == dev)) {
    buffer_puts(buffer_1, "runsvchdir: ");
    buffer_puts(buffer_1, new);
    buffer_puts(buffer_1, ": current.\n");
    buffer_flush(buffer_1);
    _exit(0);
  }

  if (unlink("current.new") == -1)
    if (errno != error_noent) fatal("unable to unlink: ", "current.new");
  if (symlink(new, "current.new") == -1)
    fatal("unable to create: current.new -> ", new);
  if (unlink("previous") == -1)
    if (errno != error_noent) fatal("unable to unlink: ", "previous");
  if (rename("current", "previous") == -1)
    fatal("unable to copy: current to ", "previous");
  if (rename("current.new", "current") == -1) {
    warn("unable to move: current.new to ", "current");
    if (rename("previous", "current") == -1)
      fatal("unable to move previous back to ", "current");
    _exit(111);
  }
  buffer_puts(buffer_1, "runsvchdir: ");
  buffer_puts(buffer_1, new);
  buffer_puts(buffer_1, ": now current.\n");
  buffer_flush(buffer_1);
  _exit(0);
}