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