merge with 0.30.213
[util-vserver.git] / src / chroot-sh.c
1 // $Id: chroot-sh.c 2536 2007-04-27 09:01:20Z hollow $    --*- 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 struct Command {
214     char const          *cmd;
215     int                 (*handler)(int argc, char *argv[]);
216 } const         COMMANDS[] = {
217   { "cat",      execCat },
218   { "append",   execAppend },
219   { "truncate", execTruncate },
220   { "testfile", execTestFile },
221   { "rm",       execRm },
222   { "mkdir",    execMkdir },
223   { "chmod",    execChmod },
224   { "link",     execLink },
225   { 0,0 }
226 };
227
228 static void
229 showHelp()
230 {
231   WRITE_MSG(1,
232             "Usage: chroot-sh "
233             " [--] <cmd> <args>*\n\n"
234             "This program chroots into the current directory and executes the specified\n"
235             "commands there. This means that all used paths are relative to the current\n"
236             "directory, and symlinks can point to files under the current path only.\n"
237             "\n"
238             "The supported commands are:\n"
239             "  cat <file>      ...  gives out <file> to stdout\n"
240             "  append <file>   ...  appends stdin to <file> which is created when needed\n"
241             "  truncate <file> ...  clear <file> and fill it with stdin; the <file> is\n"
242             "                       created when needed\n"
243             "  rm <file>+      ...  unlink the given files\n"
244             "  mkdir <file>+   ...  create the given directories\n"
245             "  chmod <mode> <file>+\n"
246             "                  ...  change access permissions of files\n"
247             "  link <src> dst> ...  create a symbolic link from <src> to <dst>\n\n"
248             "Please report bugs to " PACKAGE_BUGREPORT "\n");
249   exit(0);
250 }
251
252 static void
253 showVersion()
254 {
255   WRITE_MSG(1,
256             "chroot-sh " VERSION " -- execute commands within a chroot\n"
257             "This program is part of " PACKAGE_STRING "\n\n"
258             "Copyright (C) 2005 Enrico Scholz\n"
259             VERSION_COPYRIGHT_DISCLAIMER);
260   exit(0);
261 }
262
263
264 int main(int argc, char *argv[])
265 {
266   struct Command const  *cmd;
267   int                   idx = 1;
268   
269   if (argc>=2) {
270     if (strcmp(argv[idx], "--help")   ==0) showHelp();
271     if (strcmp(argv[idx], "--version")==0) showVersion();
272     if (strcmp(argv[idx], "--")==0)        ++idx;
273   }
274
275   if (argc<idx+1) {
276     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
277     return wrapper_exit_code;
278   }
279
280   Echroot(".");
281   Echdir("/");
282
283   for (cmd=COMMANDS+0; cmd->cmd!=0; ++cmd) {
284     if (strcmp(cmd->cmd, argv[idx])==0)
285       return cmd->handler(argc-idx, argv+idx);
286   }
287
288   WRITE_MSG(2, "Invalid command '");
289   WRITE_STR(2, argv[idx]);
290   WRITE_MSG(2, "'; try '--help' for more information\n");
291
292   return wrapper_exit_code;
293 }