1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 #include "strerr.h"
6 #include "error.h"
7 #include "buffer.h"
8 #include "runit.local.h"
9 
10 #define USAGE " dir"
11 #define SVDIR RUNITDIR "/runsvdir"
12 
13 
14 char *progname;
15 char *new;
16 
usage()17 void usage () { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); }
18 
fatal(char * m1,char * m2)19 void fatal(char *m1, char *m2) {
20   strerr_die5sys(111, progname, ": fatal: ", m1, m2, ": ");
21 }
fatalx(char * m1,char * m2)22 void fatalx(char *m1, char *m2) {
23   strerr_die4x(111, progname, ": fatal: ", m1, m2);
24 }
warn(char * m1,char * m2)25 void warn(char *m1, char *m2) {
26   strerr_warn5(progname, ": fatal: ", m1, m2, ": ", &strerr_sys);
27 }
28 
main(int argc,char ** argv)29 int main (int argc, char **argv) {
30   struct stat s;
31   int dev;
32   int ino;
33 
34   progname =*argv++;
35   if (! argv || ! *argv) usage();
36 
37   new =*argv;
38   if (new[0] == '.') fatalx(new, ": must not start with a dot.");
39   if (chdir(SVDIR) == -1) fatal("unable to chdir: ", SVDIR);
40 
41   if (stat(new, &s) == -1) {
42     if (errno == error_noent) fatal(new, 0);
43     fatal("unable to stat: ", new);
44   }
45   if (! S_ISDIR(s.st_mode)) fatalx(new, "not a directory.");
46   ino =s.st_ino;
47   dev =s.st_dev;
48   if (stat("current", &s) == -1) fatal("unable to stat: ", "current");
49   if ((s.st_ino == ino) && (s.st_dev == dev)) {
50     buffer_puts(buffer_1, "runsvchdir: ");
51     buffer_puts(buffer_1, new);
52     buffer_puts(buffer_1, ": current.\n");
53     buffer_flush(buffer_1);
54     _exit(0);
55   }
56 
57   if (unlink("current.new") == -1)
58     if (errno != error_noent) fatal("unable to unlink: ", "current.new");
59   if (symlink(new, "current.new") == -1)
60     fatal("unable to create: current.new -> ", new);
61   if (unlink("previous") == -1)
62     if (errno != error_noent) fatal("unable to unlink: ", "previous");
63   if (rename("current", "previous") == -1)
64     fatal("unable to copy: current to ", "previous");
65   if (rename("current.new", "current") == -1) {
66     warn("unable to move: current.new to ", "current");
67     if (rename("previous", "current") == -1)
68       fatal("unable to move previous back to ", "current");
69     _exit(111);
70   }
71   buffer_puts(buffer_1, "runsvchdir: ");
72   buffer_puts(buffer_1, new);
73   buffer_puts(buffer_1, ": now current.\n");
74   buffer_flush(buffer_1);
75   _exit(0);
76 }
77