merge from 2.2
[metze/samba/wip.git] / source3 / web / statuspage.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.2.
4    web status page
5    Copyright (C) Andrew Tridgell 1997-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "webintl.h"
24
25 #define PIDMAP          struct PidMap
26
27 PIDMAP {
28         PIDMAP  *next, *prev;
29         pid_t   pid;
30         char    *machine;
31 };
32
33 static PIDMAP   *pidmap;
34 static int      PID_or_Machine;         /* 0 = show PID, else show Machine name */
35
36 static pid_t smbd_pid;
37
38 /* from 2nd call on, remove old list */
39 static void initPid2Machine (void)
40 {
41         /* show machine name rather PID on table "Open Files"? */
42         if (PID_or_Machine) {
43                 PIDMAP *p, *q;
44
45                 for (p = pidmap; p != NULL; ) {
46                         DLIST_REMOVE(pidmap, p);
47                         SAFE_FREE(p->machine);
48                         SAFE_FREE(p);
49                 }
50
51                 pidmap = NULL;
52         }
53 }
54
55 /* add new PID <-> Machine name mapping */
56 static void addPid2Machine (pid_t pid, char *machine)
57 {
58         /* show machine name rather PID on table "Open Files"? */
59         if (PID_or_Machine) {
60                 PIDMAP *newmap;
61
62                 if ((newmap = (PIDMAP *) malloc (sizeof (PIDMAP))) == NULL) {
63                         /* XXX need error message for this?
64                            if malloc fails, PID is always shown */
65                         return;
66                 }
67
68                 newmap->pid = pid;
69                 newmap->machine = strdup (machine);
70
71                 DLIST_ADD(pidmap, newmap);
72         }
73 }
74
75 /* lookup PID <-> Machine name mapping */
76 static char *mapPid2Machine (pid_t pid)
77 {
78         static char pidbuf [64];
79         PIDMAP *map;
80
81         /* show machine name rather PID on table "Open Files"? */
82         if (PID_or_Machine) {
83                 for (map = pidmap; map != NULL; map = map->next) {
84                         if (pid == map->pid) {
85                                 if (map->machine == NULL)       /* no machine name */
86                                         break;                  /* show PID */
87
88                                 return map->machine;
89                         }
90                 }
91         }
92
93         /* PID not in list or machine name NULL? return pid as string */
94         snprintf (pidbuf, sizeof (pidbuf) - 1, "%d", pid);
95         return pidbuf;
96 }
97
98 static char *tstring(time_t t)
99 {
100         static pstring buf;
101         pstrcpy(buf, asctime(LocalTime(&t)));
102         all_string_sub(buf," ","&nbsp;",sizeof(buf));
103         return buf;
104 }
105
106 static void print_share_mode(share_mode_entry *e, char *fname)
107 {
108         printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid)));
109         printf("<td>");
110         switch ((e->share_mode>>4)&0xF) {
111         case DENY_NONE: printf(_("DENY_NONE")); break;
112         case DENY_ALL:  printf(_("DENY_ALL   ")); break;
113         case DENY_DOS:  printf(_("DENY_DOS   ")); break;
114         case DENY_READ: printf(_("DENY_READ  ")); break;
115         case DENY_WRITE:printf(_("DENY_WRITE ")); break;
116         }
117         printf("</td>");
118
119         printf("<td>");
120         switch (e->share_mode&0xF) {
121         case 0: printf(_("RDONLY     ")); break;
122         case 1: printf(_("WRONLY     ")); break;
123         case 2: printf(_("RDWR       ")); break;
124         }
125         printf("</td>");
126
127         printf("<td>");
128         if((e->op_type & 
129             (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == 
130            (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
131                 printf(_("EXCLUSIVE+BATCH "));
132         else if (e->op_type & EXCLUSIVE_OPLOCK)
133                 printf(_("EXCLUSIVE       "));
134         else if (e->op_type & BATCH_OPLOCK)
135                 printf(_("BATCH           "));
136         else if (e->op_type & LEVEL_II_OPLOCK)
137                 printf(_("LEVEL_II        "));
138         else
139                 printf(_("NONE            "));
140         printf("</td>");
141
142         printf("<td>%s</td><td>%s</td></tr>\n",
143                fname,tstring(e->time.tv_sec));
144 }
145
146
147 /* kill off any connections chosen by the user */
148 static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void* state)
149 {
150         struct connections_data crec;
151
152         if (dbuf.dsize != sizeof(crec))
153                 return 0;
154
155         memcpy(&crec, dbuf.dptr, sizeof(crec));
156
157         if (crec.cnum == -1 && process_exists(crec.pid)) {
158                 char buf[30];
159                 slprintf(buf,sizeof(buf)-1,"kill_%d", (int)crec.pid);
160                 if (cgi_variable(buf)) {
161                         kill_pid(crec.pid);
162                 }
163         }
164         return 0;
165 }
166
167 /* traversal fn for showing machine connections */
168 static int traverse_fn2(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void* state)
169 {
170         struct connections_data crec;
171
172         if (dbuf.dsize != sizeof(crec))
173                 return 0;
174
175         memcpy(&crec, dbuf.dptr, sizeof(crec));
176         
177         if (crec.cnum != -1 || !process_exists(crec.pid) || (crec.pid == smbd_pid))
178                 return 0;
179
180         addPid2Machine (crec.pid, crec.machine);
181
182         printf("<tr><td>%d</td><td>%s</td><td>%s</td><td>%s</td>\n",
183                (int)crec.pid,
184                crec.machine,crec.addr,
185                tstring(crec.start));
186         if (geteuid() == 0) {
187                 printf("<td><input type=submit value=\"X\" name=\"kill_%d\"></td>\n",
188                        (int)crec.pid);
189         }
190         printf("</tr>\n");
191
192         return 0;
193 }
194
195 /* traversal fn for showing share connections */
196 static int traverse_fn3(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void* state)
197 {
198         struct connections_data crec;
199
200         if (dbuf.dsize != sizeof(crec))
201                 return 0;
202
203         memcpy(&crec, dbuf.dptr, sizeof(crec));
204
205         if (crec.cnum == -1 || !process_exists(crec.pid))
206                 return 0;
207
208         printf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td></tr>\n",
209                crec.name,uidtoname(crec.uid),
210                gidtoname(crec.gid),(int)crec.pid,
211                crec.machine,
212                tstring(crec.start));
213         return 0;
214 }
215
216
217 /* show the current server status */
218 void status_page(void)
219 {
220         char *v;
221         int autorefresh=0;
222         int refresh_interval=30;
223         TDB_CONTEXT *tdb;
224
225         smbd_pid = pidfile_pid("smbd");
226
227         if (cgi_variable("smbd_restart")) {
228                 stop_smbd();
229                 start_smbd();
230         }
231
232         if (cgi_variable("smbd_start")) {
233                 start_smbd();
234         }
235
236         if (cgi_variable("smbd_stop")) {
237                 stop_smbd();
238         }
239
240         if (cgi_variable("nmbd_restart")) {
241                 stop_nmbd();
242                 start_nmbd();
243         }
244         if (cgi_variable("nmbd_start")) {
245                 start_nmbd();
246         }
247
248         if (cgi_variable("nmbd_stop")) {
249                 stop_nmbd();
250         }
251
252         if (cgi_variable("autorefresh")) {
253                 autorefresh = 1;
254         } else if (cgi_variable("norefresh")) {
255                 autorefresh = 0;
256         } else if (cgi_variable("refresh")) {
257                 autorefresh = 1;
258         }
259
260         if ((v=cgi_variable("refresh_interval"))) {
261                 refresh_interval = atoi(v);
262         }
263
264         if (cgi_variable("show_client_in_col_1")) {
265                 PID_or_Machine = 1;
266         }
267
268         tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
269         if (tdb) tdb_traverse(tdb, traverse_fn1, NULL);
270  
271         initPid2Machine ();
272
273         printf("<H2>%s</H2>\n", _("Server Status"));
274
275         printf("<FORM method=post>\n");
276
277         if (!autorefresh) {
278                 printf("<input type=submit value=\"%s\" name=autorefresh>\n", _("Auto Refresh"));
279                 printf("<br>%s", _("Refresh Interval: "));
280                 printf("<input type=text size=2 name=\"refresh_interval\" value=%d>\n", 
281                        refresh_interval);
282         } else {
283                 printf("<input type=submit value=\"%s\" name=norefresh>\n", _("Stop Refreshing"));
284                 printf("<br>%s%d\n", _("Refresh Interval: "), refresh_interval);
285                 printf("<input type=hidden name=refresh value=1>\n");
286         }
287
288         printf("<p>\n");
289
290         if (!tdb) {
291                 /* open failure either means no connections have been
292                    made */
293         }
294
295
296         printf("<table>\n");
297
298         printf("<tr><td>%s</td><td>%s</td></tr>", _("version:"), VERSION);
299
300         fflush(stdout);
301         printf("<tr><td>%s</td><td>%s</td>\n", _("smbd:"), smbd_running()?_("running"):_("not running"));
302         if (geteuid() == 0) {
303             if (smbd_running()) {
304                 printf("<td><input type=submit name=\"smbd_stop\" value=\"%s\"></td>\n", _("Stop smbd"));
305             } else {
306                 printf("<td><input type=submit name=\"smbd_start\" value=\"%s\"></td>\n", _("Start smbd"));
307             }
308             printf("<td><input type=submit name=\"smbd_restart\" value=\"%s\"></td>\n", _("Restart smbd"));
309         }
310         printf("</tr>\n");
311
312         fflush(stdout);
313         printf("<tr><td>%s</td><td>%s</td>\n", _("nmbd:"), nmbd_running()?_("running"):_("not running"));
314         if (geteuid() == 0) {
315             if (nmbd_running()) {
316                 printf("<td><input type=submit name=\"nmbd_stop\" value=\"%s\"></td>\n", _("Stop nmbd"));
317             } else {
318                 printf("<td><input type=submit name=\"nmbd_start\" value=\"%s\"></td>\n", _("Start nmbd"));
319             }
320             printf("<td><input type=submit name=\"nmbd_restart\" value=\"%s\"></td>\n", _("Restart nmbd"));
321         }
322         printf("</tr>\n");
323
324         printf("</table>\n");
325         fflush(stdout);
326
327         printf("<p><h3>%s</h3>\n", _("Active Connections"));
328         printf("<table border=1>\n");
329         printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th>\n", _("PID"), _("Client"), _("IP address"), _("Date"));
330         if (geteuid() == 0) {
331                 printf("<th>%s</th>\n", _("Kill"));
332         }
333         printf("</tr>\n");
334
335         if (tdb) tdb_traverse(tdb, traverse_fn2, NULL);
336
337         printf("</table><p>\n");
338
339         printf("<p><h3>%s</h3>\n", _("Active Shares"));
340         printf("<table border=1>\n");
341         printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n\n",
342                 _("Share"), _("User"), _("Group"), _("PID"), _("Client"), _("Date"));
343
344         if (tdb) tdb_traverse(tdb, traverse_fn3, NULL);
345
346         printf("</table><p>\n");
347
348         printf("<h3>%s</h3>\n", _("Open Files"));
349         printf("<table border=1>\n");
350         printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n", _("PID"), _("Sharing"), _("R/W"), _("Oplock"), _("File"), _("Date"));
351
352         locking_init(1);
353         share_mode_forall(print_share_mode);
354         locking_end();
355         printf("</table>\n");
356
357         if (tdb) tdb_close(tdb);
358
359         printf("<br><input type=submit name=\"show_client_in_col_1\" value=\"Show Client in col 1\">\n");
360         printf("<input type=submit name=\"show_pid_in_col_1\" value=\"Show PID in col 1\">\n");
361
362         printf("</FORM>\n");
363
364         if (autorefresh) {
365                 /* this little JavaScript allows for automatic refresh
366                    of the page. There are other methods but this seems
367                    to be the best alternative */
368                 printf("<script language=\"JavaScript\">\n");
369                 printf("<!--\nsetTimeout('window.location.replace(\"%s/status?refresh_interval=%d&refresh=1\")', %d)\n", 
370                        cgi_baseurl(),
371                        refresh_interval,
372                        refresh_interval*1000);
373                 printf("//-->\n</script>\n");
374         }
375 }