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