ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/contrib/soft_reboot.c
Revision: 774
Committed: Wed Aug 23 00:13:06 2006 UTC (20 years, 1 month ago) by adx
Content type: text/x-csrc
File size: 11239 byte(s)
Log Message:
+ break a safelist during reboot, if currently processing

File Contents

# User Rev Content
1 adx 773 /************************************************************************
2     * IRC - Internet Relay Chat, contrib/soft_reboot.c
3     * Copyright (C) 2006 Hybrid Development Team
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; either version 1, or (at your option)
8     * any later version.
9     *
10     * This program is distributed in the hope that it will be useful,
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     * GNU General Public License for more details.
14     *
15     * You should have received a copy of the GNU General Public License
16     * along with this program; if not, write to the Free Software
17     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18     *
19     * $Id$
20     */
21    
22     #include "stdinc.h"
23     #include "conf/conf.h"
24     #include "channel.h"
25     #include "channel_mode.h"
26     #include "client.h"
27     #include "hash.h"
28     #include "ircd.h"
29     #include "ircd_defs.h"
30     #include "listener.h"
31 adx 774 #include "numeric.h"
32 adx 773 #include "packet.h"
33     #include "parse.h"
34     #include "restart.h"
35     #include "s_serv.h"
36     #include "s_user.h"
37     #include "send.h"
38    
39     static dlink_node *h_shutdown, *h_verify;
40    
41     struct SocketInfo
42     {
43     int fd;
44     int namelen;
45     int caplen;
46     int recvqlen;
47     int sendqlen;
48     };
49    
50     /*
51     * make_dummy()
52     *
53     * Prepares a dummy server-alike local client.
54     *
55     * inputs: file descriptor to use
56     * output: client pointer
57     */
58     static struct Client *
59     make_dummy(int transfd)
60     {
61     dlink_node *m;
62     struct Client *client_p = make_client(NULL);
63    
64     fd_open(&client_p->localClient->fd, transfd, 1, "Softboot");
65     client_p->localClient->caps = -1;
66    
67     strcpy(client_p->name, ".");
68     strcpy(client_p->id, "...");
69     dlinkAdd(client_p, &client_p->node, &global_client_list);
70    
71     m = dlinkFind(&unknown_list, client_p);
72     dlinkDelete(m, &unknown_list);
73     dlinkAdd(client_p, m, &serv_list);
74     dlinkAdd(client_p, make_dlink_node(), &global_serv_list);
75    
76     make_server(client_p);
77     SetServer(client_p);
78    
79     return client_p;
80     }
81    
82     /*
83     * write_dbuf()
84     *
85     * Writes the contents of a dbuf to the given socket.
86     *
87     * inputs:
88     * transfd - where to write to
89     * dbuf - dbuf pointer
90     * output: none
91     */
92     static void
93     write_dbuf(int transfd, struct dbuf_queue *dbuf)
94     {
95     while (dbuf_length(dbuf) > 0)
96     {
97     struct dbuf_block *first = dbuf->blocks.head->data;
98    
99     write(transfd, first->data, first->size);
100     dbuf_delete(dbuf, first->size);
101     }
102     }
103    
104     /*
105     * introduce_socket()
106     *
107     * Encodes and writes socket information about the given client.
108     *
109     * inputs:
110     * transfd - where to write to
111     * client_p - local client to inform about
112     * output: none
113     */
114     static void
115     introduce_socket(int transfd, struct Client *client_p)
116     {
117     struct SocketInfo si;
118     const char *capabs = "";
119    
120     if (IsDefunct(client_p))
121     return;
122    
123     if (IsServer(client_p))
124     capabs = show_capabilities(client_p);
125    
126     si.fd = client_p->localClient->fd.fd;
127     si.namelen = strlen(client_p->name);
128     si.caplen = strlen(capabs);
129     si.recvqlen = dbuf_length(&client_p->localClient->buf_recvq);
130     si.sendqlen = dbuf_length(&client_p->localClient->buf_sendq);
131    
132     write(transfd, &si, sizeof(si));
133     write(transfd, client_p->name, si.namelen);
134     write(transfd, capabs, si.caplen);
135    
136     write_dbuf(transfd, &client_p->localClient->buf_recvq);
137     write_dbuf(transfd, &client_p->localClient->buf_sendq);
138     }
139    
140     /*
141     * do_shutdown()
142     *
143     * Implements the /RESTART part of the soft reboot code.
144     *
145     * inputs:
146     * msg - shutdown message
147     * rboot - 1 if it's a restart, 0 if plain exit
148     * output: none
149     */
150     static void *
151     do_shutdown(va_list args)
152     {
153     const char *msg = va_arg(args, const char *);
154     int rboot = va_arg(args, int);
155     struct Client *client_p;
156     dlink_node *ptr;
157     int transfd[2];
158    
159     if (!rboot || socketpair(AF_UNIX, SOCK_STREAM, 0, transfd) < 0)
160     return pass_callback(h_shutdown, msg, rboot);
161    
162     if (EmptyString(msg))
163     {
164     ilog(L_CRIT, "Server Soft-Rebooting");
165     sendto_realops_flags(UMODE_ALL, L_ALL, "Server Soft-Rebooting");
166     }
167     else
168     {
169     ilog(L_CRIT, "Server Soft-Rebooting: %s", msg);
170     sendto_realops_flags(UMODE_ALL, L_ALL, "Server Soft-Rebooting: %s", msg);
171     }
172    
173     //
174     // Prevent all sockets which belong to registered users/servers from
175     // being closed on exec().
176     //
177     fcntl(transfd[0], F_SETFD, 0);
178    
179     DLINK_FOREACH(ptr, local_client_list.head)
180     {
181     client_p = ptr->data;
182     if (!IsDefunct(client_p))
183 adx 774 {
184 adx 773 fcntl(client_p->localClient->fd.fd, F_SETFD, 0);
185 adx 774 if (client_p->localClient->list_task != NULL)
186     sendto_one(client_p, form_str(RPL_LISTEND), me.name, client_p->name);
187     }
188 adx 773 }
189    
190     DLINK_FOREACH(ptr, serv_list.head)
191     {
192     client_p = ptr->data;
193     if (!IsDefunct(client_p))
194     fcntl(client_p->localClient->fd.fd, F_SETFD, 0);
195     }
196    
197     //
198     // Start the new ircd.
199     //
200     switch (fork())
201     {
202     case -1:
203     ilog(L_CRIT, "Unable to fork(): %s", strerror(errno));
204     exit(1);
205    
206     case 0:
207     {
208     int i;
209     char **argv, buf[24];
210    
211     snprintf(buf, sizeof(buf), "softboot_%d", transfd[0]);
212    
213     for (i = 0; myargv[i] != NULL; i++);
214     argv = MyMalloc((i + 2) * sizeof(char *));
215    
216     for (i = 0; myargv[i] != NULL; i++)
217     argv[i] = myargv[i];
218     argv[i++] = buf;
219     argv[i] = NULL;
220    
221     execv(SPATH, argv);
222     ilog(L_CRIT, "Unable to execve(): %s", strerror(errno));
223     exit(1);
224     }
225     }
226    
227     //
228     // Pass our data.
229     //
230     burst_all(make_dummy(transfd[1]));
231    
232     write(transfd[1], "\001\r\n", 3);
233    
234     DLINK_FOREACH(ptr, local_client_list.head)
235     introduce_socket(transfd[1], ptr->data);
236    
237     DLINK_FOREACH(ptr, serv_list.head)
238     introduce_socket(transfd[1], ptr->data);
239    
240     exit(0);
241     }
242    
243     /*
244     * restore_socket()
245     *
246     * Restores socket related fields in struct LocalUser.
247     *
248     * inputs:
249     * client_p - client pointer
250     * fd - file descriptor
251     * output: the same pointer or NULL if exited
252     */
253     static struct Client *
254     restore_socket(struct Client *client_p, int fd)
255     {
256     char buf[HOSTLEN+10];
257     struct irc_ssaddr addr;
258     int family, port;
259    
260     snprintf(buf, sizeof(buf), IsServer(client_p) ? "Server: %s" : "Nick: %s",
261     client_p->name);
262    
263     client_p->localClient = BlockHeapAlloc(lclient_heap);
264     fd_open(&client_p->localClient->fd, fd, 1, buf);
265    
266     addr.ss_len = sizeof(addr);
267     getsockname(fd, (struct sockaddr *) &addr, &addr.ss_len);
268     family = addr.ss.sin_family;
269     port = ntohs(addr.ss.sin_port);
270    
271     if (!(client_p->localClient->listener = find_listener(port, &addr)))
272     {
273     memset(&addr.ss, 0, sizeof(addr.ss));
274     addr.ss.sin_family = family;
275     addr.ss.sin_port = htons(port);
276    
277     if (!(client_p->localClient->listener = find_listener(port, &addr)))
278     {
279     exit_client(client_p, &me, "Listener closed");
280     return NULL;
281     }
282     }
283    
284     client_p->localClient->ip.ss_len = sizeof(client_p->localClient->ip.ss);
285     getpeername(fd, (struct sockaddr *) &client_p->localClient->ip,
286     &client_p->localClient->ip.ss_len);
287     client_p->localClient->aftype = client_p->localClient->ip.ss.sin_family;
288    
289     if (irc_getnameinfo((struct sockaddr *) &client_p->localClient->ip,
290     client_p->localClient->ip.ss_len, client_p->sockhost,
291     sizeof(client_p->sockhost), NULL, 0,
292     NI_NUMERICHOST) != 0)
293     {
294     exit_client(client_p, &me, "Protocol family no longer supported");
295     return NULL;
296     }
297    
298     return client_p;
299     }
300    
301     /*
302     * restore_client()
303     * restore_server()
304     *
305     * Restores a local user/server entity.
306     *
307     * inputs:
308     * client_p - client pointer
309     * capabs - user/server capab string
310     * output: the same pointer or NULL if exited
311     */
312     static struct Client *
313     restore_client(struct Client *client_p, char *capabs)
314     {
315     char userbuf[USERLEN+1];
316     struct Class *cptr;
317    
318     if (client_p->username[0] != '~')
319     SetGotId(client_p);
320     strlcpy(userbuf, client_p->username + !IsGotId(client_p),
321     sizeof(userbuf));
322    
323     if (!(cptr = execute_callback(authorize_client, client_p, userbuf)))
324     return NULL;
325     attach_class(client_p, cptr);
326    
327     Count.local++, Count.totalrestartcount++;
328     if (Count.local > Count.max_loc)
329     Count.max_loc = Count.local;
330    
331     dlinkAdd(client_p, &client_p->localClient->lclient_node, &local_client_list);
332     dlinkAdd(client_p, &client_p->lnode, &me.serv->client_list);
333     return client_p;
334     }
335    
336     static struct Client *
337     restore_server(struct Client *client_p, char *capabs)
338     {
339     char *p = NULL, *s = NULL;
340     int cap;
341    
342     SetGotId(client_p);
343    
344     for (s = strtoken(&p, capabs, " "); s; s = strtoken(&p, NULL, " "))
345     if ((cap = find_capability(s)) != 0)
346     SetCapable(client_p, cap);
347    
348     set_chcap_usage_counts(client_p);
349     Count.myserver++;
350    
351     dlinkAdd(client_p, &client_p->localClient->lclient_node, &serv_list);
352     dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
353     return client_p;
354     }
355    
356     /*
357     * restore_dbuf()
358     *
359     * Loads a dbuf contents from a file stream.
360     *
361     * inputs:
362     * f - file stream
363     * dbuf - dbuf to fill or NULL
364     * cnt - number of bytes to read
365     * output: none
366     */
367     static void
368     restore_dbuf(FILE *f, struct dbuf_queue *dbuf, int cnt)
369     {
370     while (cnt > 0)
371     {
372     int nread = fread(readBuf, 1, sizeof(readBuf), f);
373    
374     dbuf_put(dbuf, readBuf, nread);
375     cnt -= nread;
376     }
377     }
378    
379     /*
380     * load_state()
381     *
382     * Loads ircd state from a socket stream.
383     *
384     * inputs: socket fd
385     * output: none
386     */
387     static void
388     load_state(int transfd)
389     {
390     FILE *f = fdopen(transfd, "r");
391     char buf[IRCD_BUFSIZE+1], *p;
392     struct Client *dummy = make_dummy(transfd);
393     struct Client *client_p;
394     struct SocketInfo si;
395    
396     while (fgets(buf, sizeof(buf), f))
397     {
398     if ((p = strpbrk(buf, "\r\n")) != NULL)
399     *p = 0;
400     if (buf[0] == '\001')
401     break;
402     parse(dummy, buf, buf + strlen(buf));
403     }
404    
405     SetDead(dummy);
406    
407     while (fread(&si, sizeof(si), 1, f) == 1)
408     {
409     assert(si.namelen < IRCD_BUFSIZE);
410     assert(si.caplen < IRCD_BUFSIZE);
411    
412     fread(buf, 1, si.namelen, f);
413     buf[si.namelen] = 0;
414    
415     if ((client_p = find_client(buf)) != NULL)
416     {
417     client_p->servptr = &me;
418     client_p->from = client_p;
419     client_p = restore_socket(client_p, si.fd);
420     }
421    
422     fread(buf, 1, si.caplen, f);
423     buf[si.caplen] = 0;
424    
425     if (client_p != NULL)
426     client_p = (IsServer(client_p) ? restore_server : restore_client)
427     (client_p, buf);
428    
429     restore_dbuf(f, client_p ? &client_p->localClient->buf_recvq : NULL,
430     si.recvqlen);
431     restore_dbuf(f, client_p ? &client_p->localClient->buf_sendq : NULL,
432     si.sendqlen);
433     }
434    
435     exit_one_client(dummy, "Soft reboot");
436     fclose(f);
437     }
438    
439     /*
440     * do_verify_conf()
441     *
442     * Handles the conf verification callback.
443     *
444     * inputs: none
445     * output: none
446     */
447     static void *
448     do_verify_conf(va_list args)
449     {
450     pass_callback(h_verify);
451    
452     if (conf_cold)
453     {
454     int i;
455    
456     for (i = 0; myargv[i] != NULL; i++)
457     if (!ircncmp(myargv[i], "softboot_", 9))
458     {
459     load_state(atoi(myargv[i] + 9));
460     myargv[i] = NULL;
461     }
462     }
463    
464     return NULL;
465     }
466    
467     INIT_MODULE(soft_reboot, "$Revision$")
468     {
469     h_shutdown = install_hook(ircd_shutdown, do_shutdown);
470     h_verify = install_hook(verify_conf, do_verify_conf);
471     }
472    
473     CLEANUP_MODULE
474     {
475     uninstall_hook(verify_conf, do_verify_conf);
476     uninstall_hook(ircd_shutdown, do_shutdown);
477     }

Properties

Name Value
svn:eol-style native
svn:keywords "Id Revision"