f03eed309e76d84871d81eb4baa71c5ce31e9b72
[debian/amanda] / server-src / server_util.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: server_util.c,v 1.17 2006/05/25 01:47:20 johnfranks Exp $
28  *
29  */
30
31 #include "amanda.h"
32 #include "server_util.h"
33 #include "arglist.h"
34 #include "logfile.h"
35 #include "util.h"
36 #include "conffile.h"
37 #include "diskfile.h"
38 #include "pipespawn.h"
39 #include "version.h"
40 #include "conffile.h"
41 #include "sys/wait.h"
42
43 const char *cmdstr[] = {
44     "BOGUS", "QUIT", "QUITTING", "DONE", "PARTIAL", 
45     "START", "FILE-DUMP", "PORT-DUMP", "CONTINUE", "ABORT",/* dumper cmds */
46     "FAILED", "TRY-AGAIN", "NO-ROOM", "RQ-MORE-DISK",   /* dumper results */
47     "ABORT-FINISHED", "BAD-COMMAND",                    /* dumper results */
48     "START-TAPER", "FILE-WRITE", "NEW-TAPE", "NO-NEW-TAPE",
49      
50     "PARTDONE", "PORT-WRITE", "DUMPER-STATUS",              /* taper cmds */
51     "PORT", "TAPE-ERROR", "TAPER-OK",                    /* taper results */
52     "REQUEST-NEW-TAPE",
53     "LAST_TOK",
54     NULL
55 };
56
57
58 struct cmdargs *
59 getcmd(void)
60 {
61     char *line;
62     cmd_t cmd_i;
63     struct cmdargs *cmdargs = g_new0(struct cmdargs, 1);
64
65     if (isatty(0)) {
66         g_printf("%s> ", get_pname());
67         fflush(stdout);
68         line = agets(stdin);
69     } else {
70         line = agets(stdin);
71     }
72     if (line == NULL) {
73         line = stralloc("QUIT");
74     }
75
76     dbprintf(_("getcmd: %s\n"), line);
77
78     cmdargs->argv = split_quoted_strings(line);
79     cmdargs->argc = g_strv_length(cmdargs->argv);
80     cmdargs->cmd = BOGUS;
81
82     amfree(line);
83
84     if (cmdargs->argc < 1) {
85         return cmdargs;
86     }
87
88     for(cmd_i=BOGUS; cmdstr[cmd_i] != NULL; cmd_i++)
89         if(strcmp(cmdargs->argv[0], cmdstr[cmd_i]) == 0) {
90             cmdargs->cmd = cmd_i;
91             return cmdargs;
92         }
93     return cmdargs;
94 }
95
96 struct cmdargs *
97 get_pending_cmd(void)
98 {
99     SELECT_ARG_TYPE ready;
100     struct timeval  to;
101     int             nfound;
102
103     FD_ZERO(&ready);
104     FD_SET(0, &ready);
105     to.tv_sec = 0;
106     to.tv_usec = 0;
107
108     nfound = select(1, &ready, NULL, NULL, &to);
109     if (nfound && FD_ISSET(0, &ready)) {
110         return getcmd();
111     } else {
112         return NULL;
113     }
114 }
115
116 void
117 free_cmdargs(
118     struct cmdargs *cmdargs)
119 {
120     if (!cmdargs)
121         return;
122     if (cmdargs->argv)
123         g_strfreev(cmdargs->argv);
124     g_free(cmdargs);
125 }
126
127 printf_arglist_function1(void putresult, cmd_t, result, const char *, format)
128 {
129     va_list argp;
130
131     arglist_start(argp, format);
132     dbprintf(_("putresult: %d %s\n"), result, cmdstr[result]);
133     g_printf("%s ", cmdstr[result]);
134     g_vprintf(format, argp);
135     fflush(stdout);
136     arglist_end(argp);
137 }
138
139 char *
140 amhost_get_security_conf(
141     char *      string,
142     void *      arg)
143 {
144     if(!string || !*string)
145         return(NULL);
146
147     if(strcmp(string, "krb5principal")==0)
148         return(getconf_str(CNF_KRB5PRINCIPAL));
149     else if(strcmp(string, "krb5keytab")==0)
150         return(getconf_str(CNF_KRB5KEYTAB));
151
152     if(!arg || !((am_host_t *)arg)->disks) return(NULL);
153
154     if(strcmp(string, "amandad_path")==0)
155         return ((am_host_t *)arg)->disks->amandad_path;
156     else if(strcmp(string, "client_username")==0)
157         return ((am_host_t *)arg)->disks->client_username;
158     else if(strcmp(string, "ssh_keys")==0)
159         return ((am_host_t *)arg)->disks->ssh_keys;
160
161     return(NULL);
162 }
163
164 int check_infofile(
165     char        *infodir,
166     disklist_t  *dl,
167     char       **errmsg)
168 {
169     disk_t      *dp, *diskp;
170     char        *hostinfodir, *old_hostinfodir, *Xhostinfodir;
171     char        *diskdir,     *old_diskdir,     *Xdiskdir;
172     char        *infofile,    *old_infofile,    *Xinfofile;
173     struct stat  statbuf;
174     int other_dle_match;
175
176     if (stat(infodir, &statbuf) != 0) {
177         return 0;
178     }
179
180     for (dp = dl->head; dp != NULL; dp = dp->next) {
181         hostinfodir = sanitise_filename(dp->host->hostname);
182         diskdir     = sanitise_filename(dp->name);
183         infofile = vstralloc(infodir, "/", hostinfodir, "/", diskdir,
184                              "/info", NULL);
185         if (stat(infofile, &statbuf) == -1 && errno == ENOENT) {
186             old_hostinfodir = old_sanitise_filename(dp->host->hostname);
187             old_diskdir     = old_sanitise_filename(dp->name);
188             old_infofile    = vstralloc(infodir, old_hostinfodir, "/",
189                                         old_diskdir, "/info", NULL);
190             if (stat(old_infofile, &statbuf) == 0) {
191                 other_dle_match = 0;
192                 diskp = dl->head;
193                 while (diskp != NULL) {
194                     Xhostinfodir = sanitise_filename(diskp->host->hostname);
195                     Xdiskdir     = sanitise_filename(diskp->name);
196                     Xinfofile = vstralloc(infodir, "/", Xhostinfodir, "/",
197                                           Xdiskdir, "/info", NULL);
198                     if (strcmp(old_infofile, Xinfofile) == 0) {
199                         other_dle_match = 1;
200                         diskp = NULL;
201                     }
202                     else {
203                         diskp = diskp->next;
204                     }
205                 }
206                 if (other_dle_match == 0) {
207                     if(mkpdir(infofile, (mode_t)0755, (uid_t)-1,
208                               (gid_t)-1) == -1) {
209                         *errmsg = vstralloc("Can't create directory for ",
210                                             infofile, NULL);
211                         return -1;
212                     }
213                     if(copy_file(infofile, old_infofile, errmsg) == -1) 
214                         return -1;
215                 }
216             }
217         }
218         amfree(diskdir);
219         amfree(hostinfodir);
220         amfree(infofile);
221     }
222     return 0;
223 }
224
225 void
226 run_server_script(
227     pp_script_t  *pp_script,
228     execute_on_t  execute_on,
229     char         *config,
230     disk_t       *dp,
231     int           level)
232 {
233     pid_t   scriptpid;
234     int     scriptin, scriptout, scripterr;
235     char   *cmd;
236     char  **argvchild;
237     int     i, k;
238     FILE   *streamout;
239     char   *line;
240     char   *plugin;
241     char    level_number[NUM_STR_SIZE];
242
243     if ((pp_script_get_execute_on(pp_script) & execute_on) == 0)
244         return;
245     if (pp_script_get_execute_where(pp_script) != ES_SERVER)
246         return;
247
248     plugin = pp_script_get_plugin(pp_script);
249     k = property_argv_size(pp_script_get_property(pp_script));
250     argvchild = g_new0(char *, 16+k);
251     cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
252     i = 0;
253     argvchild[i++] = plugin;
254
255     switch (execute_on) {
256     case EXECUTE_ON_PRE_DLE_AMCHECK:
257         argvchild[i++] = "PRE-DLE-AMCHECK"; break;
258     case EXECUTE_ON_PRE_HOST_AMCHECK:
259         argvchild[i++] = "PRE-HOST-AMCHECK"; break;
260     case EXECUTE_ON_POST_DLE_AMCHECK:
261         argvchild[i++] = "POST-DLE-AMCHECK"; break;
262     case EXECUTE_ON_POST_HOST_AMCHECK:
263         argvchild[i++] = "POST-HOST-AMCHECK"; break;
264     case EXECUTE_ON_PRE_DLE_ESTIMATE:
265         argvchild[i++] = "PRE-DLE-ESTIMATE"; break;
266     case EXECUTE_ON_PRE_HOST_ESTIMATE:
267         argvchild[i++] = "PRE-HOST-ESTIMATE"; break;
268     case EXECUTE_ON_POST_DLE_ESTIMATE:
269         argvchild[i++] = "POST-DLE-ESTIMATE"; break;
270     case EXECUTE_ON_POST_HOST_ESTIMATE:
271         argvchild[i++] = "POST-HOST-ESTIMATE"; break;
272     case EXECUTE_ON_PRE_DLE_BACKUP:
273         argvchild[i++] = "PRE-DLE-BACKUP"; break;
274     case EXECUTE_ON_PRE_HOST_BACKUP:
275         argvchild[i++] = "PRE-HOST-BACKUP"; break;
276     case EXECUTE_ON_POST_DLE_BACKUP:
277         argvchild[i++] = "POST-DLE-BACKUP"; break;
278     case EXECUTE_ON_POST_HOST_BACKUP:
279         argvchild[i++] = "POST-HOST-BACKUP"; break;
280     case EXECUTE_ON_PRE_RECOVER:
281     case EXECUTE_ON_POST_RECOVER:
282     case EXECUTE_ON_PRE_LEVEL_RECOVER:
283     case EXECUTE_ON_POST_LEVEL_RECOVER:
284     case EXECUTE_ON_INTER_LEVEL_RECOVER:
285         {
286              // ERROR these script can't be executed on server.
287              return;
288         }
289     }
290
291     argvchild[i++] = "--execute-where";
292     argvchild[i++] = "server";
293
294     if (config) {
295         argvchild[i++] = "--config";
296         argvchild[i++] = config;
297     }
298     if (dp->host->hostname) {
299         argvchild[i++] = "--host";
300         argvchild[i++] = dp->host->hostname;
301     }
302     if (dp->name) {
303         argvchild[i++] = "--disk";
304         argvchild[i++] = dp->name;
305     }
306     if (dp->device) {
307         argvchild[i++] = "--device";
308         argvchild[i++] = dp->device;
309     }
310     if (level >= 0) {
311         g_snprintf(level_number, SIZEOF(level_number), "%d", level);
312         argvchild[i++] = "--level";
313         argvchild[i++] = level_number;
314     }
315
316     i += property_add_to_argv(&argvchild[i], pp_script_get_property(pp_script));
317     argvchild[i++] = NULL;
318
319     scripterr = fileno(stderr);
320     scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, 0, &scriptin,
321                            &scriptout, &scripterr, argvchild);
322     close(scriptin);
323
324     streamout = fdopen(scriptout, "r");
325     if (streamout) {
326         while((line = agets(streamout)) != NULL) {
327             dbprintf("script: %s\n", line);
328         }
329     }
330     fclose(streamout);
331     waitpid(scriptpid, NULL, 0);
332 }
333
334
335 void
336 run_server_scripts(
337     execute_on_t  execute_on,
338     char         *config,
339     disk_t       *dp,
340     int           level)
341 {
342     GSList   *pp_scriptlist;
343
344     for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
345          pp_scriptlist = pp_scriptlist->next) {
346         run_server_script(pp_scriptlist->data, execute_on, config, dp, level);
347     }
348 }
349
350 void
351 run_amcleanup(
352     char *config_name)
353 {
354     pid_t amcleanup_pid;
355     char *amcleanup_program;
356     char *amcleanup_options[4];
357
358     switch(amcleanup_pid = fork()) {
359         case -1:
360             return;
361             break;
362         case  0: /* child process */
363             amcleanup_program = vstralloc(sbindir, "/", "amcleanup", versionsuffix(), NULL);
364             amcleanup_options[0] = amcleanup_program;
365             amcleanup_options[1] = "-p";
366             amcleanup_options[2] = config_name;
367             amcleanup_options[3] = NULL;
368             execve(amcleanup_program, amcleanup_options, safe_env());
369             error("exec %s: %s", amcleanup_program, strerror(errno));
370             /*NOTREACHED*/
371         default:
372             break;
373     }
374     waitpid(amcleanup_pid, NULL, 0);
375 }
376
377 char *
378 get_master_process(
379     char *logfile)
380 {
381     FILE *log;
382     char line[1024];
383     char *s, ch;
384     char *process_name;
385
386     log = fopen(logfile, "r");
387     if (!log)
388         return stralloc("UNKNOWN");
389
390     while(fgets(line, 1024, log)) {
391         if (strncmp_const(line, "INFO ") == 0) {
392             s = line+5;
393             ch = *s++;
394             process_name = s-1;
395             skip_non_whitespace(s, ch);
396             s[-1] = '\0';
397             skip_whitespace(s, ch);
398             skip_non_whitespace(s, ch);
399             s[-1] = '\0';
400             skip_whitespace(s, ch);
401             if (strncmp_const(s-1, "pid ") == 0) {
402                 process_name = stralloc(process_name);
403                 fclose(log);
404                 return process_name;
405             }
406         }
407     }
408     fclose(log);
409     return stralloc("UNKNOWN");
410 }