1 | /* |
---|
2 | * ---------------------------------------------------------------------- |
---|
3 | * Rappture::sysinfo |
---|
4 | * |
---|
5 | * This is an interface to the system sysinfo() function, which gives |
---|
6 | * information about system load averages, use of virtual memory, etc. |
---|
7 | * ====================================================================== |
---|
8 | * AUTHOR: Michael McLennan, Purdue University |
---|
9 | * Copyright (c) 2004-2006 Purdue Research Foundation |
---|
10 | * |
---|
11 | * See the file "license.terms" for information on usage and |
---|
12 | * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
13 | * ====================================================================== |
---|
14 | */ |
---|
15 | #include "config.h" |
---|
16 | #include <tcl.h> |
---|
17 | #include <stdlib.h> |
---|
18 | #include <stddef.h> |
---|
19 | #include <string.h> |
---|
20 | |
---|
21 | static Tcl_CmdProc RpSysinfoCmd; |
---|
22 | |
---|
23 | |
---|
24 | /* |
---|
25 | * ------------------------------------------------------------------------ |
---|
26 | * RpSysinfo_Init() |
---|
27 | * |
---|
28 | * Called in Rappture_Init() to initialize the commands defined |
---|
29 | * in this file. |
---|
30 | * ------------------------------------------------------------------------ |
---|
31 | */ |
---|
32 | int |
---|
33 | RpSysinfo_Init(interp) |
---|
34 | Tcl_Interp *interp; /* interpreter being initialized */ |
---|
35 | { |
---|
36 | /* install the sysinfo command */ |
---|
37 | Tcl_CreateCommand(interp, "::Rappture::sysinfo", RpSysinfoCmd, |
---|
38 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
39 | |
---|
40 | return TCL_OK; |
---|
41 | } |
---|
42 | |
---|
43 | #ifndef HAVE_SYSINFO |
---|
44 | |
---|
45 | static int |
---|
46 | RpSysinfoCmd(cdata, interp, argc, argv) |
---|
47 | ClientData cdata; /* not used */ |
---|
48 | Tcl_Interp *interp; /* interpreter handling this request */ |
---|
49 | int argc; /* number of command line args */ |
---|
50 | CONST84 char *argv[]; /* strings for command line args */ |
---|
51 | { |
---|
52 | Tcl_SetResult(interp, "command not implemented: no sysinfo", TCL_STATIC); |
---|
53 | return TCL_ERROR; |
---|
54 | } |
---|
55 | |
---|
56 | #else |
---|
57 | |
---|
58 | #ifdef HAVE_SYS_SYSINFO_H |
---|
59 | #include <sys/sysinfo.h> |
---|
60 | #endif /* HAVE_SYS_SYSINFO_H */ |
---|
61 | |
---|
62 | #define RP_SLOT_LONG 1 |
---|
63 | #define RP_SLOT_ULONG 2 |
---|
64 | #define RP_SLOT_USHORT 3 |
---|
65 | #define RP_SLOT_LOAD 4 |
---|
66 | |
---|
67 | struct rpSysinfoList { |
---|
68 | const char *name; /* Name of this system parameter */ |
---|
69 | int type; /* Parameter type (long, unsigned long, |
---|
70 | * etc.) */ |
---|
71 | int offset; /* Offset into sysinfo struct */ |
---|
72 | }; |
---|
73 | |
---|
74 | #ifdef offsetof |
---|
75 | #define Offset(type, field) ((int) offsetof(type, field)) |
---|
76 | #else |
---|
77 | #define Offset(type, field) ((int) ((char *) &((type *) 0)->field)) |
---|
78 | #endif |
---|
79 | |
---|
80 | static struct rpSysinfoList RpSysinfoList [] = { |
---|
81 | {"freeram", RP_SLOT_ULONG, Offset(struct sysinfo, freeram)}, |
---|
82 | {"freeswap", RP_SLOT_ULONG, Offset(struct sysinfo, freeswap)}, |
---|
83 | {"load1", RP_SLOT_LOAD, Offset(struct sysinfo, loads[0])}, |
---|
84 | {"load5", RP_SLOT_LOAD, Offset(struct sysinfo, loads[1])}, |
---|
85 | {"load15", RP_SLOT_LOAD, Offset(struct sysinfo, loads[2])}, |
---|
86 | {"procs", RP_SLOT_USHORT, Offset(struct sysinfo, procs)}, |
---|
87 | {"totalram", RP_SLOT_ULONG, Offset(struct sysinfo, totalram)}, |
---|
88 | {"totalswap", RP_SLOT_ULONG, Offset(struct sysinfo, totalswap)}, |
---|
89 | {"uptime", RP_SLOT_LONG, Offset(struct sysinfo, uptime)}, |
---|
90 | {NULL, 0, 0} |
---|
91 | }; |
---|
92 | |
---|
93 | static Tcl_Obj* RpSysinfoValue(struct sysinfo *sinfo, int idx); |
---|
94 | |
---|
95 | /* |
---|
96 | * ------------------------------------------------------------------------ |
---|
97 | * RpSysinfoCmd() |
---|
98 | * |
---|
99 | * Invoked whenever someone uses the "sysinfo" command to get info |
---|
100 | * about system load. Handles the following syntax: |
---|
101 | * |
---|
102 | * sysinfo ?<keyword>...? |
---|
103 | * |
---|
104 | * With no extra args, it returns a list of the form "key1 val1 key2 |
---|
105 | * val2 ..." with all known system info. Otherwise, it treats each |
---|
106 | * argument as a desired keyword and returns only the values for the |
---|
107 | * specified keywords. |
---|
108 | * |
---|
109 | * Returns TCL_OK on success, and TCL_ERROR (along with an error |
---|
110 | * message in the interpreter) if anything goes wrong. |
---|
111 | * ------------------------------------------------------------------------ |
---|
112 | */ |
---|
113 | static int |
---|
114 | RpSysinfoCmd(cdata, interp, argc, argv) |
---|
115 | ClientData cdata; /* not used */ |
---|
116 | Tcl_Interp *interp; /* interpreter handling this request */ |
---|
117 | int argc; /* number of command line args */ |
---|
118 | CONST84 char *argv[]; /* strings for command line args */ |
---|
119 | { |
---|
120 | char c; |
---|
121 | int n, i; |
---|
122 | struct sysinfo info; |
---|
123 | Tcl_Obj *resultPtr; |
---|
124 | |
---|
125 | if (sysinfo(&info) < 0) { |
---|
126 | Tcl_SetResult(interp, "oops! can't query system info", TCL_STATIC); |
---|
127 | return TCL_ERROR; |
---|
128 | } |
---|
129 | resultPtr = Tcl_GetObjResult(interp); |
---|
130 | |
---|
131 | /* |
---|
132 | * If no args are given, return all info in the form: |
---|
133 | * key1 value1 key2 value2 ... |
---|
134 | */ |
---|
135 | if (argc < 2) { |
---|
136 | for (i=0; RpSysinfoList[i].name != NULL; i++) { |
---|
137 | Tcl_ListObjAppendElement(interp, resultPtr, |
---|
138 | Tcl_NewStringObj(RpSysinfoList[i].name, -1)); |
---|
139 | Tcl_ListObjAppendElement(interp, resultPtr, |
---|
140 | RpSysinfoValue(&info, i)); |
---|
141 | } |
---|
142 | return TCL_OK; |
---|
143 | } |
---|
144 | |
---|
145 | /* |
---|
146 | * Query and return each of the specified values. |
---|
147 | */ |
---|
148 | for (n=1; n < argc; n++) { |
---|
149 | c = *argv[n]; |
---|
150 | for (i=0; RpSysinfoList[i].name != NULL; i++) { |
---|
151 | if (c == *RpSysinfoList[i].name |
---|
152 | && strcmp(argv[n], RpSysinfoList[i].name) == 0) { |
---|
153 | break; |
---|
154 | } |
---|
155 | } |
---|
156 | |
---|
157 | /* couldn't find the name in the list? then return an error */ |
---|
158 | if (RpSysinfoList[i].name == NULL) { |
---|
159 | Tcl_ResetResult(interp); |
---|
160 | Tcl_AppendResult(interp, "bad parameter \"", |
---|
161 | argv[n], "\": should be one of ", (char*)NULL); |
---|
162 | for (i=0; RpSysinfoList[i].name != NULL; i++) { |
---|
163 | Tcl_AppendResult(interp, (i == 0) ? "" : ", ", |
---|
164 | RpSysinfoList[i].name, (char*)NULL); |
---|
165 | } |
---|
166 | return TCL_ERROR; |
---|
167 | } |
---|
168 | Tcl_ListObjAppendElement(interp, resultPtr, RpSysinfoValue(&info, i)); |
---|
169 | } |
---|
170 | return TCL_OK; |
---|
171 | } |
---|
172 | |
---|
173 | /* |
---|
174 | * ------------------------------------------------------------------------ |
---|
175 | * RpSysinfoValue() |
---|
176 | * |
---|
177 | * Returns the value for a desired system info parameter, specified as |
---|
178 | * as offset into the global RpSysinfoList array. The value is returned |
---|
179 | * as a Tcl_Obj, which should be used or freed by the caller. |
---|
180 | * ------------------------------------------------------------------------ |
---|
181 | */ |
---|
182 | static Tcl_Obj* |
---|
183 | RpSysinfoValue(sinfo, idx) |
---|
184 | struct sysinfo *sinfo; /* system load info */ |
---|
185 | int idx; /* index for desired sysinfo value */ |
---|
186 | { |
---|
187 | char *ptr; |
---|
188 | int ival; long lval; double dval, loadscale; |
---|
189 | ptr = (char*)sinfo + RpSysinfoList[idx].offset; |
---|
190 | |
---|
191 | switch (RpSysinfoList[idx].type) { |
---|
192 | case RP_SLOT_LONG: |
---|
193 | return Tcl_NewLongObj(*(long*)ptr); |
---|
194 | break; |
---|
195 | case RP_SLOT_ULONG: |
---|
196 | lval = *(unsigned long*)ptr; |
---|
197 | return Tcl_NewLongObj(lval); |
---|
198 | break; |
---|
199 | case RP_SLOT_USHORT: |
---|
200 | ival = *(unsigned short*)ptr; |
---|
201 | return Tcl_NewIntObj(ival); |
---|
202 | break; |
---|
203 | case RP_SLOT_LOAD: |
---|
204 | loadscale = (double)(1 << SI_LOAD_SHIFT); |
---|
205 | dval = (double)(*(unsigned long*)ptr)/loadscale; |
---|
206 | return Tcl_NewDoubleObj(dval); |
---|
207 | break; |
---|
208 | } |
---|
209 | return NULL; |
---|
210 | } |
---|
211 | |
---|
212 | #endif /*HAVE_SYSINFO*/ |
---|