Rename flags to cflags.
[util-vserver.git] / src / chroot-sh.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include <lib_internal/util.h>
24
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30
31 #define ENSC_WRAPPERS_PREFIX    "chroot-sh: "
32 #define ENSC_WRAPPERS_UNISTD    1
33 #define ENSC_WRAPPERS_IO        1
34 #define ENSC_WRAPPERS_FCNTL     1
35 #include <ensc_wrappers/wrappers.h>
36
37 int     wrapper_exit_code = EXIT_FAILURE;
38
39 static void
40 showFD(int fd_in, int fd_out)
41 {
42   for (;;) {
43     char                buf[4096];
44     char const *        ptr=buf;
45     ssize_t             len;
46
47     len = Eread(fd_in, buf, sizeof(buf));
48     if (len<=0) break;
49
50     EwriteAll(fd_out, ptr, len);
51   }
52 }
53
54 static int
55 redirectFileInternal(int argc, char *argv[],
56                      int mode, bool is_input,
57                      char const *operation)
58 {
59   int           fd;
60
61   if (argc<2) {
62     WRITE_MSG(2, "Not enough parameters for '");
63     WRITE_STR(2, operation);
64     WRITE_MSG(2, "' operation; use '--help' for more information\n");
65     return wrapper_exit_code;
66   }
67
68   fd = EopenD(argv[1], mode, 0644);
69   if (is_input) showFD(fd,  1);
70   else          showFD( 0, fd);
71   Eclose(fd);
72
73   return EXIT_SUCCESS;
74 }
75
76 static mode_t
77 testInternal(int argc, char *argv[], char const *operation)
78 {
79   struct stat           st;
80     
81   if (argc<2) {
82     WRITE_MSG(2, "Not enough parameters for '");
83     WRITE_STR(2, operation);
84     WRITE_MSG(2, "' operation; use '--help' for more information\n");
85     return wrapper_exit_code;
86   }
87
88   if (stat(argv[1], &st)==-1) return -1;
89   else                        return st.st_mode;
90 }
91
92 static int
93 execCat(int argc, char *argv[])
94 {
95   return redirectFileInternal(argc, argv,
96                               O_RDONLY|O_NOCTTY, true,
97                               "cat");
98 }
99
100 static int
101 execAppend(int argc, char *argv[])
102 {
103   return redirectFileInternal(argc, argv,
104                               O_WRONLY|O_CREAT|O_APPEND, false,
105                               "append");
106 }
107
108 static int
109 execTruncate(int argc, char *argv[])
110 {
111   return redirectFileInternal(argc, argv,
112                               O_WRONLY|O_CREAT|O_TRUNC, false,
113                               "truncate");
114 }
115
116 static int
117 execRm(int argc, char *argv[])
118 {
119   int           i   = 1;
120   int           res = EXIT_SUCCESS;
121   
122   if (argc<2) {
123     WRITE_MSG(2, "No files specified for 'rm' operation; try '--help' for more information\n");
124     return wrapper_exit_code;
125   }
126
127   for (;i<argc; ++i) {
128     if (unlink(argv[i])==-1) {
129       PERROR_Q(ENSC_WRAPPERS_PREFIX "unlink", argv[i]);
130       res = EXIT_FAILURE;
131     }
132   }
133
134   return res;
135 }
136
137 static int
138 execTestFile(int argc, char *argv[])
139 {
140   int           res = testInternal(argc, argv, "testfile");
141   
142   return res!=-1 && S_ISREG(res) ? EXIT_SUCCESS : EXIT_FAILURE;
143 }
144
145 static int
146 execMkdir(int argc, char *argv[])
147 {
148   int           i   = 1;
149   int           res = EXIT_SUCCESS;
150   
151   if (argc<2) {
152     WRITE_MSG(2, "No files specified for 'mkdir' operation; try '--help' for more information\n");
153     return wrapper_exit_code;
154   }
155
156   for (;i<argc; ++i) {
157     if (mkdir(argv[i], 0755)==-1) {
158       PERROR_Q(ENSC_WRAPPERS_PREFIX "mkdir", argv[i]);
159       res = EXIT_FAILURE;
160     }
161   }
162
163   return res;
164 }
165
166 static int
167 execChmod(int argc, char *argv[])
168 {
169   int           i   = 2;
170   int           res = EXIT_SUCCESS;
171   unsigned long mode;
172   
173   if (argc<3) {
174     WRITE_MSG(2, "No files specified for 'chmod' operation; try '--help' for more information\n");
175     return wrapper_exit_code;
176   }
177
178   if (!isNumberUnsigned(argv[1], &mode, 1)) {
179     WRITE_MSG(2, "Invalid mode: '");
180     WRITE_STR(2, argv[1]);
181     WRITE_MSG(2, "'\n");
182     return EXIT_FAILURE;
183   }
184
185   for (;i<argc; ++i) {
186     if (chmod(argv[i], mode)==-1) {
187       PERROR_Q(ENSC_WRAPPERS_PREFIX "chmod", argv[i]);
188       res = EXIT_FAILURE;
189     }
190   }
191
192   return res;
193 }
194
195 static int
196 execLink(int argc, char *argv[])
197 {
198   int           res = EXIT_SUCCESS;
199
200   if (argc!=3) {
201     WRITE_MSG(2, "Need exactly two files for 'link' operation; try '--help' for more information\n");
202     return wrapper_exit_code;
203   }
204
205   if (symlink(argv[1], argv[2])==-1) {
206     PERROR_Q(ENSC_WRAPPERS_PREFIX "link", argv[1]);
207     res = EXIT_FAILURE;
208   }
209
210   return res;
211 }
212
213 static int
214 execMv(int argc, char *argv[])
215 {
216   int           res = EXIT_SUCCESS;
217
218   if (argc!=3) {
219     WRITE_MSG(2, "Need exactly two files for 'mv' operation; try '--help' for more information\n");
220     return wrapper_exit_code;
221   }
222
223   if (rename(argv[1], argv[2])==-1) {
224     PERROR_Q(ENSC_WRAPPERS_PREFIX "mv", argv[1]);
225     res = EXIT_FAILURE;
226   }
227
228   return res;
229 }
230
231 static struct Command {
232     char const          *cmd;
233     int                 (*handler)(int argc, char *argv[]);
234 } const         COMMANDS[] = {
235   { "cat",      execCat },
236   { "append",   execAppend },
237   { "truncate", execTruncate },
238   { "testfile", execTestFile },
239   { "rm",       execRm },
240   { "mkdir",    execMkdir },
241   { "chmod",    execChmod },
242   { "link",     execLink },
243   { "mv",       execMv },
244   { 0,0 }
245 };
246
247 static void
248 showHelp()
249 {
250   WRITE_MSG(1,
251             "Usage: chroot-sh "
252             " [--] <cmd> <args>*\n\n"
253             "This program chroots into the current directory and executes the specified\n"
254             "commands there. This means that all used paths are relative to the current\n"
255             "directory, and symlinks can point to files under the current path only.\n"
256             "\n"
257             "The supported commands are:\n"
258             "  cat <file>       ...  gives out <file> to stdout\n"
259             "  append <file>    ...  appends stdin to <file> which is created when needed\n"
260             "  truncate <file>  ...  clear <file> and fill it with stdin; the <file> is\n"
261             "                       created when needed\n"
262             "  rm <file>+       ...  unlink the given files\n"
263             "  mkdir <file>+    ...  create the given directories\n"
264             "  chmod <mode> <file>+\n"
265             "                   ...  change access permissions of files\n"
266             "  link <src> <dst> ...  create a symbolic link from <src> to <dst>\n"
267             "  mv <src> <dst>   ...  rename <src> to <dst>\n"
268             "\nPlease report bugs to " PACKAGE_BUGREPORT "\n");
269   exit(0);
270 }
271
272 static void
273 showVersion()
274 {
275   WRITE_MSG(1,
276             "chroot-sh " VERSION " -- execute commands within a chroot\n"
277             "This program is part of " PACKAGE_STRING "\n\n"
278             "Copyright (C) 2005 Enrico Scholz\n"
279             VERSION_COPYRIGHT_DISCLAIMER);
280   exit(0);
281 }
282
283
284 int main(int argc, char *argv[])
285 {
286   struct Command const  *cmd;
287   int                   idx = 1;
288   
289   if (argc>=2) {
290     if (strcmp(argv[idx], "--help")   ==0) showHelp();
291     if (strcmp(argv[idx], "--version")==0) showVersion();
292     if (strcmp(argv[idx], "--")==0)        ++idx;
293   }
294
295   if (argc<idx+1) {
296     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
297     return wrapper_exit_code;
298   }
299
300   Echroot(".");
301   Echdir("/");
302
303   for (cmd=COMMANDS+0; cmd->cmd!=0; ++cmd) {
304     if (strcmp(cmd->cmd, argv[idx])==0)
305       return cmd->handler(argc-idx, argv+idx);
306   }
307
308   WRITE_MSG(2, "Invalid command '");
309   WRITE_STR(2, argv[idx]);
310   WRITE_MSG(2, "'; try '--help' for more information\n");
311
312   return wrapper_exit_code;
313 }