]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_server.c
54f4801ed52ff9294d071ba17da9a7d0f927aad2
[bacula/bacula] / bacula / src / dird / ua_server.c
1 /*
2  *
3  *   Bacula Director -- User Agent Server
4  *
5  *     Kern Sibbald, September MM
6  *
7  *    Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2003 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Imported subroutines */
34
35 /* Imported variables */
36 extern int r_first;
37 extern int r_last;
38 extern struct s_res resources[];
39 extern int console_msg_pending;
40 extern char my_name[];
41
42 /* Static variables */
43
44 /* Exported variables */
45 int quit_cmd_thread = 0;
46
47 /* Imported functions */
48
49 /* Forward referenced functions */
50
51 static void *connect_thread(void *arg);
52 static void *handle_UA_client_request(void *arg);
53
54
55 /* Global variables */
56 static int started = FALSE;
57 static workq_t ua_workq;
58
59 struct s_addr_port {
60    char *addr;
61    int port;
62 };
63
64 /* Called here by Director daemon to start UA (user agent)
65  * command thread. This routine creates the thread and then
66  * returns.
67  */
68 void start_UA_server(char *UA_addr, int UA_port)
69 {
70    pthread_t thid;
71    int status;
72    static struct s_addr_port arg;
73
74    arg.port = UA_port;
75    arg.addr = UA_addr;
76    if ((status=pthread_create(&thid, NULL, connect_thread, (void *)&arg)) != 0) {
77       Emsg1(M_ABORT, 0, _("Cannot create UA thread: %s\n"), strerror(status));
78    }
79    started = TRUE;
80    return;
81 }
82
83 static void *connect_thread(void *arg)
84 {
85    struct s_addr_port *UA = (struct s_addr_port *)arg;
86
87    pthread_detach(pthread_self());
88
89    /*  ****FIXME**** put # 5 on config parameter */
90    bnet_thread_server(UA->addr, UA->port, 5, &ua_workq, handle_UA_client_request);
91    return NULL;
92 }
93
94 /*
95  * Create a Job Control Record for a console "job" 
96  *   filling in all the appropriate fields.
97  */
98 static JCR *create_console_jcr()
99 {
100    JCR *jcr;
101    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
102    jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */
103    create_unique_job_name(jcr, "*Console*");
104    jcr->sched_time = jcr->start_time;
105    jcr->JobType = JT_CONSOLE;
106    jcr->JobLevel = L_FULL;
107    jcr->JobStatus = JS_Running;
108    /* None of these are really defined for the Console, so we
109     * simply take the first of each one. This ensures that there
110     * will be no null pointer references.
111     */
112    LockRes();
113    jcr->job = (JOB *)GetNextRes(R_JOB, NULL);
114    jcr->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
115    jcr->client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
116    jcr->pool = (POOL *)GetNextRes(R_POOL, NULL);
117    jcr->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
118    jcr->store = (STORE *)GetNextRes(R_STORAGE, NULL);
119    jcr->fileset = (FILESET *)GetNextRes(R_FILESET, NULL);
120    UnlockRes();
121    return jcr;
122 }
123
124 /*
125  * Handle Director User Agent commands   
126  *
127  */
128 static void *handle_UA_client_request(void *arg)
129 {
130    int stat;
131    UAContext *ua;
132    JCR *jcr;
133    BSOCK *UA_sock = (BSOCK *)arg;
134
135    pthread_detach(pthread_self());
136
137    jcr = create_console_jcr();
138
139    ua = new_ua_context(jcr);
140    ua->UA_sock = UA_sock;
141
142    bnet_recv(ua->UA_sock);          /* Get first message */
143    if (!authenticate_user_agent(ua->UA_sock)) {
144       goto getout;
145    }
146
147    while (!ua->quit) {
148       stat = bnet_recv(ua->UA_sock);
149       if (stat >= 0) {
150          ua->cmd = check_pool_memory_size(ua->cmd, ua->UA_sock->msglen+1);
151          bstrncpy(ua->cmd, ua->UA_sock->msg, ua->UA_sock->msglen+1);
152          parse_ua_args(ua);
153          if (ua->argc > 0 && ua->argk[0][0] == '.') {
154             do_a_dot_command(ua, ua->cmd);
155          } else {
156             do_a_command(ua, ua->cmd);
157          }
158          if (!ua->quit) {
159             if (ua->auto_display_messages) {
160                strcpy(ua->cmd, "messages");
161                qmessagescmd(ua, ua->cmd);
162                ua->user_notified_msg_pending = FALSE;
163             } else if (!ua->user_notified_msg_pending && console_msg_pending) {
164                bsendmsg(ua, _("You have messages.\n"));
165                ua->user_notified_msg_pending = TRUE;
166             }
167             bnet_sig(ua->UA_sock, BNET_EOD); /* send end of command */
168          }
169       } else if (is_bnet_stop(ua->UA_sock)) {
170          ua->quit = TRUE;
171          break;
172       } else { /* signal */
173          bnet_sig(ua->UA_sock, BNET_POLL);
174       }
175    }
176
177 getout:
178
179    free_ua_context(ua);
180    free_jcr(jcr);
181
182    return NULL;
183 }
184
185 /*
186  * Create a UAContext for a Job that is running so that
187  *   it can the User Agent routines and    
188  *   to ensure that the Job gets the proper output.
189  *   This is a sort of mini-kludge, and should be
190  *   unified at some point.
191  */
192 UAContext *new_ua_context(JCR *jcr)
193 {
194    UAContext *ua;
195
196    ua = (UAContext *)malloc(sizeof(UAContext));
197    memset(ua, 0, sizeof(UAContext));
198    ua->jcr = jcr;
199    ua->db = jcr->db;
200    ua->cmd = get_pool_memory(PM_FNAME);
201    ua->args = get_pool_memory(PM_FNAME);
202    ua->verbose = 1;
203    ua->automount = TRUE;
204    return ua;
205 }
206
207 void free_ua_context(UAContext *ua)
208 {
209    if (ua->cmd) {
210       free_pool_memory(ua->cmd);
211    }
212    if (ua->args) {
213       free_pool_memory(ua->args);
214    }
215    if (ua->prompt) {
216       free(ua->prompt);
217    }
218
219    if (ua->UA_sock) {
220       bnet_close(ua->UA_sock);
221    }
222
223    close_db(ua);
224
225    free(ua);
226 }
227
228
229 /*
230  * Called from main Bacula thread 
231  */
232 void term_ua_server()
233 {
234    if (!started) {
235       return;
236    }
237    quit_cmd_thread = TRUE;
238 }