gentoo: use /var/run for new /run compatibility
[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 int
232 execRealpath(int argc, char *argv[])
233 {
234   int           res = EXIT_SUCCESS,
235                 i;
236
237   if (argc < 2) {
238     WRITE_MSG(2, "Need some files to work on for 'realpath' operation; try '--help' for more information\n");
239     return wrapper_exit_code;
240   }
241
242   for (i = 1; i< argc; i++) {
243     char buf[4096];
244
245     if (realpath(argv[i], buf) == NULL) {
246       PERROR_Q(ENSC_WRAPPERS_PREFIX "realpath", argv[i]);
247       res = EXIT_FAILURE;
248     }
249     else {
250       WRITE_STR(1, buf);
251       WRITE_MSG(1, "\n");
252     }
253   }
254
255   return res;
256 }
257
258 static struct Command {
259     char const          *cmd;
260     int                 (*handler)(int argc, char *argv[]);
261 } const         COMMANDS[] = {
262   { "cat",      execCat },
263   { "append",   execAppend },
264   { "truncate", execTruncate },
265   { "testfile", execTestFile },
266   { "rm",       execRm },
267   { "mkdir",    execMkdir },
268   { "chmod",    execChmod },
269   { "link",     execLink },
270   { "mv",       execMv },
271   { "realpath", execRealpath },
272   { 0,0 }
273 };
274
275 static void
276 showHelp()
277 {
278   WRITE_MSG(1,
279             "Usage: chroot-sh "
280             " [--] <cmd> <args>*\n\n"
281             "This program chroots into the current directory and executes the specified\n"
282             "commands there. This means that all used paths are relative to the current\n"
283             "directory, and symlinks can point to files under the current path only.\n"
284             "\n"
285             "The supported commands are:\n"
286             "  cat <file>       ...  gives out <file> to stdout\n"
287             "  append <file>    ...  appends stdin to <file> which is created when needed\n"
288             "  truncate <file>  ...  clear <file> and fill it with stdin; the <file> is\n"
289             "                       created when needed\n"
290             "  rm <file>+       ...  unlink the given files\n"
291             "  mkdir <file>+    ...  create the given directories\n"
292             "  chmod <mode> <file>+\n"
293             "                   ...  change access permissions of files\n"
294             "  link <src> <dst> ...  create a symbolic link from <src> to <dst>\n"
295             "  mv <src> <dst>   ...  rename <src> to <dst>\n"
296             "  realpath <file>+ ...  output real path of each <file>\n"
297             "\nPlease report bugs to " PACKAGE_BUGREPORT "\n");
298   exit(0);
299 }
300
301 static void
302 showVersion()
303 {
304   WRITE_MSG(1,
305             "chroot-sh " VERSION " -- execute commands within a chroot\n"
306             "This program is part of " PACKAGE_STRING "\n\n"
307             "Copyright (C) 2005 Enrico Scholz\n"
308             VERSION_COPYRIGHT_DISCLAIMER);
309   exit(0);
310 }
311
312
313 int main(int argc, char *argv[])
314 {
315   struct Command const  *cmd;
316   int                   idx = 1;
317   
318   if (argc>=2) {
319     if (strcmp(argv[idx], "--help")   ==0) showHelp();
320     if (strcmp(argv[idx], "--version")==0) showVersion();
321     if (strcmp(argv[idx], "--")==0)        ++idx;
322   }
323
324   if (argc<idx+1) {
325     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
326     return wrapper_exit_code;
327   }
328
329   Echroot(".");
330   Echdir("/");
331
332   for (cmd=COMMANDS+0; cmd->cmd!=0; ++cmd) {
333     if (strcmp(cmd->cmd, argv[idx])==0)
334       return cmd->handler(argc-idx, argv+idx);
335   }
336
337   WRITE_MSG(2, "Invalid command '");
338   WRITE_STR(2, argv[idx]);
339   WRITE_MSG(2, "'; try '--help' for more information\n");
340
341   return wrapper_exit_code;
342 }