f8baac3a0abef03bcf0be6557c6296f346bd8deb
[util-vserver.git] / src / chroot-sh.c
1 // $Id: chroot-sh.c 2407 2006-11-25 19:18:06Z dhozac $    --*- 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 struct Command {
196     char const          *cmd;
197     int                 (*handler)(int argc, char *argv[]);
198 } const         COMMANDS[] = {
199   { "cat",      execCat },
200   { "append",   execAppend },
201   { "truncate", execTruncate },
202   { "testfile", execTestFile },
203   { "rm",       execRm },
204   { "mkdir",    execMkdir },
205   { "chmod",    execChmod },
206   { 0,0 }
207 };
208
209 static void
210 showHelp()
211 {
212   WRITE_MSG(1,
213             "Usage: chroot-sh "
214             " [--] <cmd> <args>*\n\n"
215             "This program chroots into the current directory and executes the specified\n"
216             "commands there. This means that all used paths are relative to the current\n"
217             "directory, and symlinks can point to files under the current path only.\n"
218             "\n"
219             "The supported commands are:\n"
220             "  cat <file>      ...  gives out <file> to stdout\n"
221             "  append <file>   ...  appends stdin to <file> which is created when needed\n"
222             "  truncate <file> ...  clear <file> and fill it with stdin; the <file> is\n"
223             "                       created when needed\n"
224             "  rm <file>+      ...  unlink the given files\n"
225             "  mkdir <file>+   ...  create the given directories\n"
226             "  chmod <mode> <file>+\n"
227             "                  ...  change access permissions of files\n\n"
228             "Please report bugs to " PACKAGE_BUGREPORT "\n");
229   exit(0);
230 }
231
232 static void
233 showVersion()
234 {
235   WRITE_MSG(1,
236             "chroot-sh " VERSION " -- execute commands within a chroot\n"
237             "This program is part of " PACKAGE_STRING "\n\n"
238             "Copyright (C) 2005 Enrico Scholz\n"
239             VERSION_COPYRIGHT_DISCLAIMER);
240   exit(0);
241 }
242
243
244 int main(int argc, char *argv[])
245 {
246   struct Command const  *cmd;
247   int                   idx = 1;
248   
249   if (argc>=2) {
250     if (strcmp(argv[idx], "--help")   ==0) showHelp();
251     if (strcmp(argv[idx], "--version")==0) showVersion();
252     if (strcmp(argv[idx], "--")==0)        ++idx;
253   }
254
255   if (argc<idx+1) {
256     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
257     return wrapper_exit_code;
258   }
259
260   Echroot(".");
261   Echdir("/");
262
263   for (cmd=COMMANDS+0; cmd->cmd!=0; ++cmd) {
264     if (strcmp(cmd->cmd, argv[idx])==0)
265       return cmd->handler(argc-idx, argv+idx);
266   }
267
268   WRITE_MSG(2, "Invalid command '");
269   WRITE_STR(2, argv[idx]);
270   WRITE_MSG(2, "'; try '--help' for more information\n");
271
272   return wrapper_exit_code;
273 }