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