]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_server.c
Backport from BEE
[bacula/bacula] / bacula / src / dird / ua_server.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *
18  *   Bacula Director -- User Agent Server
19  *
20  *     Kern Sibbald, September MM
21  *
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 /* Imported variables */
28
29
30 /* Forward referenced functions */
31 extern "C" void *connect_thread(void *arg);
32 static void *handle_UA_client_request(void *arg);
33
34
35 /* Global variables */
36 static int started = FALSE;
37 static workq_t ua_workq;
38
39 struct s_addr_port {
40    char *addr;
41    char *port;
42 };
43
44 /* Called here by Director daemon to start UA (user agent)
45  * command thread. This routine creates the thread and then
46  * returns.
47  */
48 void start_UA_server(dlist *addrs)
49 {
50    pthread_t thid;
51    int status;
52    static dlist *myaddrs = addrs;
53
54    if ((status=pthread_create(&thid, NULL, connect_thread, (void *)myaddrs)) != 0) {
55       berrno be;
56       Emsg1(M_ABORT, 0, _("Cannot create UA thread: %s\n"), be.bstrerror(status));
57    }
58    started = TRUE;
59    return;
60 }
61
62 extern "C"
63 void *connect_thread(void *arg)
64 {
65    pthread_detach(pthread_self());
66    set_jcr_in_tsd(INVALID_JCR);
67
68    /* Permit MaxConsoleConnect console connections */
69    bnet_thread_server((dlist*)arg, director->MaxConsoleConnect, &ua_workq, handle_UA_client_request);
70    return NULL;
71 }
72
73 /*
74  * Create a Job Control Record for a control "job",
75  *   filling in all the appropriate fields.
76  */
77 JCR *new_control_jcr(const char *base_name, int job_type)
78 {
79    JCR *jcr;
80    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
81    /*
82     * The job and defaults are not really used, but
83     *  we set them up to ensure that everything is correctly
84     *  initialized.
85     */
86    LockRes();
87    jcr->job = (JOB *)GetNextRes(R_JOB, NULL);
88    set_jcr_defaults(jcr, jcr->job);
89    UnlockRes();
90    jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */
91    create_unique_job_name(jcr, base_name);
92    jcr->sched_time = jcr->start_time;
93    jcr->setJobType(job_type);
94    jcr->setJobLevel(L_NONE);
95    jcr->setJobStatus(JS_Running);
96    jcr->JobId = 0;
97    return jcr;
98 }
99
100 /*
101  * Handle Director User Agent commands
102  *
103  */
104 static void *handle_UA_client_request(void *arg)
105 {
106    int stat;
107    UAContext *ua;
108    JCR *jcr;
109    BSOCK *user = (BSOCK *)arg;
110
111    pthread_detach(pthread_self());
112
113    jcr = new_control_jcr("-Console-", JT_CONSOLE);
114
115    ua = new_ua_context(jcr);
116    ua->UA_sock = user;
117    set_jcr_in_tsd(INVALID_JCR);
118
119    user->recv();             /* Get first message */
120    if (!authenticate_user_agent(ua)) {
121       goto getout;
122    }
123
124    while (!ua->quit) {
125       if (ua->api) user->signal(BNET_MAIN_PROMPT);
126       stat = user->recv();
127       if (stat >= 0) {
128          pm_strcpy(ua->cmd, ua->UA_sock->msg);
129          parse_ua_args(ua);
130          if (ua->argc > 0 && ua->argk[0][0] == '.') {
131             do_a_dot_command(ua);
132          } else {
133             do_a_command(ua);
134          }
135          dequeue_messages(ua->jcr);
136          if (!ua->quit) {
137             if (console_msg_pending && acl_access_ok(ua, Command_ACL, "messages", 8)) {
138                if (ua->auto_display_messages) {
139                   pm_strcpy(ua->cmd, "messages");
140                   qmessagescmd(ua, ua->cmd);
141                   ua->user_notified_msg_pending = false;
142                } else if (!ua->gui && !ua->user_notified_msg_pending && console_msg_pending) {
143                   if (ua->api) {
144                      user->signal(BNET_MSGS_PENDING);
145                   } else {
146                      bsendmsg(ua, _("You have messages.\n"));
147                   }
148                   ua->user_notified_msg_pending = true;
149                }
150             }
151             if (!ua->api) user->signal(BNET_EOD);     /* send end of command */
152          }
153       } else if (user->is_stop()) {
154          ua->quit = true;
155       } else { /* signal */
156          user->signal(BNET_POLL);
157       }
158
159       /* At the end of each command, revert to the main shared SQL link */
160       ua->db = ua->shared_db;
161    }
162
163 getout:
164    close_db(ua);
165    free_ua_context(ua);
166    free_jcr(jcr);
167
168    return NULL;
169 }
170
171 /*
172  * Create a UAContext for a Job that is running so that
173  *   it can the User Agent routines and
174  *   to ensure that the Job gets the proper output.
175  *   This is a sort of mini-kludge, and should be
176  *   unified at some point.
177  */
178 UAContext *new_ua_context(JCR *jcr)
179 {
180    UAContext *ua;
181
182    ua = (UAContext *)malloc(sizeof(UAContext));
183    memset(ua, 0, sizeof(UAContext));
184    ua->jcr = jcr;
185    ua->shared_db = ua->db = jcr->db;
186    ua->cmd = get_pool_memory(PM_FNAME);
187    ua->args = get_pool_memory(PM_FNAME);
188    ua->errmsg = get_pool_memory(PM_FNAME);
189    ua->verbose = true;
190    ua->automount = true;
191    return ua;
192 }
193
194 void free_ua_context(UAContext *ua)
195 {
196    if (ua->cmd) {
197       free_pool_memory(ua->cmd);
198    }
199    if (ua->args) {
200       free_pool_memory(ua->args);
201    }
202    if (ua->errmsg) {
203       free_pool_memory(ua->errmsg);
204    }
205    if (ua->prompt) {
206       free(ua->prompt);
207    }
208    if (ua->unique) {
209       free(ua->unique);
210    }
211    free_bsock(ua->UA_sock);
212    free(ua);
213 }
214
215
216 /*
217  * Called from main Bacula thread
218  */
219 void term_ua_server()
220 {
221    if (!started) {
222       return;
223    }
224 }