chiark / gitweb /
Disable all exported shell functions
[bash.git] / debian / bash.preinst-lib.c
1 /*
2  * This file is in the public domain.
3  * You may freely use, modify, distribute, and relicense it.
4  */
5
6 #include "bash.preinst.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <spawn.h>
18
19 extern char **environ;
20
21 __attribute__((format(printf, 1, 0)))
22 static void vreportf(const char *err, va_list params, int errnum)
23 {
24         fprintf(stderr, "bash.preinst: ");
25         vfprintf(stderr, err, params);
26         if (errnum)
27                 fprintf(stderr, ": %s", strerror(errnum));
28         fprintf(stderr, "\n");
29 }
30
31 __attribute__((format(printf, 1, 2)))
32 NORETURN void die_errno(const char *fmt, ...)
33 {
34         va_list params;
35         va_start(params, fmt);
36         vreportf(fmt, params, errno);
37         va_end(params);
38         exit(1);
39 }
40
41 __attribute__((format(printf, 1, 2)))
42 NORETURN void die(const char *fmt, ...)
43 {
44         va_list params;
45         va_start(params, fmt);
46         vreportf(fmt, params, 0);
47         va_end(params);
48         exit(1);
49 }
50
51 int exists(const char *file)
52 {
53         struct stat sb;
54         if (!lstat(file, &sb))
55                 return 1;
56         if (errno == ENOENT)
57                 return 0;
58         die_errno("cannot get status of %s", file);
59 }
60
61 void set_cloexec(int fd)
62 {
63         int flags = fcntl(fd, F_GETFD);
64         if (flags < 0 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC))
65                 die_errno("cannot set close-on-exec flag");
66 }
67
68 void xpipe(int pipefd[2])
69 {
70         if (pipe(pipefd))
71                 die_errno("cannot create pipe");
72         set_cloexec(pipefd[0]);
73         set_cloexec(pipefd[1]);
74 }
75
76 void wait_or_die(pid_t child, const char *name, int flags)
77 {
78         int status;
79         if (waitpid(child, &status, 0) != child)
80                 die_errno("cannot wait for %s", name);
81         if ((WIFEXITED(status) && WEXITSTATUS(status) == 0) ||
82             ((flags & ERROR_OK) && WIFEXITED(status)) ||
83             ((flags & SIGPIPE_OK) &&
84              WIFSIGNALED(status) && WTERMSIG(status) == SIGPIPE))
85                 return;
86
87         if (WIFEXITED(status))
88                 die("%s exited with status %d", name, WEXITSTATUS(status));
89         if (WIFSIGNALED(status))
90                 die("%s killed by signal %d", name, WTERMSIG(status));
91         if (WIFSTOPPED(status))
92                 die("%s stopped by signal %d", name, WSTOPSIG(status));
93         die("waitpid is confused (status=%d)", status);
94 }
95
96 pid_t spawn(const char * const cmd[], int out, int err)
97 {
98         pid_t child;
99         posix_spawn_file_actions_t redir;
100
101         if (posix_spawn_file_actions_init(&redir) ||
102             (out >= 0 && posix_spawn_file_actions_adddup2(&redir, out, 1)) ||
103             (err >= 0 && posix_spawn_file_actions_adddup2(&redir, err, 2)) ||
104             posix_spawnp(&child, cmd[0], &redir, NULL,
105                                                 (char **) cmd, environ) ||
106             posix_spawn_file_actions_destroy(&redir))
107                 die_errno("cannot run %s", cmd[0]);
108         return child;
109 }
110
111 void run(const char * const cmd[])
112 {
113         pid_t child = spawn(cmd, -1, -1);
114         wait_or_die(child, cmd[0], 0);
115 }
116
117 FILE *spawn_pipe(pid_t *pid, const char * const cmd[], int errfd)
118 {
119         int pipefd[2];
120         FILE *f;
121
122         xpipe(pipefd);
123         *pid = spawn(cmd, pipefd[1], errfd);
124         if (close(pipefd[1]) || (errfd != -1 && close(errfd)))
125                 die_errno("cannot close unneeded fd");
126
127         f = fdopen(pipefd[0], "r");
128         if (!f)
129                 die_errno("cannot stream read end of pipe");
130         return f;
131 }