substitute @TAR@
[util-vserver.git] / util-vserver / 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 xid_t
176 str2xid(char const *str)
177 {
178   if (strcmp(str,"self")==0) return Evc_get_task_xid(0);
179   else                       return atoi(str);
180 }
181
182 static size_t
183 findUtsIdx(char const *str, size_t len)
184 {
185   size_t                i;
186   for (i=0; i<DIM_OF(UTS_STRINGS); ++i)
187     if (UTS_STRINGS[i]!=0 && strncasecmp(UTS_STRINGS[i], str, len)==0)
188       return i;
189
190   WRITE_MSG(2, "Tag '");
191   write(2, str, len);
192   WRITE_STR(2, "' not recognized\n");
193   exit(wrapper_exit_code);
194 }
195
196 static void
197 registerValue(char const *str, struct Tag tags[DIM_OF(UTS_MAPPING)])
198 {
199   char const *  ptr = strchr(str, '=');
200   size_t        idx;
201   
202   if (ptr==0) ptr = str + strlen(str);
203   assert(*ptr=='=' || *ptr=='\0');
204
205   idx = findUtsIdx(str, ptr-str);
206
207   if (*ptr=='=') ++ptr;
208   tags[idx].is_set = true;
209   tags[idx].value  = ptr;
210 }
211
212 static void
213 printUtsValue(xid_t xid, int val)
214 {
215   char  buf[128];
216   if (vc_get_vhi_name(xid, val, buf, sizeof(buf)-1)==-1)
217     WRITE_MSG(1, "???");
218   else
219     WRITE_STR(1, buf);
220   
221 }
222
223 int main(int argc, char *argv[])
224 {
225   struct Arguments      args = {
226     .tags        = { [0] = {false,0} },
227     .do_set      = false,
228     .dir         = 0,
229     .is_missingok= false,
230     .xid         = VC_NOCTX,
231   };
232   size_t                i;
233
234   assert(DIM_OF(UTS_MAPPING) == DIM_OF(args.tags));
235   
236   while (1) {
237     int         c = getopt_long(argc, argv, "+gst:", CMDLINE_OPTIONS, 0);
238     if (c==-1) break;
239
240     switch (c) {
241       case CMD_HELP     :  showHelp(1, argv[0], 0);
242       case CMD_VERSION  :  showVersion();
243       case CMD_DIR      :  args.dir          = optarg; break;
244       case CMD_MISSINGOK:  args.is_missingok = true;   break;
245       case 'g'          :  args.do_set       = false;  break;
246       case 's'          :  args.do_set       = true;   break;
247       case 'x'          :  args.xid          = str2xid(optarg); break;
248       case 't'          :  registerValue(optarg, args.tags);    break;
249       default           :
250         WRITE_MSG(2, "Try '");
251         WRITE_STR(2, argv[0]);
252         WRITE_MSG(2, " --help\" for more information.\n");
253         return EXIT_FAILURE;
254         break;
255     }
256   }
257
258   if (args.xid==VC_NOCTX) {
259     WRITE_MSG(2, "No context specified; try '--help' for more information\n");
260     exit(wrapper_exit_code);
261   }
262
263   if (args.dir)
264     setFromDir(args.dir, args.is_missingok, args.xid);
265   else if (args.do_set) {
266     for (i=0; i<DIM_OF(args.tags); ++i) {
267       if (!args.tags[i].is_set) continue;
268       Evc_set_vhi_name(args.xid, i, args.tags[i].value, strlen(args.tags[i].value));
269     }
270   }
271   else if (optind==argc) {
272     char const *        delim = "";
273     for (i=0; i<DIM_OF(UTS_MAPPING); ++i) {
274       WRITE_STR(1, delim);
275       printUtsValue(args.xid, i);
276       delim = " ";
277     }
278     WRITE_MSG(1, "\n");
279
280     return EXIT_SUCCESS;
281   }
282   else {
283     char const *        delim = "";
284     while (optind <argc) {
285       int               idx = findUtsIdx(argv[optind], strlen(argv[optind]));
286       WRITE_STR(1, delim);
287       printUtsValue(args.xid, idx);
288       delim = " ";
289
290       ++optind;
291     }
292     WRITE_MSG(1, "\n");
293     
294     return EXIT_SUCCESS;
295   }
296
297   if (optind<argc)
298     EexecvpD(argv[optind], argv+optind);
299
300   return wrapper_exit_code;
301 }