]> git.pld-linux.org Git - projects/setup.git/blob - postshell.c
add etc/sub[ug]id
[projects/setup.git] / postshell.c
1 /*
2  * Copyright (c) 2002 Michal Moskal <malekith@pld-linux.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Michal Moskal.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * Usage
35  * ~~~~~
36  *
37  * This simple program is aimed to be used as script interpreter in rpm
38  * %post scriptlets and the like. It opens file passed as first argument
39  * and executes commands found there. Only linear execution is supported.
40  * For example, in glibc.spec:
41  *
42  * %post -p /sbin/postshell
43  * ldconfig
44  * -telinit q
45  *
46  * (full patch like /sbin/ldconfig or -/sbin/tellinit will also work).
47  *
48  * If command starts with - its exit status is ignored. Otherwise last 
49  * non-zero exit status is returned.
50  *
51  * There are no builtin commands (yet :).
52  *
53  * Following commands *will* work as expected (as in Bourne shell):
54  *
55  * /bin/echo "Foo     bar baz"
56  * insmod foobar options="foo bar 'qux'"
57  * false
58  *
59  * Following *won't*:
60  *
61  * exit 1
62  * echo foo || echo baz
63  * set -x
64  * 
65  * Patches and bugreports are welcome, direct them to Michal Moskal
66  * <malekith@pld-linux.org>.
67  */
68
69 #define _GNU_SOURCE
70 #include <sys/types.h>
71 #include <sys/wait.h>
72 #include <unistd.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <ctype.h>
77 #include <fcntl.h>
78 #include <sys/mman.h>
79 #include <sys/stat.h>
80
81 #define MAX_LINE 1024
82 #define MAX_ARGS 32
83 #define SEARCH_PATH { "/sbin/", "/bin/", "/usr/sbin/", "/usr/bin/", NULL }
84
85 int exit_status;
86 int ignore_status;
87
88 void do_execve(char **argv)
89 {
90         char *path[] = SEARCH_PATH;
91         char file[MAX_LINE + 100];
92         int i; 
93
94         if (**argv == '.' || **argv == '/')
95                 execve(argv[0], argv, environ);
96         else 
97                 for (i = 0; path[i]; i++) {
98                         strcpy(file, path[i]);
99                         strcat(file, argv[0]);
100                         execve(file, argv, environ);
101                 }
102 }
103
104 int exec_and_wait(char **argv)
105 {
106         pid_t pid;
107
108         pid = fork();
109
110         if (pid == -1) {
111                 perror("fork");
112                 return -1;
113         } else if (pid == 0) {
114                 /* child. */
115                 do_execve(argv);
116                 if (!ignore_status) 
117                         perror(argv[0]); 
118                 exit(127);
119         } else {
120                 int status, err;
121                 
122                 err = waitpid(pid, &status, 0);
123                 if (err < 0) {
124                         perror("waitpid");
125                         return -1;
126                 } else
127                         return WEXITSTATUS(status);
128         }
129 }
130
131 void split_argv(char **argv, char *s)
132 {
133         char *dst;
134         int argc, delim;
135         
136         for (argc = 0; argc < MAX_ARGS; argc++) {
137                 while (*s == ' ' || *s == '\t')
138                         s++;
139
140                 if (*s == 0)
141                         break;
142
143                 argv[argc] = s;
144                 dst = s;
145                 
146                 while (*s && *s != ' ' && *s != '\t') {
147                         if (*s == '\'' || *s == '"') {
148                                 delim = *s++;
149                                 while (*s && *s != delim)
150                                         *dst++ = *s++;
151                                 if (*s)
152                                         s++;
153                         } else {
154                                 *dst++ = *s++;
155                         }
156                 }
157
158                 if (*dst) {
159                         if (s == dst)
160                                 s++;
161                         *dst++ = 0;
162                 }
163         }
164
165         argv[argc] = NULL;
166 }
167
168 void exec_line(char *s)
169 {
170         char *argv[MAX_ARGS + 1], *c;
171         int ret;
172
173
174         /* skip blank characters */     
175         for (c = s; c && isblank(*c); c++)
176                 ;
177         /* skip commented lines */
178         if (*c == '#')
179                 return;
180
181         split_argv(argv, s);
182         
183         ignore_status = 0;
184
185         if (**argv == '-') {
186                 ignore_status++;
187                 (*argv)++;
188         }
189
190         ret = exec_and_wait(argv);
191
192         if (ret && !ignore_status)
193                 exit_status = ret;
194 }
195
196 void exec_file(int fd)
197 {
198         char line[MAX_LINE];
199         struct stat sbuf;
200         char *p, *s, *a;
201
202         if (fstat(fd, &sbuf) < 0) {
203                 perror("fstat()");
204                 exit(1);
205         }
206
207         if ((p = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) < 0) {
208                 perror("mmap()");
209                 exit(1);
210         }
211
212         for (a = s = p; s < p + sbuf.st_size; s++) {
213                 if (*s == '\n') {
214                         memcpy(line, a, s - a);
215                         line[s - a] = '\0';
216                         exec_line(line);
217                         a = ++s;
218                 }
219         }
220
221         // last line was not terminated.
222         if (s == p + sbuf.st_size) {
223                 memcpy(line, a, s - a);
224                 line[s - a] = '\0';
225                 exec_line(line);
226         }
227
228         if (munmap(p, sbuf.st_size) < 0) {
229                 perror("munmap()");
230                 exit(1);
231         }
232 }
233
234 ssize_t error(char *msg) {
235         return write(2, msg, strlen(msg));
236 }
237
238 int main(int argc, char **argv)
239 {
240         int fd;
241
242         if (argc < 2) {
243                 error("USAGE: ");
244                 error(argv[0]);
245                 error(" filename\n");
246                 exit(1);
247         }
248
249         fd = open(argv[1], O_RDONLY);
250         
251         if (fd == -1) {
252                 perror(argv[1]);
253                 exit(1);
254         }
255
256         exec_file(fd);
257         close(fd);
258         exit(exit_status);
259 }
This page took 0.081899 seconds and 3 git commands to generate.