added SYSINFO command
[util-vserver.git] / util-vserver / src / vserver-info.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2003 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 "pathconfig.h"
24 #include "util.h"
25
26 #include "internal.h"
27 #include "vserver.h"
28
29 #include <stdlib.h>
30 #include <getopt.h>
31 #include <assert.h>
32 #include <stdbool.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <sys/utsname.h>
36
37 #define ENSC_WRAPPERS_FCNTL     1
38 #define ENSC_WRAPPERS_IO        1
39 #define ENSC_WRAPPERS_UNISTD    1
40 #include <wrappers.h>
41
42 typedef enum { tgNONE,tgCONTEXT, tgRUNNING,
43                tgVDIR, tgNAME, tgCFGDIR, tgAPPDIR,
44                tgAPIVER,
45                tgINITPID, tgINITPID_PID,
46                tgXID, tgUTS, tgSYSINFO,
47 }       VserverTag;
48
49 static struct {
50     char const * const  tag;
51     VserverTag const    val;
52     char const * const  descr;
53 }  const TAGS[] = {
54   { "CONTEXT", tgCONTEXT, "the current and/or assigned context" },
55   { "RUNNING", tgRUNNING, "gives out '1' when vserver is running; else, it fails without output" },
56   { "VDIR",    tgVDIR,    "gives out the root-directory of the vserver" },
57   { "NAME",    tgNAME,    "gives out the name of the vserver" },
58   { "CFGDIR",  tgCFGDIR,  "gives out the configuration directory of the vserver" },
59   { "APPDIR",  tgAPPDIR,  "gives out the name of the toplevel application cfgdir" },
60   { "INITPID",     tgINITPID,     "gives out the initpid of the given context" },
61   { "INITPID_PID", tgINITPID_PID, "gives out the initpid of the given pid" },
62   { "XID",         tgXID,         "gives out the context-id of the given pid" },
63   { "APIVER",      tgAPIVER,      "gives out the version of the kernel API" },
64   { "UTS",         tgUTS,         ("gives out an uts-entry; possible entries are "
65                                    "context, sysname, nodename, release, version, "
66                                    "machine and domainname") },
67   { "SYSINFO",     tgSYSINFO,     "gives out information about the systen" },
68 };
69
70 int wrapper_exit_code = 1;
71
72 static struct option const
73 CMDLINE_OPTIONS[] = {
74   { "help",     no_argument,  0, 'h' },
75   { "version",  no_argument,  0, 'v' },
76   { 0,0,0,0 }
77 };
78
79
80 static void
81 showHelp(int fd, char const *cmd, int res)
82 {
83   WRITE_MSG(fd, "Usage:  ");
84   WRITE_STR(fd, cmd);
85   WRITE_MSG(fd,
86             " [-ql] <vserver>|<pid>|<context> <tag>\n"
87             "Please report bugs to " PACKAGE_BUGREPORT "\n");
88   exit(res);
89 }
90
91 static void
92 showVersion()
93 {
94   WRITE_MSG(1,
95             "vserver-info " VERSION " -- returns information about vservers\n"
96             "This program is part of " PACKAGE_STRING "\n\n"
97             "Copyright (C) 2003 Enrico Scholz\n"
98             VERSION_COPYRIGHT_DISCLAIMER);
99   exit(0);
100 }
101
102 static void
103 showTags()
104 {
105   char const *          delim = "";
106   size_t        i;
107
108   WRITE_MSG(1, "Valid tags are: ");
109   for (i=0; i<DIM_OF(TAGS); ++i) {
110     WRITE_STR(1, delim);
111     WRITE_STR(1, TAGS[i].tag);
112
113     delim = ", ";
114   }
115   WRITE_MSG(1, "\n");
116   exit(0);
117 }
118
119 static VserverTag
120 stringToTag(char const *str)
121 {
122   size_t        i;
123   for (i=0; i<DIM_OF(TAGS); ++i)
124     if (strcmp(TAGS[i].tag, str)==0) return TAGS[i].val;
125
126   return tgNONE;
127 }
128
129 static vc_uts_type
130 utsText2Tag(char const *str)
131 {
132   if      (strcmp(str, "context")   ==0) return vcVHI_CONTEXT;
133   else if (strcmp(str, "sysname")   ==0) return vcVHI_SYSNAME;
134   else if (strcmp(str, "nodename")  ==0) return vcVHI_NODENAME;
135   else if (strcmp(str, "release")   ==0) return vcVHI_RELEASE;
136   else if (strcmp(str, "version")   ==0) return vcVHI_VERSION;
137   else if (strcmp(str, "machine")   ==0) return vcVHI_MACHINE;
138   else if (strcmp(str, "domainname")==0) return vcVHI_DOMAINNAME;
139   else {
140     WRITE_MSG(2, "Unknown UTS tag\n");
141     exit(1);
142   }
143 }
144
145 static char *
146 getAPIVer(char *buf)
147 {
148   int           v = vc_get_version();
149   size_t        l;
150   
151   if (v==-1) return 0;
152
153   
154   l = utilvserver_fmt_xulong(0, (unsigned int)v);
155   memcpy(buf, "0x00000000", 10);
156   utilvserver_fmt_xulong(buf+2+8-l, (unsigned int)v);
157
158   return buf;
159 }
160
161 static char *
162 getXid(char *buf, char const *vserver)
163 {
164   pid_t         pid = atoi(vserver);
165   xid_t         xid = vc_get_task_xid(pid);
166
167   if (xid==VC_NOCTX) perror("vc_get_task_xid()");
168   else {
169     utilvserver_fmt_long(buf, xid);
170     return buf;
171   }
172
173   return 0;
174 }
175
176 static char *
177 getInitPid(char *buf, xid_t xid)
178 {
179   struct vc_vx_info             info;
180   
181   if (vc_get_vx_info(xid, &info)==-1) perror("vc_get_vx_info()");
182   else {
183     utilvserver_fmt_long(buf, info.xid);
184     return buf;
185   }
186
187   return 0;
188 }
189
190 static char *
191 getInitPidPid(char *buf, char const *vserver)
192 {
193   struct vc_vx_info     info;
194   pid_t                 pid = atoi(vserver);
195   xid_t                 xid = vc_get_task_xid(pid);
196
197   if (xid==VC_NOCTX) perror("vc_get_task_xid()");
198   else if (vc_get_vx_info(xid, &info)==-1) perror("vc_get_vx_info()");
199   else {
200     utilvserver_fmt_long(buf, info.xid);
201     return buf;
202   }
203
204   return 0;
205 }
206
207 static char *
208 getUTS(char *buf, xid_t xid, size_t argc, char * argv[])
209 {
210   if (argc>0) {
211     vc_uts_type type = utsText2Tag(argv[0]);
212     if (vc_get_vhi_name(xid, type, buf, sizeof(buf)-1)==-1)
213       perror("vc_get_vhi_name()");
214     else
215       return buf;
216   }
217   else {
218     bool                is_passed = false;
219     char                tmp[128];
220 #define APPEND_UTS(TYPE)                                                \
221     (((vc_get_vhi_name(xid, TYPE, tmp, sizeof(tmp)-1)!=-1) && (strcat(buf, tmp), strcat(buf, " "), is_passed=true)) || \
222      (strcat(buf, "??? ")))
223
224     if (APPEND_UTS(vcVHI_CONTEXT) &&
225         APPEND_UTS(vcVHI_SYSNAME) &&
226         APPEND_UTS(vcVHI_NODENAME) &&
227         APPEND_UTS(vcVHI_RELEASE) &&
228         APPEND_UTS(vcVHI_VERSION) &&
229         APPEND_UTS(vcVHI_MACHINE) &&
230         APPEND_UTS(vcVHI_DOMAINNAME) &&
231         is_passed)
232       return buf;
233
234     perror("vc_get_vhi_name()");
235 #undef APPEND_UTS
236   }
237
238   return 0;
239 }
240
241 static int
242 printSysInfo(char *buf)
243 {
244   int                   fd = open(PKGLIBDIR "/FEATURES.txt", O_RDONLY);
245   struct utsname        uts;
246
247   if (uname(&uts)==-1)
248     perror("uname()");
249   else {
250     WRITE_MSG(1,
251               "Versions:\n"
252               "                   Kernel: ");
253     WRITE_STR(1, uts.release);
254     WRITE_MSG(1, "\n"
255               "                   VS-API: ");
256
257     memset(buf, 0, 128);
258     if (getAPIVer(buf)) WRITE_STR(1, buf);
259     else                WRITE_MSG(1, "???");
260     
261     WRITE_MSG(1, "\n"
262               "             util-vserver: " PACKAGE_VERSION "; " __DATE__ ", " __TIME__"\n"
263               "\n");
264   }
265
266   if (fd==-1)
267     WRITE_MSG(1, "FEATURES.txt not found\n");
268   else {
269     off_t               l  = Elseek(fd, 0, SEEK_END);
270     Elseek(fd, 0, SEEK_SET);
271     {
272       char              buf[l];
273       EreadAll(fd, buf, l);
274       EwriteAll(1, buf, l);
275     }
276     Eclose(fd);
277   }
278
279   return EXIT_SUCCESS;
280 }
281
282 static char *
283 getContext(char *buf, char const *vserver)
284 {
285   xid_t         xid = vc_getVserverCtx(vserver, vcCFG_AUTO, true, 0);
286   if (xid==VC_NOCTX) return 0;
287   
288   utilvserver_fmt_long(buf, xid);
289   return buf;
290 }
291
292 static int
293 execQuery(char const *vserver, VserverTag tag, int argc, char *argv[])
294 {
295   char const *          res = 0;
296   char                  buf[sizeof(xid_t)*4 + 1024];
297   xid_t                 xid = *vserver!='\0' ? (xid_t)(atoi(vserver)) : VC_SAMECTX;
298
299   memset(buf, 0, sizeof buf);
300   switch (tag) {
301     case tgNAME         :  res = vc_getVserverName(vserver, vcCFG_AUTO); break;
302     case tgVDIR         :
303       res = vc_getVserverVdir(vserver, vcCFG_AUTO, argc>0 && atoi(argv[0]));
304       break;
305     case tgCFGDIR       :  res = vc_getVserverCfgDir(vserver, vcCFG_AUTO);     break;
306     case tgAPPDIR       :
307       res = vc_getVserverAppDir(vserver, vcCFG_AUTO, argc==0 ? "" : argv[0]);
308       break;
309       
310     case tgRUNNING      :
311       res = (vc_getVserverCtx(vserver, vcCFG_AUTO, false, 0)==VC_NOCTX) ? 0 : "1";
312       break;
313
314     case tgCONTEXT      :  res = getContext(buf, vserver);     break;
315     case tgXID          :  res = getXid(buf, vserver);         break;
316     case tgINITPID      :  res = getInitPid(buf, xid);         break;
317     case tgINITPID_PID  :  res = getInitPidPid(buf, vserver);  break;
318     case tgAPIVER       :  res = getAPIVer(buf);               break;
319     case tgUTS          :  res = getUTS(buf, xid, argc, argv); break;
320     case tgSYSINFO      :  return printSysInfo(buf);           break;
321     
322     default             :  assert(false); abort();  // TODO
323   }
324
325   if (res==0) return EXIT_FAILURE;
326   WRITE_STR(1, res);
327   WRITE_MSG(1, "\n");
328   return EXIT_SUCCESS;
329 }
330
331 int main(int argc, char *argv[])
332 {
333   bool          quiet = false;
334   char const *  vserver;
335   VserverTag    tag;
336   
337   while (1) {
338     int         c = getopt_long(argc, argv, "ql", CMDLINE_OPTIONS, 0);
339     if (c==-1) break;
340
341     switch (c) {
342       case 'h'          :  showHelp(1, argv[0], 0);
343       case 'v'          :  showVersion();
344       case 'l'          :  showTags();
345       case 'q'          :  quiet = true; break;
346       default           :
347         WRITE_MSG(2, "Try '");
348         WRITE_STR(2, argv[0]);
349         WRITE_MSG(2, " --help\" for more information.\n");
350         exit(1);
351         break;
352     }
353   }
354
355   if (optind+2>argc) {
356     WRITE_MSG(2, "No vserver or tag give; please try '--help' for more information.\n");
357     exit(1);
358   }
359
360   vserver = argv[optind];
361   tag     = stringToTag(argv[optind+1]);
362
363   if (tag==tgNONE) {
364     WRITE_MSG(2, "Unknown tag; use '-l' to get list of valid tags\n");
365     exit(1);
366   }
367
368   if (quiet) {
369     int         fd = Eopen("/dev/null", O_WRONLY, 0644);
370     Edup2(fd, 1);
371     Eclose(fd);
372   }
373
374   return execQuery(vserver, tag, argc-(optind+2), argv+optind+2);
375 }