Nothing to see here
[public/pyceo-broken.git] / src / util.c
1 #define _ATFILE_SOURCE
2 #include <unistd.h>
3 #include <sys/wait.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <fcntl.h>
8 #include <syslog.h>
9 #include <errno.h>
10 #include <grp.h>
11
12 #include "util.h"
13 #include "strbuf.h"
14
15 static int log_stderr = 1;
16
17 void init_log(const char *ident, int option, int facility) {
18     openlog(ident, option, facility);
19     log_stderr = isatty(STDERR_FILENO);
20 }
21
22 static void errmsg(int prio, const char *prefix, const char *fmt, va_list args) {
23     struct strbuf msg = STRBUF_INIT;
24
25     strbuf_addf(&msg, "%s: ", prefix);
26     strbuf_vaddf(&msg, fmt, args);
27     strbuf_addch(&msg, '\n');
28
29     syslog(prio, "%s", msg.buf);
30     if (log_stderr)
31         fputs(msg.buf, stderr);
32
33     strbuf_release(&msg);
34 }
35
36 static void errmsgpe(int prio, const char *prefix, const char *fmt, va_list args) {
37     struct strbuf msg = STRBUF_INIT;
38
39     strbuf_addf(&msg, "%s: ", prefix);
40     strbuf_vaddf(&msg, fmt, args);
41     strbuf_addf(&msg, ": %s\n", strerror(errno));
42
43     syslog(prio, "%s", msg.buf);
44     if (log_stderr)
45         fputs(msg.buf, stderr);
46
47     strbuf_release(&msg);
48 }
49
50 NORETURN static void die(int prio, const char *prefix, const char *msg, va_list args) {
51     errmsg(prio, prefix, msg, args);
52     exit(1);
53 }
54
55 NORETURN static void diepe(int prio, const char *prefix, const char *msg, va_list args) {
56     errmsgpe(prio, prefix, msg, args);
57     exit(1);
58 }
59
60 NORETURN void fatal(const char *msg, ...) {
61     va_list args;
62     va_start(args, msg);
63     die(LOG_CRIT, "fatal", msg, args);
64     va_end(args);
65 }
66
67 void error(const char *msg, ...) {
68     va_list args;
69     va_start(args, msg);
70     errmsg(LOG_ERR, "error", msg, args);
71     va_end(args);
72 }
73
74 void warn(const char *msg, ...) {
75     va_list args;
76     va_start(args, msg);
77     errmsg(LOG_WARNING, "warning", msg, args);
78     va_end(args);
79 }
80
81 void notice(const char *msg, ...) {
82     va_list args;
83     va_start(args, msg);
84     errmsg(LOG_NOTICE, "notice", msg, args);
85     va_end(args);
86 }
87
88 void debug(const char *msg, ...) {
89     va_list args;
90     va_start(args, msg);
91     errmsg(LOG_DEBUG, "debug", msg, args);
92     va_end(args);
93 }
94
95 void logmsg(int priority, const char *msg, ...) {
96     va_list args;
97     va_start(args, msg);
98     vsyslog(priority, msg, args);
99     va_end(args);
100     va_start(args, msg);
101     if (log_stderr) {
102         vfprintf(stderr, msg, args);
103         fputc('\n', stderr);
104     }
105     va_end(args);
106 }
107
108 NORETURN void deny(const char *msg, ...) {
109     va_list args;
110     va_start(args, msg);
111     die(LOG_ERR, "denied", msg, args);
112     va_end(args);
113 }
114
115 NORETURN void badconf(const char *msg, ...) {
116     va_list args;
117     va_start(args, msg);
118     die(LOG_CRIT, "configuration error", msg, args);
119     va_end(args);
120 }
121
122 NORETURN void fatalpe(const char *msg, ...) {
123     va_list args;
124     va_start(args, msg);
125     diepe(LOG_CRIT, "fatal", msg, args);
126     va_end(args);
127 }
128
129 void errorpe(const char *msg, ...) {
130     va_list args;
131     va_start(args, msg);
132     errmsgpe(LOG_ERR, "error", msg, args);
133     va_end(args);
134 }
135
136 void warnpe(const char *msg, ...) {
137     va_list args;
138     va_start(args, msg);
139     errmsgpe(LOG_WARNING, "warning", msg, args);
140     va_end(args);
141 }
142
143 int spawnv(const char *path, char *const argv[]) {
144     int pid, status;
145
146     fflush(stdout);
147     fflush(stderr);
148
149     pid = fork();
150     if (pid < 0)
151         fatalpe("fork");
152     else if (pid)
153         waitpid(pid, &status, 0);
154     else
155         exit(execv(path, argv));
156     return status;
157 }
158
159 void full_write(int fd, const void *buf, size_t count) {
160     ssize_t total = 0;
161
162     while (total < count) {
163         ssize_t wcount = write(fd, (char *)buf + total, count - total);
164         if (wcount < 0)
165             fatalpe("write");
166         total += wcount;
167     }
168 }
169
170 int spawnvem(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr) {
171     int pid, wpid, status;
172     int tochild[2];
173     int fmchild[2];
174
175     if (pipe(tochild))
176         fatalpe("pipe");
177     if (pipe(fmchild))
178         fatalpe("pipe");
179
180     fflush(stdout);
181     fflush(stderr);
182
183     pid = fork();
184     if (pid < 0)
185         fatalpe("fork");
186     if (!pid) {
187         dup2(tochild[0], STDIN_FILENO);
188         dup2(fmchild[1], STDOUT_FILENO);
189         if (cap_stderr)
190             dup2(STDOUT_FILENO, STDERR_FILENO);
191         close(tochild[0]);
192         close(tochild[1]);
193         close(fmchild[0]);
194         close(fmchild[1]);
195         execve(path, argv, envp);
196         fatalpe("execve");
197     } else {
198         close(tochild[0]);
199         close(fmchild[1]);
200         full_write(tochild[1], output->buf, output->len);
201         close(tochild[1]);
202
203         if (input)
204             strbuf_read(input, fmchild[0], 0);
205         close(fmchild[0]);
206     }
207
208     wpid = waitpid(pid, &status, 0);
209     if (wpid < 0)
210         fatalpe("waitpid");
211     else if (wpid != pid)
212         fatal("waitpid is broken");
213
214     if (WIFEXITED(status) && WEXITSTATUS(status))
215         notice("child %s exited with status %d", path, WEXITSTATUS(status));
216     else if (WIFSIGNALED(status))
217         notice("child %s killed by signal %d", path, WTERMSIG(status));
218
219     return status;
220 }
221
222 int spawnv_msg(const char *path, char *const *argv, const struct strbuf *output) {
223     return spawnvem(path, argv, environ, output, NULL, 0);
224 }
225
226 int check_group(char *username, char *group) {
227     struct group *grp = getgrnam(group);
228     char **members;
229
230     if (grp)
231         for (members = grp->gr_mem; *members; members++)
232             if (!strcmp(username, *members))
233                 return 1;
234
235     return 0;
236 }
237
238 FILE *fopenat(DIR *d, const char *path, int flags) {
239     int dfd = dirfd(d);
240     if (dfd < 0)
241         return NULL;
242     int fd = openat(dfd, path, flags);
243     if (fd < 0)
244         return NULL;
245     return fdopen(fd, flags & O_RDWR   ? "r+" :
246                       flags & O_WRONLY ? "w" :
247                                          "r");
248 }
249
250 void make_env(char **envp, ...) {
251     const size_t len = 4096;
252     size_t used = 0;
253     int args = 0;
254     char *buf = xmalloc(len);
255     va_list ap;
256     va_start(ap, envp);
257     char *name, *val;
258
259     while ((name = va_arg(ap, char *))) {
260         val = va_arg(ap, char *);
261         if (!val)
262             continue;
263         int n = snprintf(buf + used, len - used, "%s=%s", name, val);
264         if (n < 0)
265             fatalpe("snprintf");
266         if (n >= len - used)
267             fatal("environment too big");
268
269         envp[args++] = buf + used;
270         used += n + 1;
271     }
272
273     if (!args)
274         free(buf);
275
276     envp[args] = NULL;
277 }
278
279 void free_env(char **envp) {
280     free(*envp);
281 }