Add /usr/bin to exception list, to make sure we keep the /usr mount around.
[util-vserver.git] / src / vuname.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2004 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 "vserver.h"
24 #include "util.h"
25
26 #include <getopt.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <libgen.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <strings.h>
35
36 #define ENSC_WRAPPERS_PREFIX    "vuname: "
37 #define ENSC_WRAPPERS_UNISTD    1
38 #define ENSC_WRAPPERS_IO        1
39 #define ENSC_WRAPPERS_VSERVER   1
40 #include <wrappers.h>
41
42 #define CMD_HELP                0x1000
43 #define CMD_VERSION             0x1001
44 #define CMD_DIR                 0x4007
45 #define CMD_MISSINGOK           0x4008
46
47 int                     wrapper_exit_code = 255;
48
49 static vc_uts_type const        UTS_MAPPING[7] = {
50   vcVHI_CONTEXT, vcVHI_SYSNAME, vcVHI_NODENAME,
51   vcVHI_RELEASE, vcVHI_VERSION, vcVHI_MACHINE,
52   vcVHI_DOMAINNAME };
53
54 #define DECL(UTS) [vcVHI_ ## UTS] = #UTS
55 static char const * const       UTS_STRINGS[] = {
56   DECL(CONTEXT), DECL(SYSNAME), DECL(NODENAME),
57   DECL(RELEASE), DECL(VERSION), DECL(MACHINE),
58   DECL(DOMAINNAME)
59 };
60
61 struct Tag {
62     bool                is_set;
63     char const *        value;
64 };
65
66 struct Arguments {
67     struct Tag          tags[DIM_OF(UTS_MAPPING)];
68     xid_t               xid;
69     bool                do_set;
70     char const *        dir;
71     bool                is_missingok;
72 };
73
74 static struct option const
75 CMDLINE_OPTIONS[] = {
76   { "help",        no_argument,       0, CMD_HELP },
77   { "version",     no_argument,       0, CMD_VERSION },
78   { "xid",         required_argument, 0, 'x' },
79   { "set",         no_argument,       0, 's' },
80   { "get",         no_argument,       0, 'g' },
81   { "dir",         required_argument, 0, CMD_DIR },
82   { "missingok",   no_argument,       0, CMD_MISSINGOK },
83   { 0,0,0,0 }
84 };
85
86 static void
87 showHelp(int fd, char const *cmd, int res)
88 {
89   VSERVER_DECLARE_CMD(cmd);
90   
91   WRITE_MSG(fd, "Usage:  ");
92   WRITE_STR(fd, cmd);
93   WRITE_MSG(fd,
94             "  [-g] --xid <xid> <TAG>*\n"
95             "    or  ");
96   WRITE_STR(fd, cmd);
97   WRITE_MSG(fd,
98             "  -s --xid <xid> -t <TAG>=<VALUE> [--] [<command> <args>*]\n"
99             "    or  ");
100   WRITE_STR(fd, cmd);
101   WRITE_MSG(fd,     
102             "  --dir <dir> --xid <xid> [--missingok] [--] [<command> <args>*]\n\n"
103             " Options:\n"
104             "   -g           ...  get and print the value\n"
105             "   -s           ...  set the value\n\n"
106             "   --xid <xid>  ...  operate on this context; 'self' means the current one\n"
107             "   -t <TAG>=<VALUE>\n"
108             "                ...  set <TAG> to <VALUE>; this option can be repeated multiple time\n"
109             "   --dir <dir>  ...  read values from files in <dir>. These files must\n"
110             "                     have a valid TAG as their name\n"
111             "   --missingok  ...  do not fail when the <DIR> from '--dir' does not exist.\n"
112             "\n"
113             " Possible values for TAG are:\n"
114             "   context, sysname, nodename, release, version, machine, domainname\n"
115             "\n"
116             "Please report bugs to " PACKAGE_BUGREPORT "\n");
117   exit(res);
118 }
119
120 static void
121 showVersion()
122 {
123   WRITE_MSG(1,
124             "vuname " VERSION " -- modifies and shows uname entries of vserver contexts\n"
125             "This program is part of " PACKAGE_STRING "\n\n"
126             "Copyright (C) 2004 Enrico Scholz\n"
127             VERSION_COPYRIGHT_DISCLAIMER);
128   exit(0);
129 }
130
131 static void
132 setFromDir(char const *pathname, bool is_missingok, xid_t xid)
133 {
134   struct stat           st;
135   size_t                i;
136   size_t                l_pathname = strlen(pathname);
137   char                  buf[l_pathname + sizeof("/domainname") + 32];
138   
139   if (stat(pathname, &st)==-1) {
140     if (errno==ENOENT && is_missingok) return;
141     PERROR_Q(ENSC_WRAPPERS_PREFIX "fstat", pathname);
142     exit(wrapper_exit_code);
143   }
144
145   memcpy(buf, pathname, l_pathname);
146   if (l_pathname>0 && pathname[l_pathname-1]!='/')
147     buf[l_pathname++] = '/';
148   
149   for (i=0; i<DIM_OF(UTS_STRINGS); ++i) {
150     char *      ptr   = buf+l_pathname;
151     int         fd;
152
153     // ignore unimplemented uts-names
154     if (UTS_STRINGS[i]==0) continue;
155     strcpy(ptr, UTS_STRINGS[i]);
156     for (;*ptr;++ptr) *ptr = tolower(*ptr);
157     fd = open(buf, O_RDONLY);
158     if (fd!=-1) {
159       size_t    l = Elseek(fd, 0, SEEK_END);
160       char      name[l+1];
161       Elseek(fd,0,SEEK_SET);
162       EreadAll(fd, name, l);
163       while (l>0 && name[l-1]=='\n') --l;
164       name[l] = '\0';
165       Eclose(fd);
166
167       if (vc_set_vhi_name(xid, (vc_uts_type)(i), name, l)==-1) {
168         PERROR_U(ENSC_WRAPPERS_PREFIX "vc_set_vhi_name", UTS_STRINGS[i]);
169         exit(wrapper_exit_code);
170       }
171     }
172   }
173 }
174
175 static size_t
176 findUtsIdx(char const *str, size_t len)
177 {
178   size_t                i;
179   for (i=0; i<DIM_OF(UTS_STRINGS); ++i)
180     if (UTS_STRINGS[i]!=0 && strncasecmp(UTS_STRINGS[i], str, len)==0)
181       return i;
182
183   WRITE_MSG(2, "Tag '");
184   Vwrite   (2, str, len);
185   WRITE_STR(2, "' not recognized\n");
186   exit(wrapper_exit_code);
187 }
188
189 static void
190 registerValue(char const *str, struct Tag tags[DIM_OF(UTS_MAPPING)])
191 {
192   char const *  ptr = strchr(str, '=');
193   size_t        idx;
194   
195   if (ptr==0) ptr = str + strlen(str);
196   assert(*ptr=='=' || *ptr=='\0');
197
198   idx = findUtsIdx(str, ptr-str);
199
200   if (*ptr=='=') ++ptr;
201   tags[idx].is_set = true;
202   tags[idx].value  = ptr;
203 }
204
205 static void
206 printUtsValue(xid_t xid, int val)
207 {
208   char  buf[128];
209   if (vc_get_vhi_name(xid, val, buf, sizeof(buf)-1)==-1)
210     WRITE_MSG(1, "???");
211   else
212     WRITE_STR(1, buf);
213   
214 }
215
216 int main(int argc, char *argv[])
217 {
218   struct Arguments      args = {
219     .tags        = { [0] = {false,0} },
220     .do_set      = false,
221     .dir         = 0,
222     .is_missingok= false,
223     .xid         = VC_NOCTX,
224   };
225   size_t                i;
226
227   assert(DIM_OF(UTS_MAPPING) == DIM_OF(args.tags));
228   
229   while (1) {
230     int         c = getopt_long(argc, argv, "+gst:", CMDLINE_OPTIONS, 0);
231     if (c==-1) break;
232
233     switch (c) {
234       case CMD_HELP     :  showHelp(1, argv[0], 0);
235       case CMD_VERSION  :  showVersion();
236       case CMD_DIR      :  args.dir          = optarg; break;
237       case CMD_MISSINGOK:  args.is_missingok = true;   break;
238       case 'g'          :  args.do_set       = false;  break;
239       case 's'          :  args.do_set       = true;   break;
240       case 'x'          :  args.xid = Evc_xidopt2xid(optarg,true); break;
241       case 't'          :  registerValue(optarg, args.tags);       break;
242       default           :
243         WRITE_MSG(2, "Try '");
244         WRITE_STR(2, argv[0]);
245         WRITE_MSG(2, " --help' for more information.\n");
246         return EXIT_FAILURE;
247         break;
248     }
249   }
250
251   if (args.xid==VC_NOCTX) {
252     WRITE_MSG(2, "No context specified; try '--help' for more information\n");
253     exit(wrapper_exit_code);
254   }
255
256   if (args.dir)
257     setFromDir(args.dir, args.is_missingok, args.xid);
258   else if (args.do_set) {
259     for (i=0; i<DIM_OF(args.tags); ++i) {
260       if (!args.tags[i].is_set) continue;
261       Evc_set_vhi_name(args.xid, i, args.tags[i].value, strlen(args.tags[i].value));
262     }
263   }
264   else if (optind==argc) {
265     char const *        delim = "";
266     for (i=0; i<DIM_OF(UTS_MAPPING); ++i) {
267       WRITE_STR(1, delim);
268       printUtsValue(args.xid, i);
269       delim = " ";
270     }
271     WRITE_MSG(1, "\n");
272
273     return EXIT_SUCCESS;
274   }
275   else {
276     char const *        delim = "";
277     while (optind <argc) {
278       int               idx = findUtsIdx(argv[optind], strlen(argv[optind]));
279       WRITE_STR(1, delim);
280       printUtsValue(args.xid, idx);
281       delim = " ";
282
283       ++optind;
284     }
285     WRITE_MSG(1, "\n");
286     
287     return EXIT_SUCCESS;
288   }
289
290   if (optind<argc)
291     EexecvpD(argv[optind], argv+optind);
292
293   return wrapper_exit_code;
294 }