a1d4bb990dfbe35fb84a24f8be7eb80a2172b5d5
[util-vserver.git] / src / chroot-sh.c
1 // $Id: chroot-sh.c,v 1.2 2005/07/03 17:40:15 ensc Exp $    --*- 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 0;
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
146 static struct Command {
147     char const          *cmd;
148     int                 (*handler)(int argc, char *argv[]);
149 } const         COMMANDS[] = {
150   { "cat",      execCat },
151   { "append",   execAppend },
152   { "truncate", execTruncate },
153   { "testfile", execTestFile },
154   { "rm",       execRm },
155   { 0,0 }
156 };
157
158 static void
159 showHelp()
160 {
161   WRITE_MSG(1,
162             "Usage: chroot-sh "
163             " [--] <cmd> <args>*\n\n"
164             "This program chroots into the current directory and executes the specified\n"
165             "commands there. This means that all used paths are relative to the current\n"
166             "directory, and symlinks can point to files under the current path only.\n"
167             "\n"
168             "The supported commands are:\n"
169             "  cat <file>      ...  gives out <file> to stdout\n"
170             "  append <file>   ...  appends stdin to <file> which is created when needed\n"
171             "  truncate <file> ...  clear <file> and fill it with stdin; the <file> is\n"
172             "                       created when needed\n"
173             "  rm <file>+      ...  unlink the given files\n\n"
174             "Please report bugs to " PACKAGE_BUGREPORT "\n");
175   exit(0);
176 }
177
178 static void
179 showVersion()
180 {
181   WRITE_MSG(1,
182             "chroot-sh " VERSION " -- execute commands within a chroot\n"
183             "This program is part of " PACKAGE_STRING "\n\n"
184             "Copyright (C) 2005 Enrico Scholz\n"
185             VERSION_COPYRIGHT_DISCLAIMER);
186   exit(0);
187 }
188
189
190 int main(int argc, char *argv[])
191 {
192   struct Command const  *cmd;
193   int                   idx = 1;
194   
195   if (argc>=2) {
196     if (strcmp(argv[idx], "--help")   ==0) showHelp();
197     if (strcmp(argv[idx], "--version")==0) showVersion();
198     if (strcmp(argv[idx], "--")==0)        ++idx;
199   }
200
201   if (argc<idx+1) {
202     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
203     return wrapper_exit_code;
204   }
205
206   Echroot(".");
207   Echdir("/");
208
209   for (cmd=COMMANDS+0; cmd->cmd!=0; ++cmd) {
210     if (strcmp(cmd->cmd, argv[idx])==0)
211       return cmd->handler(argc-idx, argv+idx);
212   }
213
214   WRITE_MSG(2, "Invalid command '");
215   WRITE_STR(2, argv[idx]);
216   WRITE_MSG(2, "'; try '--help' for more information\n");
217
218   return wrapper_exit_code;
219 }