~cpick/mongrel2/release

« back to all changes in this revision

Viewing changes to examples/procer/procer.c

  • Committer: Chris Pick
  • Date: 2013-06-30 16:39:57 UTC
  • mfrom: (1106.1.15)
  • Revision ID: git-v1:ec39967acb6bc9867ed9b9dc3774304ca6b9c294
Merge tag 'v1.8.1' into debian

Hotfix for github issue 148

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <unixy.h>
2
 
#include <dbg.h>
3
 
#include "procer.h"
4
 
#include <glob.h>
5
 
#include <adt/tst.h>
6
 
#include <signal.h>
7
 
#include <stdlib.h>
8
 
#include <unistd.h>
9
 
#include <sys/wait.h>
10
 
#include <sys/stat.h>
11
 
 
12
 
extern char **environ;
13
 
 
14
 
static inline void hardsleep(int sec)
15
 
{
16
 
    taskyield();
17
 
    sleep(sec);
18
 
}
19
 
 
20
 
 
21
 
static inline void redirect_output(const char *run_log)
22
 
{
23
 
    freopen(run_log, "a+", stdout);
24
 
    setbuf(stdout, NULL);
25
 
    freopen(run_log, "a+", stderr);
26
 
    setbuf(stdout, NULL);
27
 
    freopen("/dev/null", "r", stdin);
28
 
}
29
 
 
30
 
 
31
 
int Action_exec(Action *action, Profile *prof)
32
 
{
33
 
    int rc = 0;
34
 
 
35
 
    debug("ACTION: command=%s, pid_file=%s, restart=%d, depends=%s",
36
 
            bdata(prof->command), bdata(prof->pid_file), prof->restart,
37
 
            bdata(action->depends));
38
 
 
39
 
    pid_t pid = fork();
40
 
    check(pid >= 0, "Fork failed, WTF.  How can fork fail?");
41
 
 
42
 
    if(pid == 0) {
43
 
        rc = Unixy_drop_priv(action->profile_dir);
44
 
 
45
 
        if(rc != 0) {
46
 
            log_err("Not fatal, but we couldn't drop priv for %s",
47
 
                    bdata(action->name));
48
 
        }
49
 
 
50
 
        redirect_output("run.log");
51
 
 
52
 
        rc = execle(bdata(prof->command), bdata(prof->command), NULL, environ);
53
 
        check(rc != -1, "Failed to exec command: %s", bdata(prof->command));
54
 
    } else {
55
 
        int status = 0;
56
 
        debug("WAITING FOR CHILD.");
57
 
        pid = waitpid(pid, &status, 0);
58
 
    }
59
 
 
60
 
    debug("Command ran and exited successfully, now looking for the PID file.");
61
 
    return 0;
62
 
error:
63
 
    return -1;
64
 
}
65
 
 
66
 
 
67
 
void Action_task(void *v)
68
 
{
69
 
    Action *action = (Action *)v;
70
 
    int rc = 0;
71
 
    pid_t child = 0;
72
 
    Profile *prof = Profile_load(action->profile_dir);
73
 
 
74
 
    taskname(bdata(action->name));
75
 
 
76
 
    taskstate("depends");
77
 
    rc = Rampart_wait(action->before);
78
 
    check(rc != -1, "A dependency failed to start, we can't start.");
79
 
 
80
 
    Rampart_running(&action->after);
81
 
 
82
 
    taskstate("ready");
83
 
    debug("STARTED %s", bdata(action->name));
84
 
 
85
 
    while(1) {
86
 
        taskstate("starting");
87
 
 
88
 
        if(Unixy_still_running(prof->pid_file, &child)) {
89
 
            debug("Looks like %s is already running, we'll just leave it alone.", bdata(action->name));
90
 
        } else {
91
 
            Unixy_remove_dead_pidfile(prof->pid_file);
92
 
            Action_exec(action, prof);
93
 
        }
94
 
 
95
 
        check(access(bdata(prof->pid_file), R_OK) == 0, "%s didn't make pidfile %s.", 
96
 
                bdata(action->name), bdata(prof->pid_file));
97
 
 
98
 
        taskstate("waiting");
99
 
        while(Unixy_still_running(prof->pid_file, &child)) {
100
 
            hardsleep(1);
101
 
        }
102
 
 
103
 
        if(!prof->restart) {
104
 
            break;
105
 
        }
106
 
 
107
 
        taskstate("restarting");
108
 
        hardsleep(1);
109
 
    }
110
 
 
111
 
    debug("ACTION %s exited.", bdata(action->name));
112
 
 
113
 
error:
114
 
    Rampart_failed(&action->after);
115
 
    return;
116
 
}
117
 
 
118
 
 
119
 
Action *Action_create(const char *profile)
120
 
{
121
 
    Action *action = calloc(sizeof(Action), 1);
122
 
    check_mem(action);
123
 
 
124
 
    action->profile_dir = bfromcstr(profile);
125
 
    action->name = bTail(action->profile_dir, 
126
 
            blength(action->profile_dir) -
127
 
            bstrrchr(action->profile_dir, '/') - 1);
128
 
 
129
 
    action->depends = Profile_read_setting(action->profile_dir, "depends");
130
 
 
131
 
    return action;
132
 
 
133
 
error:
134
 
    return NULL;
135
 
}
136
 
 
137
 
 
138
 
int Action_depends(Action *this_one, Action *needs)
139
 
{
140
 
    check(this_one->waiting_count < MAX_DEPENDS, 
141
 
            "Too many dependencies for %s, max is %d",
142
 
            bdata(this_one->name), MAX_DEPENDS);
143
 
 
144
 
    this_one->before[this_one->waiting_count] = &needs->after;
145
 
    this_one->waiting_count++;
146
 
 
147
 
    return 0;
148
 
error:
149
 
    return -1;
150
 
}
151
 
 
152
 
 
153
 
void Action_start(Action *action)
154
 
{
155
 
    taskcreate(Action_task, action, 32 * 1024);
156
 
}
157
 
 
158
 
void Action_dependency_assign(void *value, void *data)
159
 
{
160
 
    Action *action = (Action *)value;
161
 
    Action *target = NULL;
162
 
    tst_t *targets = (tst_t *)data;
163
 
    int i = 0;
164
 
 
165
 
    if(!action->depends) return;
166
 
 
167
 
    debug("Processed %s action depending on: %s", bdata(action->name), bdata(action->depends));
168
 
 
169
 
    if(action->depends) {
170
 
        struct bstrList *dep_list = bsplit(action->depends, ' ');
171
 
 
172
 
        for(i = 0; i < dep_list->qty; i++) {
173
 
            bstring dep = dep_list->entry[i];
174
 
 
175
 
            target = (Action *)tst_search(targets, bdata(dep), blength(dep));
176
 
 
177
 
            if(target) {
178
 
                Action_depends(action, target);
179
 
            } else {
180
 
                log_err("Could not find dependency %s has on %s.",
181
 
                        bdata(action->name), bdata(dep));
182
 
            }
183
 
        }
184
 
 
185
 
        bstrListDestroy(dep_list);
186
 
    }
187
 
}
188
 
 
189
 
void Action_start_all(void *value, void *data)
190
 
{
191
 
    Action *action = (Action *)value;
192
 
    Action_start(action);
193
 
}
194
 
 
195
 
 
196
 
void taskmain(int argc, char *argv[])
197
 
{
198
 
    dbg_set_log(stderr);
199
 
    glob_t profile_glob;
200
 
    int rc = 0;
201
 
    int i = 0;
202
 
    Action *action = NULL;
203
 
    tst_t *targets = NULL;
204
 
    bstring pid_file = NULL;
205
 
 
206
 
    check(argc == 3, "USAGE: procer <profile_dir> <procer_pid_file>");
207
 
    pid_file = bfromcstr(argv[2]);
208
 
 
209
 
    rc = Unixy_remove_dead_pidfile(pid_file);
210
 
    check(rc == 0, "Failed to remove %s, procer is probably already running.", bdata(pid_file));
211
 
 
212
 
    rc = Unixy_daemonize();
213
 
    check(rc == 0, "Couldn't daemonize, that's not good.");
214
 
 
215
 
    rc = chdir(argv[1]);
216
 
    check(rc == 0, "Couldn't change to %s profile dir.", argv[1]);
217
 
 
218
 
    rc = Unixy_pid_file(pid_file);
219
 
    check(rc == 0, "Failed to make the PID file: %s", bdata(pid_file));
220
 
 
221
 
    FILE *log = fopen("error.log", "a+");
222
 
    check(log, "Couldn't open error.log");
223
 
    setbuf(log, NULL);
224
 
    dbg_set_log(log);
225
 
 
226
 
    bstring dir_glob = bformat("%s/[A-Za-z0-9]*", argv[1]);
227
 
    check(dir_glob, "Couldn't make the directory glob.");
228
 
 
229
 
    rc = glob(bdata(dir_glob), GLOB_ERR, NULL, &profile_glob);
230
 
    check(rc == 0, "Failed to find directories in the profiles.");
231
 
 
232
 
    struct stat sb;
233
 
    debug("Loading %zu actions.", profile_glob.gl_pathc);
234
 
    for(i = 0; i < profile_glob.gl_pathc; i++) {
235
 
        rc = lstat(profile_glob.gl_pathv[i], &sb);
236
 
        check(rc == 0, "Failed to stat file or directory: %s", profile_glob.gl_pathv[i]);
237
 
 
238
 
        if (sb.st_mode & S_IFDIR) {
239
 
            action = Action_create(profile_glob.gl_pathv[i]);
240
 
            targets = tst_insert(targets, bdata(action->name), blength(action->name), action);
241
 
        }
242
 
    }
243
 
 
244
 
    // now we setup the dependencies from the settings they've got
245
 
    tst_traverse(targets, Action_dependency_assign, targets);
246
 
    tst_traverse(targets, Action_start_all, NULL);
247
 
 
248
 
    taskexit(0);
249
 
 
250
 
error:
251
 
    taskexitall(1);
252
 
}
253
 
 
254
 
 
255