char * amhost_get_security_conf( char * string, void * arg) { if(!string || !*string) return(NULL); if(strcmp(string, "krb5principal")==0) return(getconf_str(CNF_KRB5PRINCIPAL)); else if(strcmp(string, "krb5keytab")==0) return(getconf_str(CNF_KRB5KEYTAB)); if(!arg || !((am_host_t *)arg)->disks) return(NULL); if(strcmp(string, "amandad_path")==0) return ((am_host_t *)arg)->disks->amandad_path; else if(strcmp(string, "client_username")==0) return ((am_host_t *)arg)->disks->client_username; else if(strcmp(string, "client_port")==0) return ((am_host_t *)arg)->disks->client_port; else if(strcmp(string, "ssh_keys")==0) return ((am_host_t *)arg)->disks->ssh_keys; return(NULL); }
char * amhost_get_security_conf( char * string, void * arg) { if(!string || !*string) return(NULL); if(g_str_equal(string, "krb5principal")) return(getconf_str(CNF_KRB5PRINCIPAL)); else if(g_str_equal(string, "krb5keytab")) return(getconf_str(CNF_KRB5KEYTAB)); if(!arg || !((am_host_t *)arg)->disks) return(NULL); if(g_str_equal(string, "amandad_path")) return ((am_host_t *)arg)->disks->amandad_path; else if(g_str_equal(string, "client_username")) return ((am_host_t *)arg)->disks->client_username; else if(g_str_equal(string, "client_port")) return ((am_host_t *)arg)->disks->client_port; else if(g_str_equal(string, "src_ip")) { char *src_ip = interface_get_src_ip(((am_host_t *)arg)->netif->config); if (g_str_equal(src_ip, "NULL")) return NULL; else return src_ip; } else if(g_str_equal(string, "ssh_keys")) return ((am_host_t *)arg)->disks->ssh_keys; return(NULL); }
void confirm(GSList *datestamp_list) { tape_t *tp; char *tpchanger; GSList *datestamp; int ch; char *extra; g_printf(_("\nToday is: %s\n"),amflush_datestamp); g_printf(_("Flushing dumps from")); extra = ""; for(datestamp = datestamp_list; datestamp != NULL; datestamp = datestamp->next) { g_printf("%s %s", extra, (char *)datestamp->data); extra = ","; } tpchanger = getconf_str(CNF_TPCHANGER); if(*tpchanger != '\0') { g_printf(_(" using tape changer \"%s\".\n"), tpchanger); } else { g_printf(_(" to tape drive \"%s\".\n"), getconf_str(CNF_TAPEDEV)); } g_printf(_("Expecting ")); tp = lookup_last_reusable_tape(0); if(tp != NULL) g_printf(_("tape %s or "), tp->label); g_printf(_("a new tape.")); tp = lookup_tapepos(1); if(tp != NULL) g_printf(_(" (The last dumps were to tape %s)"), tp->label); while (1) { g_printf(_("\nAre you sure you want to do this [yN]? ")); if((ch = get_letter_from_user()) == 'Y') { return; } else if (ch == 'N' || ch == '\0' || ch == EOF) { if (ch == EOF) { putchar('\n'); } break; } } g_printf(_("Ok, quitting. Run amflush again when you are ready.\n")); log_add(L_INFO, "pid-done %ld", (long)getpid()); exit(1); }
void log_rename( char * datestamp) { char *conf_logdir; char *logfile; char *fname = NULL; char seq_str[NUM_STR_SIZE]; unsigned int seq; struct stat statbuf; if(datestamp == NULL) datestamp = "error"; conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); logfile = g_strjoin(NULL, conf_logdir, "/log", NULL); for(seq = 0; 1; seq++) { /* if you've got MAXINT files in your dir... */ g_snprintf(seq_str, sizeof(seq_str), "%u", seq); g_free(fname); fname = g_strconcat(logfile, ".", datestamp, ".", seq_str, NULL); if(stat(fname, &statbuf) == -1 && errno == ENOENT) break; } if(rename(logfile, fname) == -1) { error(_("could not rename \"%s\" to \"%s\": %s"), logfile, fname, strerror(errno)); /*NOTREACHED*/ } amfree(fname); amfree(logfile); amfree(conf_logdir); }
char * getindexfname( char * host, char * disk, char * date, int level) { char *conf_indexdir; char *buf; char level_str[NUM_STR_SIZE]; char datebuf[14 + 1]; char *dc = NULL; char *pc; int ch; if (date != NULL) { dc = date; pc = datebuf; while (pc < datebuf + sizeof(datebuf)) { ch = *dc++; *pc++ = (char)ch; if (ch == '\0') { break; } else if (! isdigit (ch)) { pc--; } } datebuf[sizeof(datebuf)-1] = '\0'; dc = datebuf; g_snprintf(level_str, sizeof(level_str), "%d", level); } host = sanitise_filename(host); if (disk != NULL) { disk = sanitise_filename(disk); } conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR)); /* * Note: g_strjoin(NULL, ) will stop at the first NULL, which might be * "disk" or "dc" (datebuf) rather than the full file name. */ buf = g_strjoin(NULL, conf_indexdir, "/", host, "/", disk, "/", dc, "_", level_str, COMPRESS_SUFFIX, NULL); amfree(conf_indexdir); amfree(host); amfree(disk); return buf; }
void update_info_taper( disk_t *dp, char *label, off_t filenum, int level) { info_t info; stats_t *infp; int rc; rc = open_infofile(getconf_str(CNF_INFOFILE)); if(rc) { error(_("could not open infofile %s: %s (%d)"), getconf_str(CNF_INFOFILE), strerror(errno), rc); /*NOTREACHED*/ } get_info(dp->host->hostname, dp->name, &info); infp = &info.inf[level]; /* XXX - should we record these two if no-record? */ strncpy(infp->label, label, sizeof(infp->label)-1); infp->label[sizeof(infp->label)-1] = '\0'; infp->filenum = filenum; info.command = NO_COMMAND; if (put_info(dp->host->hostname, dp->name, &info)) { int save_errno = errno; g_fprintf(stderr, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); log_add(L_ERROR, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); error(_("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); /*NOTREACHED*/ } close_infofile(); }
static void end_backup( dle_t *dle, int goterror) { char *amandates_file = NULL; if(dle->record && !goterror) { if (incrname != NULL && strlen(incrname) > 4) { char *nodotnew; nodotnew = g_strdup(incrname); nodotnew[strlen(nodotnew)-4] = '\0'; if (rename(incrname, nodotnew)) { g_fprintf(stderr, _("%s: warning [renaming %s to %s: %s]\n"), get_pname(), incrname, nodotnew, strerror(errno)); } amfree(nodotnew); amfree(incrname); } /* update the amandates file */ amandates_file = getconf_str(CNF_AMANDATES); if(start_amandates(amandates_file, 1)) { amandates_updateone(cur_disk, cur_level, cur_dumptime); finish_amandates(); free_amandates(); } else { /* failure is only fatal if we didn't get a gnutar-listdir */ char *gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR); if (!gnutar_list_dir || !*gnutar_list_dir) { error(_("error [opening %s for writing: %s]"), amandates_file, strerror(errno)); /* NOTREACHED */ } else { g_debug(_("non-fatal error opening '%s' for writing: %s]"), amandates_file, strerror(errno)); } } } }
static void amstar_selfcheck( application_argument_t *argument) { fprintf(stdout, "OK amstar\n"); if (argument->dle.disk) { char *qdisk = quote_string(argument->dle.disk); fprintf(stdout, "OK %s\n", qdisk); amfree(qdisk); } if (argument->dle.device) { char *qdevice = quote_string(argument->dle.device); fprintf(stdout, "OK %s\n", qdevice); amfree(qdevice); } if (star_directory) { char *qdirectory = quote_string(star_directory); fprintf(stdout, "OK %s\n", qdirectory); amfree(qdirectory); } if (argument->dle.include_list && argument->dle.include_list->nb_element >= 0) { fprintf(stdout, "ERROR include-list not supported for backup\n"); } if (!star_path) { fprintf(stdout, "ERROR STAR-PATH not defined\n"); } else { check_file(star_path, X_OK); } if (argument->calcsize) { char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL); check_file(calcsize, X_OK); check_suid(calcsize); amfree(calcsize); } { char *amandates_file; amandates_file = getconf_str(CNF_AMANDATES); check_file(amandates_file, R_OK|W_OK); } set_root_privs(1); if (argument->dle.device) { check_dir(argument->dle.device, R_OK); } set_root_privs(0); }
static void update_tapelist( taper_state_t *state) { char *tapelist_name = NULL; char *tapelist_name_old = NULL; tape_t *tp; char *comment = NULL; tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST)); if (state->cur_tape == 0) { tapelist_name_old = stralloc2(tapelist_name, ".yesterday"); } else { char cur_str[NUM_STR_SIZE]; g_snprintf(cur_str, SIZEOF(cur_str), "%d", state->cur_tape - 1); tapelist_name_old = vstralloc(tapelist_name, ".today.", cur_str, NULL); } if (read_tapelist(tapelist_name) != 0) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("could not load tapelist \"%s\"", tapelist_name); /*NOTREACHED*/ } /* make a copy of the tapelist file */ if (write_tapelist(tapelist_name_old)) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("could not write tapelist: %s", strerror(errno)); /*NOTREACHED*/ } amfree(tapelist_name_old); /* get a copy of the comment, before freeing the old record */ tp = lookup_tapelabel(state->device->volume_label); if (tp && tp->comment) comment = stralloc(tp->comment); /* edit the tapelist and rewrite it */ remove_tapelabel(state->device->volume_label); add_tapelabel(state->driver_start_time, state->device->volume_label, comment); if (write_tapelist(tapelist_name)) { error("could not write tapelist: %s", strerror(errno)); /*NOTREACHED*/ } amfree(tapelist_name); amfree(comment); }
static void open_log(void) { char *conf_logdir; conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); logfile = g_strjoin(NULL, conf_logdir, "/log", NULL); amfree(conf_logdir); logfd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600); if(logfd == -1) { error(_("could not open log file %s: %s"), logfile, strerror(errno)); /*NOTREACHED*/ } if(amflock(logfd, "log") == -1) { error(_("could not lock log file %s: %s"), logfile, strerror(errno)); /*NOTREACHED*/ } }
int taper_scan(char* wantlabel, char** gotlabel, char** timestamp, char** tapedev, taper_scan_tracker_t * tracker, TaperscanOutputFunctor output_functor, void *output_data, TaperscanProlongFunctor prolong_functor, void *prolong_data) { char *error_message = NULL; int result; *gotlabel = *timestamp = NULL; if (wantlabel == NULL) { tape_t *tmp; tmp = lookup_last_reusable_tape(0); if (tmp != NULL) { wantlabel = tmp->label; } } if (changer_init()) { result = changer_taper_scan(wantlabel, gotlabel, timestamp, tapedev, tracker, output_functor, output_data, prolong_functor, prolong_data); } else { /* Note that the tracker is not used in this case. */ *tapedev = stralloc(getconf_str(CNF_TAPEDEV)); if (*tapedev == NULL) { result = -1; output_functor(output_data, _("No tapedev specified")); } else { result = scan_read_label(*tapedev, NULL, wantlabel, gotlabel, timestamp, &error_message); output_functor(output_data, error_message); amfree(error_message); } } return result; }
static pid_t run_sort( int fd_in, int *fd_out, int *fd_err, char *source_filename, char *dest_filename) { int in_fd; int out_fd; int create_pipe = STDERR_PIPE; pid_t pid; gchar *tmpdir = getconf_str(CNF_TMPDIR); if (fd_in == -1) { in_fd = open(source_filename, O_RDONLY); } else { in_fd = fd_in; } if (dest_filename) { out_fd = open(dest_filename, O_WRONLY|O_CREAT, S_IRUSR); } else { create_pipe |= STDOUT_PIPE; } pid = pipespawn(SORT_PATH, create_pipe, 0, &in_fd, &out_fd, fd_err, SORT_PATH, "-T", tmpdir, NULL); close(in_fd); if (dest_filename) { close(out_fd); } else { *fd_out = out_fd; } return pid; }
static void amstar_selfcheck( application_argument_t *argument) { fprintf(stdout, "OK amstar\n"); if (argument->dle.disk) { char *qdisk = quote_string(argument->dle.disk); fprintf(stdout, "OK %s\n", qdisk); amfree(qdisk); } if (argument->dle.device) { char *qdevice = quote_string(argument->dle.device); fprintf(stdout, "OK %s\n", qdevice); amfree(qdevice); } if (!star_path) { fprintf(stdout, "ERROR STAR-PATH not defined\n"); } else { check_file(star_path, X_OK); } if (argument->calcsize) { char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL); check_file(calcsize, X_OK); check_suid(calcsize); amfree(calcsize); } { char *amandates_file; amandates_file = getconf_str(CNF_AMANDATES); check_file(amandates_file, R_OK|W_OK); } }
tape_t * lookup_last_reusable_tape( int skip) { tape_t *tp, **tpsave; int count=0; int s; int tapecycle = getconf_int(CNF_TAPECYCLE); char *labelstr = getconf_str (CNF_LABELSTR); /* * The idea here is we keep the last "several" reusable tapes we * find in a stack and then return the n-th oldest one to the * caller. If skip is zero, the oldest is returned, if it is * one, the next oldest, two, the next to next oldest and so on. */ tpsave = g_malloc((skip + 1) * sizeof(*tpsave)); for(s = 0; s <= skip; s++) { tpsave[s] = NULL; } for(tp = tape_list; tp != NULL; tp = tp->next) { if(tp->reuse == 1 && !g_str_equal(tp->datestamp, "0") && match (labelstr, tp->label)) { count++; for(s = skip; s > 0; s--) { tpsave[s] = tpsave[s - 1]; } tpsave[0] = tp; } } s = tapecycle - count; if(s < 0) s = 0; if(count < tapecycle - skip) tp = NULL; else tp = tpsave[skip - s]; amfree(tpsave); return tp; }
gint64 internal_server_estimate( disk_t *dp, info_t *info, int level, int *stats) { int j; gint64 size = 0; *stats = 0; if (level == 0) { /* use latest level 0, should do extrapolation */ gint64 est_size = (gint64)0; int nb_est = 0; for (j=NB_HISTORY-2; j>=0; j--) { if (info->history[j].level == 0) { if (info->history[j].size < (gint64)0) continue; est_size = info->history[j].size; nb_est++; } } if (nb_est > 0) { size = est_size; *stats = 1; } else if (info->inf[level].size > (gint64)1000) { /* stats */ size = info->inf[level].size; *stats = 1; } else { char *conf_tapetype = getconf_str(CNF_TAPETYPE); tapetype_t *tape = lookup_tapetype(conf_tapetype); size = (gint64)1000000; if (size > tapetype_get_length(tape)/2) size = tapetype_get_length(tape)/2; *stats = 0; } } else if (level == info->last_level) { /* means of all X day at the same level */ #define NB_DAY 30 int nb_day = 0; gint64 est_size_day[NB_DAY]; int nb_est_day[NB_DAY]; for (j=0; j<NB_DAY; j++) { est_size_day[j] = (gint64)0; nb_est_day[j] = 0; } for (j=NB_HISTORY-2; j>=0; j--) { if (info->history[j].level <= 0) continue; if (info->history[j].size < (gint64)0) continue; if (info->history[j].level == info->history[j+1].level) { if (nb_day <NB_DAY-1) nb_day++; est_size_day[nb_day] += info->history[j].size; nb_est_day[nb_day]++; } else { nb_day=0; } } nb_day = info->consecutive_runs + 1; if (nb_day > NB_DAY-1) nb_day = NB_DAY-1; while (nb_day > 0 && nb_est_day[nb_day] == 0) nb_day--; if (nb_est_day[nb_day] > 0) { size = est_size_day[nb_day] / (gint64)nb_est_day[nb_day]; *stats = 1; } else if (info->inf[level].size > (gint64)1000) { /* stats */ size = info->inf[level].size; *stats = 1; } else { int level0_stat; gint64 level0_size; char *conf_tapetype = getconf_str(CNF_TAPETYPE); tapetype_t *tape = lookup_tapetype(conf_tapetype); level0_size = internal_server_estimate(dp, info, 0, &level0_stat); size = (gint64)10000; if (size > tapetype_get_length(tape)/2) size = tapetype_get_length(tape)/2; if (size > level0_size/2) size = level0_size/2; *stats = 0; } } else if (level == info->last_level + 1) { /* means of all first day at a new level */ gint64 est_size = (gint64)0; int nb_est = 0; for (j=NB_HISTORY-2; j>=0; j--) { if (info->history[j].level <= 0) continue; if (info->history[j].size < (gint64)0) continue; if (info->history[j].level == info->history[j+1].level + 1 ) { est_size += info->history[j].size; nb_est++; } } if (nb_est > 0) { size = est_size / (gint64)nb_est; *stats = 1; } else if (info->inf[level].size > (gint64)1000) { /* stats */ size = info->inf[level].size; *stats = 1; } else { int level0_stat; gint64 level0_size; char *conf_tapetype = getconf_str(CNF_TAPETYPE); tapetype_t *tape = lookup_tapetype(conf_tapetype); level0_size = internal_server_estimate(dp, info, 0, &level0_stat); size = (gint64)100000; if (size > tapetype_get_length(tape)/2) size = tapetype_get_length(tape)/2; if (size > level0_size/2) size = level0_size/2; *stats = 0; } } return size; }
void check_running_as(running_as_flags who) { #ifdef CHECK_USERID struct passwd *pw; uid_t uid_me; uid_t uid_target; char *uname_me = NULL; char *uname_target = NULL; char *dumpuser; uid_me = getuid(); if ((pw = getpwuid(uid_me)) == NULL) { error(_("current userid %ld not found in password database"), (long)uid_me); /* NOTREACHED */ } uname_me = g_strdup(pw->pw_name); #ifndef SINGLE_USERID if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) { error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"), (long long int)geteuid(), (long long int)uid_me); /* NOTREACHED */ } #endif switch (who & RUNNING_AS_USER_MASK) { case RUNNING_AS_ANY: uid_target = uid_me; uname_target = uname_me; amfree(uname_me); return; case RUNNING_AS_ROOT: uid_target = 0; uname_target = "root"; break; case RUNNING_AS_DUMPUSER_PREFERRED: dumpuser = getconf_str(CNF_DUMPUSER); if ((pw = getpwnam(dumpuser)) != NULL && uid_me != pw->pw_uid) { if ((pw = getpwnam(CLIENT_LOGIN)) != NULL && uid_me == pw->pw_uid) { /* uid == CLIENT_LOGIN: not ideal, but OK */ dbprintf(_("NOTE: running as '%s', which is the client" " user, not the dumpuser ('%s'); forging" " on anyway\n"), CLIENT_LOGIN, dumpuser); uid_target = uid_me; /* force success below */ break; } } /* FALLTHROUGH */ case RUNNING_AS_DUMPUSER: uname_target = getconf_str(CNF_DUMPUSER); if ((pw = getpwnam(uname_target)) == NULL) { error(_("cannot look up dumpuser \"%s\""), uname_target); /*NOTREACHED*/ } uid_target = pw->pw_uid; break; case RUNNING_AS_CLIENT_LOGIN: uname_target = CLIENT_LOGIN; if ((pw = getpwnam(uname_target)) == NULL) { error(_("cannot look up client user \"%s\""), uname_target); /*NOTREACHED*/ } uid_target = pw->pw_uid; break; default: error(_("Unknown check_running_as() call")); /* NOTREACHED */ } if (uid_me != uid_target) { error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target); /*NOTREACHED*/ } amfree(uname_me); #else /* Quiet unused variable warning */ (void)who; #endif }
void update_info_dumper( disk_t *dp, off_t origsize, off_t dumpsize, time_t dumptime) { int level, i; info_t info; stats_t *infp; perf_t *perfp; char *conf_infofile; level = sched(dp)->level; conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE)); if (open_infofile(conf_infofile)) { error(_("could not open info db \"%s\""), conf_infofile); /*NOTREACHED*/ } amfree(conf_infofile); get_info(dp->host->hostname, dp->name, &info); /* Clean up information about this and higher-level dumps. This assumes that update_info_dumper() is always run before update_info_taper(). */ for (i = level; i < DUMP_LEVELS; ++i) { infp = &info.inf[i]; infp->size = (off_t)-1; infp->csize = (off_t)-1; infp->secs = (time_t)-1; infp->date = (time_t)-1; infp->label[0] = '\0'; infp->filenum = 0; } /* now store information about this dump */ infp = &info.inf[level]; infp->size = origsize; infp->csize = dumpsize; infp->secs = dumptime; if (sched(dp)->timestamp == 0) { infp->date = 0; } else { infp->date = get_time_from_timestamp(sched(dp)->datestamp); } if(level == 0) perfp = &info.full; else perfp = &info.incr; /* Update the stats, but only if the new values are meaningful */ if(dp->compress != COMP_NONE && origsize > (off_t)0) { newperf(perfp->comp, (double)dumpsize/(double)origsize); } if(dumptime > (time_t)0) { if((off_t)dumptime >= dumpsize) newperf(perfp->rate, 1); else newperf(perfp->rate, (double)dumpsize/(double)dumptime); } if(origsize >= (off_t)0 && getconf_int(CNF_RESERVE)<100) { info.command = NO_COMMAND; } if (origsize >= (off_t)0 && level == info.last_level) { info.consecutive_runs++; } else if (origsize >= (off_t)0) { info.last_level = level; info.consecutive_runs = 1; } if(origsize >= (off_t)0 && dumpsize >= (off_t)0) { for(i=NB_HISTORY-1;i>0;i--) { info.history[i] = info.history[i-1]; } info.history[0].level = level; info.history[0].size = origsize; info.history[0].csize = dumpsize; if (sched(dp)->timestamp == 0) { info.history[0].date = 0; } else { info.history[0].date = get_time_from_timestamp(sched(dp)->datestamp); } info.history[0].secs = dumptime; } if (put_info(dp->host->hostname, dp->name, &info)) { int save_errno = errno; g_fprintf(stderr, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); log_add(L_ERROR, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); error(_("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); /*NOTREACHED*/ } close_infofile(); }
static char * taper_splitting_args( disk_t *dp) { GString *args = NULL; char *q = NULL; dumptype_t *dt = dp->config; tapetype_t *tt; tt = lookup_tapetype(getconf_str(CNF_TAPETYPE)); g_assert(tt != NULL); args = g_string_new(""); /* old dumptype-based parameters, using empty strings when not seen */ if (dt) { /* 'dt' may be NULL for flushes */ if (dumptype_seen(dt, DUMPTYPE_TAPE_SPLITSIZE)) { g_string_append_printf(args, "%ju ", (uintmax_t)dumptype_get_tape_splitsize(dt)*1024); } else { g_string_append(args, "\"\" "); } q = quote_string(dumptype_seen(dt, DUMPTYPE_SPLIT_DISKBUFFER)? dumptype_get_split_diskbuffer(dt) : ""); g_string_append_printf(args, "%s ", q); g_free(q); if (dumptype_seen(dt, DUMPTYPE_FALLBACK_SPLITSIZE)) { g_string_append_printf(args, "%ju ", (uintmax_t)dumptype_get_fallback_splitsize(dt)*1024); } else { g_string_append(args, "\"\" "); } if (dumptype_seen(dt, DUMPTYPE_ALLOW_SPLIT)) { g_string_append_printf(args, "%d ", (int)dumptype_get_allow_split(dt)); } else { g_string_append(args, "\"\" "); } } else { g_string_append(args, "\"\" \"\" \"\" \"\" "); } /* new tapetype-based parameters */ if (tapetype_seen(tt, TAPETYPE_PART_SIZE)) { g_string_append_printf(args, "%ju ", (uintmax_t)tapetype_get_part_size(tt)*1024); } else { g_string_append(args, "\"\" "); } q = ""; if (tapetype_seen(tt, TAPETYPE_PART_CACHE_TYPE)) { switch (tapetype_get_part_cache_type(tt)) { default: case PART_CACHE_TYPE_NONE: q = "none"; break; case PART_CACHE_TYPE_MEMORY: q = "memory"; break; case PART_CACHE_TYPE_DISK: q = "disk"; break; } } q = quote_string(q); g_string_append_printf(args, "%s ", q); g_free(q); q = quote_string(tapetype_seen(tt, TAPETYPE_PART_CACHE_DIR)? tapetype_get_part_cache_dir(tt) : ""); g_string_append_printf(args, "%s ", q); g_free(q); if (tapetype_seen(tt, TAPETYPE_PART_CACHE_MAX_SIZE)) { g_string_append_printf(args, "%ju ", (uintmax_t)tapetype_get_part_cache_max_size(tt)*1024); } else { g_string_append(args, "\"\" "); } return g_string_free(args, FALSE); }
int main( int argc, char ** argv) { int i; time_t timer; char *lineread = NULL; struct sigaction act, oact; extern char *optarg; extern int optind; char *line = NULL; const security_driver_t *secdrv; char *req = NULL; int response_error; struct tm *tm; config_overrides_t *cfg_ovr; char *starting_hostname = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); set_pname("amrecover"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_CLIENT); /* treat amrecover-specific command line options as the equivalent * -o command-line options to set configuration values */ cfg_ovr = new_config_overrides(argc/2); /* If the first argument is not an option flag, then we assume * it is a configuration name to match the syntax of the other * Amanda utilities. */ if (argc > 1 && argv[1][0] != '-') { add_config_override(cfg_ovr, "conf", argv[1]); /* remove that option from the command line */ argv[1] = argv[0]; argv++; argc--; } /* now parse regular command-line '-' options */ while ((i = getopt(argc, argv, "o:C:s:t:d:Uh:")) != EOF) { switch (i) { case 'C': add_config_override(cfg_ovr, "conf", optarg); break; case 's': add_config_override(cfg_ovr, "index_server", optarg); break; case 't': add_config_override(cfg_ovr, "tape_server", optarg); break; case 'd': add_config_override(cfg_ovr, "tapedev", optarg); break; case 'o': add_config_override_opt(cfg_ovr, optarg); break; case 'h': starting_hostname = g_strdup(optarg); break; case 'U': case '?': (void)g_printf(USAGE); return 0; } } if (optind != argc) { (void)g_fprintf(stderr, USAGE); exit(1); } /* load the base client configuration */ set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_CLIENT, NULL); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } /* and now try to load the configuration named in that file */ config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY, getconf_str(CNF_CONF)); check_running_as(RUNNING_AS_ROOT); dbrename(get_config_name(), DBG_SUBDIR_CLIENT); our_features = am_init_feature_set(); our_features_string = am_feature_to_string(our_features); if (!starting_hostname) { starting_hostname = g_malloc(MAX_HOSTNAME_LENGTH+1); if (gethostname(starting_hostname, MAX_HOSTNAME_LENGTH) != 0) { error(_("cannot determine local host name\n")); /*NOTREACHED*/ } starting_hostname[MAX_HOSTNAME_LENGTH] = '\0'; } server_name = NULL; if (getconf_seen(CNF_INDEX_SERVER) == -2) { /* command line argument */ server_name = getconf_str(CNF_INDEX_SERVER); } if (!server_name) { server_name = getenv("AMANDA_SERVER"); if (server_name) { g_printf(_("Using index server from environment AMANDA_SERVER (%s)\n"), server_name); } } if (!server_name) { server_name = getconf_str(CNF_INDEX_SERVER); } if (!server_name) { error(_("No index server set")); /*NOTREACHED*/ } server_name = g_strdup(server_name); tape_server_name = NULL; if (getconf_seen(CNF_TAPE_SERVER) == -2) { /* command line argument */ tape_server_name = getconf_str(CNF_TAPE_SERVER); } if (!tape_server_name) { tape_server_name = getenv("AMANDA_TAPE_SERVER"); if (!tape_server_name) { tape_server_name = getenv("AMANDA_TAPESERVER"); if (tape_server_name) { g_printf(_("Using tape server from environment AMANDA_TAPESERVER (%s)\n"), tape_server_name); } } else { g_printf(_("Using tape server from environment AMANDA_TAPE_SERVER (%s)\n"), tape_server_name); } } if (!tape_server_name) { tape_server_name = getconf_str(CNF_TAPE_SERVER); } if (!tape_server_name) { error(_("No tape server set")); /*NOTREACHED*/ } tape_server_name = g_strdup(tape_server_name); amfree(tape_device_name); tape_device_name = getconf_str(CNF_TAPEDEV); if (!tape_device_name || strlen(tape_device_name) == 0 || !getconf_seen(CNF_TAPEDEV)) { tape_device_name = NULL; } else { tape_device_name = g_strdup(tape_device_name); } authopt = g_strdup(getconf_str(CNF_AUTH)); amfree(disk_name); amfree(mount_point); amfree(disk_path); dump_date[0] = '\0'; /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); /* set up signal handler */ act.sa_handler = sigint_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGINT, &act, &oact) != 0) { error(_("error setting signal handler: %s"), strerror(errno)); /*NOTREACHED*/ } proplist = g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t); protocol_init(); /* We assume that amindexd support fe_amindexd_options_features */ /* and fe_amindexd_options_auth */ /* We should send a noop to really know */ req = g_strdup_printf("SERVICE amindexd\n" "OPTIONS features=%s;auth=%s;\n", our_features_string, authopt); secdrv = security_getdriver(authopt); if (secdrv == NULL) { error(_("no '%s' security driver available for host '%s'"), authopt, server_name); /*NOTREACHED*/ } protocol_sendreq(server_name, secdrv, generic_client_get_security_conf, req, STARTUP_TIMEOUT, amindexd_response, &response_error); amfree(req); protocol_run(); g_printf(_("AMRECOVER Version %s. Contacting server on %s ...\n"), VERSION, server_name); if(response_error != 0) { g_fprintf(stderr,"%s\n",errstr); exit(1); } /* get server's banner */ if (grab_reply(1) == -1) { aclose(server_socket); exit(1); } if (!server_happy()) { dbclose(); aclose(server_socket); exit(1); } /* try to get the features from the server */ { char *their_feature_string = NULL; indexsrv_features = NULL; line = g_strdup_printf("FEATURES %s", our_features_string); if(exchange(line) == 0) { their_feature_string = g_strdup(server_line+13); indexsrv_features = am_string_to_feature(their_feature_string); if (!indexsrv_features) g_printf(_("Bad feature string from server: %s"), their_feature_string); } if (!indexsrv_features) indexsrv_features = am_set_default_feature_set(); amfree(their_feature_string); amfree(line); } /* set the date of extraction to be today */ (void)time(&timer); tm = localtime(&timer); if (tm) strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", tm); else error(_("BAD DATE")); g_printf(_("Setting restore date to today (%s)\n"), dump_date); line = g_strdup_printf("DATE %s", dump_date); if (converse(line) == -1) { aclose(server_socket); exit(1); } amfree(line); line = g_strdup_printf("SCNF %s", get_config_name()); if (converse(line) == -1) { aclose(server_socket); exit(1); } amfree(line); if (server_happy()) { /* set host we are restoring to this host by default */ amfree(dump_hostname); set_host(starting_hostname); if (dump_hostname) g_printf(_("Use the setdisk command to choose dump disk to recover\n")); else g_printf(_("Use the sethost command to choose a host to recover\n")); } quit_prog = 0; do { if ((lineread = readline("amrecover> ")) == NULL) { clearerr(stdin); putchar('\n'); break; } if (lineread[0] != '\0') { add_history(lineread); dbprintf(_("user command: '%s'\n"), lineread); process_line(lineread); /* act on line's content */ } amfree(lineread); } while (!quit_prog); dbclose(); aclose(server_socket); return 0; }
/* * doing similar to $ gtar | compression | encryption */ static void start_backup( dle_t *dle, char *host, int dataf, int mesgf, int indexf) { char tmppath[PATH_MAX]; int dumpin, dumpout, compout; char *cmd = NULL; char *indexcmd = NULL; char *dirname = NULL; int l; char dumptimestr[80] = "UNUSED"; struct tm *gmtm; amandates_t *amdates = NULL; time_t prev_dumptime = 0; char *error_pn = NULL; char *compopt = NULL; char *encryptopt = skip_argument; char *tquoted; char *fquoted; char *qdisk; int infd, outfd; ssize_t nb; char buf[32768]; char *amandates_file = NULL; am_level_t *alevel = (am_level_t *)dle->levellist->data; int level = alevel->level; int native_pipe[2]; int client_pipe[2]; int data_out; have_filter = FALSE; crc32_init(&native_crc.crc); crc32_init(&client_crc.crc); /* create pipes to compute the native CRC */ if (pipe(native_pipe) < 0) { char *errmsg; char *qerrmsg; errmsg = g_strdup_printf(_("Program '%s': can't create pipe"), dle->program); qerrmsg = quote_string(errmsg); fdprintf(mesgf, _("sendbackup: error [%s]\n"), errmsg); dbprintf(_("ERROR %s\n"), qerrmsg); amfree(qerrmsg); amfree(errmsg); return; } if (dle->encrypt == ENCRYPT_CUST || dle->compress == COMP_FAST || dle->compress == COMP_BEST || dle->compress == COMP_CUST) { have_filter = TRUE; /* create pipes to compute the client CRC */ if (pipe(client_pipe) < 0) { char *errmsg; char *qerrmsg; errmsg = g_strdup_printf(_("Application '%s': can't create pipe"), dle->program); qerrmsg = quote_string(errmsg); fdprintf(mesgf, _("sendbackup: error [%s]\n"), errmsg); dbprintf(_("ERROR %s\n"), qerrmsg); amfree(qerrmsg); amfree(errmsg); return; } data_out = client_pipe[1]; client_pipe[1] = -1; } else { data_out = dataf; dataf = -1; } error_pn = g_strconcat(get_pname(), "-smbclient", NULL); qdisk = quote_string(dle->disk); dbprintf(_("start: %s:%s lev %d\n"), host, qdisk, level); g_fprintf(stderr, _("%s: start [%s:%s level %d]\n"), get_pname(), host, qdisk, level); /* apply client-side encryption here */ if ( dle->encrypt == ENCRYPT_CUST ) { encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0, &compout, &data_out, &mesgf, dle->clnt_encrypt, encryptopt, NULL); dbprintf(_("gnutar: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt); aclose(data_out); } else { compout = data_out; data_out = -1; encpid = -1; } /* now do the client-side compression */ if (dle->compress == COMP_FAST || dle->compress == COMP_BEST) { compopt = skip_argument; #if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT) if(dle->compress == COMP_BEST) { compopt = COMPRESS_BEST_OPT; } else { compopt = COMPRESS_FAST_OPT; } #endif comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0, &dumpout, &compout, &mesgf, COMPRESS_PATH, compopt, NULL); dbprintf(_("gnutar: pid %ld: %s"), (long)comppid, COMPRESS_PATH); if(compopt != skip_argument) { dbprintf(_("pid %ld: %s %s\n"), (long)comppid, COMPRESS_PATH, compopt); } else { dbprintf(_("pid %ld: %s\n"), (long)comppid, COMPRESS_PATH); } aclose(compout); } else if (dle->compress == COMP_CUST) { compopt = skip_argument; comppid = pipespawn(dle->compprog, STDIN_PIPE, 0, &dumpout, &compout, &mesgf, dle->compprog, compopt, NULL); if(compopt != skip_argument) { dbprintf(_("pid %ld: %s %s\n"), (long)comppid, dle->compprog, compopt); } else { dbprintf(_("pid %ld: %s\n"), (long)comppid, dle->compprog); } aclose(compout); } else { dumpout = compout; compout = -1; comppid = -1; } gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR); if (strlen(gnutar_list_dir) == 0) gnutar_list_dir = NULL; #ifdef SAMBA_CLIENT /* { */ if (dle->device[0] == '/' && dle->device[1]=='/') amfree(incrname); else #endif /* } */ if (gnutar_list_dir) { char *basename = NULL; char number[NUM_STR_SIZE]; char *inputname = NULL; int baselevel; char *sdisk = sanitise_filename(dle->disk); basename = g_strjoin(NULL, gnutar_list_dir, "/", host, sdisk, NULL); amfree(sdisk); g_snprintf(number, sizeof(number), "%d", level); incrname = g_strjoin(NULL, basename, "_", number, ".new", NULL); unlink(incrname); /* * Open the listed incremental file from the previous level. Search * backward until one is found. If none are found (which will also * be true for a level 0), arrange to read from /dev/null. */ baselevel = level; infd = -1; while (infd == -1) { if (--baselevel >= 0) { g_snprintf(number, sizeof(number), "%d", baselevel); g_free(inputname); inputname = g_strconcat(basename, "_", number, NULL); } else { g_free(inputname); inputname = g_strdup("/dev/null"); } if ((infd = open(inputname, O_RDONLY)) == -1) { int save_errno = errno; char *qname = quote_string(inputname); dbprintf(_("gnutar: error opening '%s': %s\n"), qname, strerror(save_errno)); if (baselevel < 0) { error(_("error [opening '%s': %s]"), qname, strerror(save_errno)); /*NOTREACHED*/ } amfree(qname); } } /* * Copy the previous listed incremental file to the new one. */ if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) { error(_("error [opening '%s': %s]"), incrname, strerror(errno)); /*NOTREACHED*/ } while ((nb = read(infd, &buf, sizeof(buf))) > 0) { if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) { error(_("error [writing to '%s': %s]"), incrname, strerror(errno)); /*NOTREACHED*/ } } if (nb < 0) { error(_("error [reading from '%s': %s]"), inputname, strerror(errno)); /*NOTREACHED*/ } if (close(infd) != 0) { error(_("error [closing '%s': %s]"), inputname, strerror(errno)); /*NOTREACHED*/ } if (close(outfd) != 0) { error(_("error [closing '%s': %s]"), incrname, strerror(errno)); /*NOTREACHED*/ } tquoted = quote_string(incrname); if(baselevel >= 0) { fquoted = quote_string(inputname); dbprintf(_("doing level %d dump as listed-incremental from '%s' to '%s'\n"), level, fquoted, tquoted); amfree(fquoted); } else { dbprintf(_("doing level %d dump as listed-incremental to '%s'\n"), level, tquoted); } amfree(tquoted); amfree(inputname); amfree(basename); } else { /* no gnutar-listdir, so we're using amandates */ /* find previous dump time, failing completely if there's a problem */ amandates_file = getconf_str(CNF_AMANDATES); if(!start_amandates(amandates_file, 0)) { error(_("error [opening %s: %s]"), amandates_file, strerror(errno)); /*NOTREACHED*/ } amdates = amandates_lookup(dle->disk); prev_dumptime = EPOCH; for(l = 0; l < level; l++) { if(amdates->dates[l] > prev_dumptime) prev_dumptime = amdates->dates[l]; } finish_amandates(); free_amandates(); gmtm = gmtime(&prev_dumptime); g_snprintf(dumptimestr, sizeof(dumptimestr), "%04d-%02d-%02d %2d:%02d:%02d GMT", gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday, gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec); dbprintf(_("gnutar: doing level %d dump from amandates-derived date: %s\n"), level, dumptimestr); } dirname = amname_to_dirname(dle->device); cur_dumptime = time(0); cur_level = level; cur_disk = g_strdup(dle->disk); #ifdef GNUTAR # define PROGRAM_GNUTAR GNUTAR #else # define PROGRAM_GNUTAR "tar" #endif indexcmd = g_strjoin(NULL, PROGRAM_GNUTAR, " -tf", " -", " 2>/dev/null", " | sed", " -e", " \'s/^\\.//\'", NULL); #ifdef SAMBA_CLIENT /* { */ /* Use sambatar if the disk to back up is a PC disk */ if (dle->device[0] == '/' && dle->device[1]=='/') { char *sharename = NULL, *user_and_password = NULL, *domain = NULL; char *share = NULL, *subdir = NULL; char *pwtext = NULL; char *taropt; int passwdf = -1; size_t lpass; size_t pwtext_len; char *pw_fd_env; parsesharename(dle->device, &share, &subdir); if (!share) { amfree(share); amfree(subdir); set_pname(error_pn); amfree(error_pn); error(_("cannot parse disk entry %s for share/subdir"), qdisk); /*NOTREACHED*/ } if ((subdir) && (SAMBA_VERSION < 2)) { amfree(share); amfree(subdir); set_pname(error_pn); amfree(error_pn); error(_("subdirectory specified for share %s but samba not v2 or better"), qdisk); /*NOTREACHED*/ } if ((user_and_password = findpass(share, &domain)) == NULL) { if(domain) { memset(domain, '\0', strlen(domain)); amfree(domain); } set_pname(error_pn); amfree(error_pn); error(_("error [invalid samba host or password not found?]")); /*NOTREACHED*/ } lpass = strlen(user_and_password); if ((pwtext = strchr(user_and_password, '%')) == NULL) { memset(user_and_password, '\0', lpass); amfree(user_and_password); if(domain) { memset(domain, '\0', strlen(domain)); amfree(domain); } set_pname(error_pn); amfree(error_pn); error(_("password field not \'user%%pass\' for %s"), qdisk); /*NOTREACHED*/ } *pwtext++ = '\0'; pwtext_len = strlen(pwtext); if ((sharename = makesharename(share, 0)) == 0) { memset(user_and_password, '\0', lpass); amfree(user_and_password); if(domain) { memset(domain, '\0', strlen(domain)); amfree(domain); } set_pname(error_pn); amfree(error_pn); error(_("error [can't make share name of %s]"), share); /*NOTREACHED*/ } taropt = g_strdup("-T"); if(dle->exclude_file && dle->exclude_file->nb_element == 1) { strappend(taropt, "X"); } #if SAMBA_VERSION >= 2 strappend(taropt, "q"); #endif strappend(taropt, "c"); if (level != 0) { strappend(taropt, "g"); } else if (dle->record) { strappend(taropt, "a"); } if (subdir) { dbprintf(_("gnutar: backup of %s/%s\n"), sharename, subdir); } else { dbprintf(_("gnutar: backup of %s\n"), sharename); } program->backup_name = program->restore_name = SAMBA_CLIENT; cmd = g_strdup(program->backup_name); info_tapeheader(dle); start_index(dle->create_index, native_pipe[1], mesgf, indexf, indexcmd); if (pwtext_len > 0) { pw_fd_env = "PASSWD_FD"; } else { pw_fd_env = "dummy_PASSWD_FD"; } dumppid = pipespawn(cmd, STDIN_PIPE|PASSWD_PIPE, 0, &dumpin, &native_pipe[1], &mesgf, pw_fd_env, &passwdf, "smbclient", sharename, *user_and_password ? "-U" : skip_argument, *user_and_password ? user_and_password : skip_argument, "-E", domain ? "-W" : skip_argument, domain ? domain : skip_argument, #if SAMBA_VERSION >= 2 subdir ? "-D" : skip_argument, subdir ? subdir : skip_argument, #endif "-d0", taropt, "-", dle->exclude_file && dle->exclude_file->nb_element == 1 ? dle->exclude_file->first->name : skip_argument, NULL); if(domain) { memset(domain, '\0', strlen(domain)); amfree(domain); } if(pwtext_len > 0 && full_write(passwdf, pwtext, pwtext_len) < pwtext_len) { int save_errno = errno; aclose(passwdf); memset(user_and_password, '\0', lpass); amfree(user_and_password); set_pname(error_pn); amfree(error_pn); error(_("error [password write failed: %s]"), strerror(save_errno)); /*NOTREACHED*/ } memset(user_and_password, '\0', lpass); amfree(user_and_password); aclose(passwdf); amfree(sharename); amfree(share); amfree(subdir); amfree(taropt); tarpid = dumppid; } else #endif /*end of samba */ { int nb_exclude = 0; int nb_include = 0; GPtrArray *argv_ptr = g_ptr_array_new(); char *file_exclude = NULL; char *file_include = NULL; messagelist_t mlist = NULL; if (dle->exclude_file) nb_exclude+=dle->exclude_file->nb_element; if (dle->exclude_list) nb_exclude+=dle->exclude_list->nb_element; if (dle->include_file) nb_include+=dle->include_file->nb_element; if (dle->include_list) nb_include+=dle->include_list->nb_element; if (nb_exclude > 0) file_exclude = build_exclude(dle, &mlist); if (nb_include > 0) file_include = build_include(dle, dirname, &mlist); g_slist_free(mlist); // MUST also free the message cmd = g_strjoin(NULL, amlibexecdir, "/", "runtar", NULL); info_tapeheader(dle); start_index(dle->create_index, native_pipe[1], mesgf, indexf, indexcmd); g_ptr_array_add(argv_ptr, g_strdup("runtar")); if (g_options->config) g_ptr_array_add(argv_ptr, g_strdup(g_options->config)); else g_ptr_array_add(argv_ptr, g_strdup("NOCONFIG")); #ifdef GNUTAR g_ptr_array_add(argv_ptr, g_strdup(GNUTAR)); #else g_ptr_array_add(argv_ptr, g_strdup("tar")); #endif g_ptr_array_add(argv_ptr, g_strdup("--create")); g_ptr_array_add(argv_ptr, g_strdup("--file")); g_ptr_array_add(argv_ptr, g_strdup("-")); g_ptr_array_add(argv_ptr, g_strdup("--directory")); canonicalize_pathname(dirname, tmppath); g_ptr_array_add(argv_ptr, g_strdup(tmppath)); g_ptr_array_add(argv_ptr, g_strdup("--one-file-system")); if (gnutar_list_dir && incrname) { g_ptr_array_add(argv_ptr, g_strdup("--listed-incremental")); g_ptr_array_add(argv_ptr, g_strdup(incrname)); } else { g_ptr_array_add(argv_ptr, g_strdup("--incremental")); g_ptr_array_add(argv_ptr, g_strdup("--newer")); g_ptr_array_add(argv_ptr, g_strdup(dumptimestr)); } #ifdef ENABLE_GNUTAR_ATIME_PRESERVE /* --atime-preserve causes gnutar to call * utime() after reading files in order to * adjust their atime. However, utime() * updates the file's ctime, so incremental * dumps will think the file has changed. */ g_ptr_array_add(argv_ptr, g_strdup("--atime-preserve")); #endif g_ptr_array_add(argv_ptr, g_strdup("--sparse")); g_ptr_array_add(argv_ptr, g_strdup("--ignore-failed-read")); g_ptr_array_add(argv_ptr, g_strdup("--totals")); if(file_exclude) { g_ptr_array_add(argv_ptr, g_strdup("--exclude-from")); g_ptr_array_add(argv_ptr, g_strdup(file_exclude)); } if(file_include) { g_ptr_array_add(argv_ptr, g_strdup("--files-from")); g_ptr_array_add(argv_ptr, g_strdup(file_include)); } else { g_ptr_array_add(argv_ptr, g_strdup(".")); } g_ptr_array_add(argv_ptr, NULL); dumppid = pipespawnv(cmd, STDIN_PIPE, 0, &dumpin, &native_pipe[1], &mesgf, (char **)argv_ptr->pdata); tarpid = dumppid; amfree(file_exclude); amfree(file_include); g_ptr_array_free_full(argv_ptr); } dbprintf(_("gnutar: %s: pid %ld\n"), cmd, (long)dumppid); amfree(qdisk); amfree(dirname); amfree(cmd); amfree(indexcmd); amfree(error_pn); /* close the write ends of the pipes */ aclose(dumpin); aclose(native_pipe[1]); aclose(mesgf); if (dle->create_index) aclose(indexf); if (shm_control_name) { shm_ring = shm_ring_link(shm_control_name); shm_ring_producer_set_size(shm_ring, NETWORK_BLOCK_BYTES*16, NETWORK_BLOCK_BYTES*4); native_crc.in = native_pipe[0]; if (!have_filter) { native_crc.out = dumpout; native_crc.shm_ring = shm_ring; native_crc.thread = g_thread_create(handle_crc_to_shm_ring_thread, (gpointer)&native_crc, TRUE, NULL); } else { native_crc.out = dumpout; native_crc.thread = g_thread_create(handle_crc_thread, (gpointer)&native_crc, TRUE, NULL); client_crc.in = client_pipe[0]; client_crc.out = dataf; client_crc.shm_ring = shm_ring; client_crc.thread = g_thread_create(handle_crc_to_shm_ring_thread, (gpointer)&client_crc, TRUE, NULL); } } else { native_crc.in = native_pipe[0]; native_crc.out = dumpout; native_crc.thread = g_thread_create(handle_crc_thread, (gpointer)&native_crc, TRUE, NULL); if (have_filter) { client_crc.in = client_pipe[0]; client_crc.out = dataf; client_crc.thread = g_thread_create(handle_crc_thread, (gpointer)&client_crc, TRUE, NULL); } } }
int main( int argc, char ** argv) { int c; char *command; application_argument_t argument; int i; #ifdef GNUTAR gnutar_path = GNUTAR; #else gnutar_path = NULL; #endif gnutar_directory = NULL; gnutar_onefilesystem = 1; gnutar_atimepreserve = 1; gnutar_checkdevice = 1; gnutar_sparse = 1; gnutar_no_unquote = 0; exit_handling = NULL; /* initialize */ /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); if (argc < 2) { printf("ERROR no command given to amgtar\n"); error(_("No command given to amgtar")); } /* drop root privileges */ if (!set_root_privs(0)) { if (strcmp(argv[1], "selfcheck") == 0) { printf("ERROR amgtar must be run setuid root\n"); } error(_("amgtar must be run setuid root")); } safe_fd(3, 2); set_pname("amgtar"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); #if defined(USE_DBMALLOC) malloc_size_1 = malloc_inuse(&malloc_hist_1); #endif add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_syslog); dbopen(DBG_SUBDIR_CLIENT); startclock(); dbprintf(_("version %s\n"), version()); config_init(CONFIG_INIT_CLIENT, NULL); //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED); //root for amrecover //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup /* parse argument */ command = argv[1]; argument.config = NULL; argument.host = NULL; argument.message = 0; argument.collection = 0; argument.calcsize = 0; argument.tar_blocksize = NULL; argument.level = NULL; init_dle(&argument.dle); while (1) { int option_index = 0; c = getopt_long (argc, argv, "", long_options, &option_index); if (c == -1) { break; } switch (c) { case 1: argument.config = stralloc(optarg); break; case 2: argument.host = stralloc(optarg); break; case 3: argument.dle.disk = stralloc(optarg); break; case 4: argument.dle.device = stralloc(optarg); break; case 5: argument.level = g_slist_append(argument.level, GINT_TO_POINTER(atoi(optarg))); break; case 6: argument.dle.create_index = 1; break; case 7: argument.message = 1; break; case 8: argument.collection = 1; break; case 9: argument.dle.record = 1; break; case 10: gnutar_path = stralloc(optarg); break; case 11: gnutar_listdir = stralloc(optarg); break; case 12: if (optarg && strcasecmp(optarg, "NO") == 0) gnutar_onefilesystem = 0; else if (optarg && strcasecmp(optarg, "YES") == 0) gnutar_onefilesystem = 1; else if (strcasecmp(command, "selfcheck") == 0) printf(_("ERROR [%s: bad ONE-FILE-SYSTEM property value (%s)]\n"), get_pname(), optarg); break; case 13: if (optarg && strcasecmp(optarg, "NO") == 0) gnutar_sparse = 0; else if (optarg && strcasecmp(optarg, "YES") == 0) gnutar_sparse = 1; else if (strcasecmp(command, "selfcheck") == 0) printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg); break; case 14: if (optarg && strcasecmp(optarg, "NO") == 0) gnutar_atimepreserve = 0; else if (optarg && strcasecmp(optarg, "YES") == 0) gnutar_atimepreserve = 1; else if (strcasecmp(command, "selfcheck") == 0) printf(_("ERROR [%s: bad ATIME-PRESERVE property value (%s)]\n"), get_pname(), optarg); break; case 15: if (optarg && strcasecmp(optarg, "NO") == 0) gnutar_checkdevice = 0; else if (optarg && strcasecmp(optarg, "YES") == 0) gnutar_checkdevice = 1; else if (strcasecmp(command, "selfcheck") == 0) printf(_("ERROR [%s: bad CHECK-DEVICE property value (%s)]\n"), get_pname(), optarg); break; case 16: if (optarg) argument.dle.include_file = append_sl(argument.dle.include_file, optarg); break; case 17: if (optarg) argument.dle.include_list = append_sl(argument.dle.include_list, optarg); break; case 18: argument.dle.include_optional = 1; break; case 19: if (optarg) argument.dle.exclude_file = append_sl(argument.dle.exclude_file, optarg); break; case 20: if (optarg) argument.dle.exclude_list = append_sl(argument.dle.exclude_list, optarg); break; case 21: argument.dle.exclude_optional = 1; break; case 22: gnutar_directory = stralloc(optarg); break; case 23: if (optarg) normal_message = g_slist_append(normal_message, optarg); break; case 24: if (optarg) ignore_message = g_slist_append(ignore_message, optarg); break; case 25: if (optarg) strange_message = g_slist_append(strange_message, optarg); break; case 26: if (optarg) exit_handling = stralloc(optarg); break; case 27: argument.calcsize = 1; break; case 28: argument.tar_blocksize = stralloc(optarg); break; case 29: if (optarg && strcasecmp(optarg, "NO") == 0) gnutar_no_unquote = 0; else if (optarg && strcasecmp(optarg, "YES") == 0) gnutar_no_unquote = 1; else if (strcasecmp(command, "selfcheck") == 0) printf(_("ERROR [%s: bad No_UNQUOTE property value (%s)]\n"), get_pname(), optarg); break; case ':': case '?': break; } } argument.argc = argc - optind; argument.argv = argv + optind; if (argument.config) { config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY, argument.config); dbrename(get_config_name(), DBG_SUBDIR_CLIENT); } if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } re_table = build_re_table(init_re_table, normal_message, ignore_message, strange_message); for(i=0;i<256;i++) exit_value[i] = 1; /* BAD */ exit_value[0] = 0; /* GOOD */ exit_value[1] = 0; /* GOOD */ if (exit_handling) { char *s = exit_handling; while (s) { char *r = strchr(s, '='); if (r) { int j = atoi(s); if (j >= 0 && j < 256) { r++; if (strncasecmp(r, "GOOD", 4) == 0) { exit_value[j] = 0; } } } s = strchr(s+1, ' '); } } gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR); if (strlen(gnutar_listdir) == 0) gnutar_listdir = NULL; if (gnutar_path) { dbprintf("GNUTAR-PATH %s\n", gnutar_path); } else { dbprintf("GNUTAR-PATH is not set\n"); } if (gnutar_listdir) { dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir); } else { dbprintf("GNUTAR-LISTDIR is not set\n"); } if (gnutar_directory) { dbprintf("DIRECTORY %s\n", gnutar_directory); } dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no"); dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no"); dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no"); dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no"); dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no"); { amregex_t *rp; for (rp = re_table; rp->regex != NULL; rp++) { switch (rp->typ) { case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break; case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break; case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break; case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break; case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break; } } } if (strcmp(command, "support") == 0) { amgtar_support(&argument); } else if (strcmp(command, "selfcheck") == 0) { amgtar_selfcheck(&argument); } else if (strcmp(command, "estimate") == 0) { amgtar_estimate(&argument); } else if (strcmp(command, "backup") == 0) { amgtar_backup(&argument); } else if (strcmp(command, "restore") == 0) { amgtar_restore(&argument); } else if (strcmp(command, "validate") == 0) { amgtar_validate(&argument); } else { dbprintf("Unknown command `%s'.\n", command); fprintf(stderr, "Unknown command `%s'.\n", command); exit (1); } return 0; }
int main( int argc, char ** argv) { GList *dlist; GList *dlist1; disk_t *diskp; disklist_t diskl; size_t i; char *conf_diskfile; char *conf_tapelist; char *conf_indexdir; find_result_t *output_find; time_t tmp_time; int amtrmidx_debug = 0; config_overrides_t *cfg_ovr = NULL; gboolean compress_index; gboolean sort_index; char *lock_file; file_lock *lock_index; if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) { printf("amtrmidx-%s\n", VERSION); return (0); } /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmidx"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], VERSION); cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc > 1 && g_str_equal(argv[1], "-t")) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } set_config_overrides(cfg_ovr); config_init_with_global(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, argv[1]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); compress_index = getconf_boolean(CNF_COMPRESS_INDEX); sort_index = getconf_boolean(CNF_SORT_INDEX); output_find = find_dump(&diskl); conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR)); /* take a lock file to prevent concurent trim */ lock_file = g_strdup_printf("%s/%s", conf_indexdir, "lock"); lock_index = file_lock_new(lock_file); if (file_lock_lock_wr(lock_index) != 0) goto lock_failed; /* now go through the list of disks and find which have indexes */ time(&tmp_time); tmp_time -= 7*24*60*60; /* back one week */ for (dlist = diskl.head; dlist != NULL; dlist = dlist->next) { diskp = dlist->data; if (diskp->index) { char *indexdir, *qindexdir; DIR *d; struct dirent *f; char **names; size_t name_length; size_t name_count; char *host; char *disk, *qdisk; size_t len_date; disk_t *dp; GSList *matching_dp = NULL; /* get listing of indices, newest first */ host = sanitise_filename(diskp->host->hostname); disk = sanitise_filename(diskp->name); qdisk = quote_string(diskp->name); indexdir = g_strjoin(NULL, conf_indexdir, "/", host, "/", disk, "/", NULL); qindexdir = quote_string(indexdir); /* find all dles that use the same indexdir */ for (dlist1 = diskl.head; dlist1 != NULL; dlist1 = dlist1->next) { char *dp_host, *dp_disk; dp = dlist1->data; dp_host = sanitise_filename(dp->host->hostname); dp_disk = sanitise_filename(dp->name); if (g_str_equal(host, dp_host) && g_str_equal(disk, dp_disk)) { matching_dp = g_slist_append(matching_dp, dp); } amfree(dp_host); amfree(dp_disk); } dbprintf("%s %s -> %s\n", diskp->host->hostname, qdisk, qindexdir); amfree(qdisk); if ((d = opendir(indexdir)) == NULL) { dbprintf(_("could not open index directory %s\n"), qindexdir); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); g_slist_free(matching_dp); continue; } name_length = 100; names = (char **)g_malloc(name_length * sizeof(char *)); name_count = 0; while ((f = readdir(d)) != NULL) { size_t l; if(is_dot_or_dotdot(f->d_name)) { continue; } for(i = 0; i < sizeof("YYYYMMDDHHMMSS")-1; i++) { if(! isdigit((int)(f->d_name[i]))) { break; } } len_date = i; /* len_date=8 for YYYYMMDD */ /* len_date=14 for YYYYMMDDHHMMSS */ if((len_date != 8 && len_date != 14) || f->d_name[len_date] != '_' || ! isdigit((int)(f->d_name[len_date+1]))) { continue; /* not an index file */ } /* * Clear out old index temp files. */ l = strlen(f->d_name) - (sizeof(".tmp")-1); if ((l > (len_date + 1)) && (g_str_equal(f->d_name + l, ".tmp"))) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, f->d_name, NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); continue; } if(name_count >= name_length) { char **new_names; new_names = g_malloc((name_length * 2) * sizeof(char *)); memcpy(new_names, names, name_length * sizeof(char *)); amfree(names); names = new_names; name_length *= 2; } names[name_count++] = g_strdup(f->d_name); } closedir(d); qsort(names, name_count, sizeof(char *), sort_by_name_reversed); /* * Search for the first full dump past the minimum number * of index files to keep. */ for(i = 0; i < name_count; i++) { char *datestamp; int level; size_t len_date; int matching = 0; GSList *mdp; for(len_date = 0; len_date < sizeof("YYYYMMDDHHMMSS")-1; len_date++) { if(! isdigit((int)(names[i][len_date]))) { break; } } datestamp = g_strdup(names[i]); datestamp[len_date] = '\0'; if (sscanf(&names[i][len_date+1], "%d", &level) != 1) level = 0; for (mdp = matching_dp; mdp != NULL; mdp = mdp->next) { dp = mdp->data; if (dump_exist(output_find, dp->host->hostname, dp->name, datestamp, level)) { matching = 1; } } if (!matching) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, names[i], NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); } /* Did it require un/compression and/or sorting */ { char *orig_name = getindexfname(host, disk, datestamp, level); char *sorted_name = getindex_sorted_fname(host, disk, datestamp, level); char *sorted_gz_name = getindex_sorted_gz_fname(host, disk, datestamp, level); char *unsorted_name = getindex_unsorted_fname(host, disk, datestamp, level); char *unsorted_gz_name = getindex_unsorted_gz_fname(host, disk, datestamp, level); gboolean orig_exist = FALSE; gboolean sorted_exist = FALSE; gboolean sorted_gz_exist = FALSE; gboolean unsorted_exist = FALSE; gboolean unsorted_gz_exist = FALSE; int fd; int uncompress_err_fd = -1; int sort_err_fd = -1; int compress_err_fd = -1; pid_t uncompress_pid = -1; pid_t sort_pid = -1; pid_t compress_pid = -1; orig_exist = file_exists(orig_name); sorted_exist = file_exists(sorted_name); sorted_gz_exist = file_exists(sorted_gz_name); unsorted_exist = file_exists(unsorted_name); unsorted_gz_exist = file_exists(unsorted_gz_name); if (sort_index && compress_index) { if (!sorted_gz_exist) { if (sorted_exist) { // COMPRESS compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // SORT AND COMPRESS sort_pid = run_sort(-1, &fd, &sort_err_fd, unsorted_name, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(orig_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (sort_index && !compress_index) { if (!sorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_exist) { // SORT sort_pid = run_sort(-1, NULL, &sort_err_fd, unsorted_name, sorted_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && compress_index) { if (!sorted_gz_exist && !unsorted_gz_exist) { if (sorted_exist) { // COMPRESS sorted compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // COMPRESS unsorted compress_pid = run_compress(-1, NULL, &compress_err_fd, unsorted_name, unsorted_gz_name); unlink(unsorted_name); } else if (orig_exist) { // RENAME orig rename(orig_name, unsorted_gz_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (sorted_gz_exist && unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && !compress_index) { if (!sorted_exist && !unsorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS sorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_gz_exist) { // UNCOMPRESS unsorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, unsorted_gz_name, unsorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS orig uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, orig_name, unsorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } if (sorted_exist && unsorted_exist) { unlink(unsorted_name); } } } if (uncompress_pid != -1) wait_process(uncompress_pid, uncompress_err_fd, "uncompress"); if (sort_pid != -1) wait_process(sort_pid, sort_err_fd, "sort"); if (compress_pid != -1) wait_process(compress_pid, compress_err_fd, "compress"); g_free(orig_name); g_free(sorted_name); g_free(sorted_gz_name); g_free(unsorted_name); g_free(unsorted_gz_name); } amfree(datestamp); amfree(names[i]); } g_slist_free(matching_dp); amfree(names); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); } } file_lock_unlock(lock_index); lock_failed: file_lock_free(lock_index); amfree(conf_indexdir); amfree(lock_file); free_find_result(&output_find); clear_tapelist(); free_disklist(&diskl); unload_disklist(); dbclose(); return 0; }
/* * ssl version of a security handle allocator. Logically sets * up a network "connection". */ static void ssl_connect( const char *hostname, char * (*conf_fn)(char *, void *), void (*fn)(void *, security_handle_t *, security_status_t), void * arg, void * datap) { struct sec_handle *rh; int result; char *canonname; char *service; in_port_t port; char *src_ip = NULL; char *ssl_dir = NULL; char *ssl_fingerprint_file = NULL; char *ssl_cert_file = NULL; char *ssl_key_file = NULL; char *ssl_ca_cert_file = NULL; char *ssl_cipher_list = NULL; int ssl_check_certificate_host = 1; assert(fn != NULL); assert(hostname != NULL); auth_debug(1, _("ssl: ssl_connect: %s\n"), hostname); rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, &ssl_security_driver); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; result = resolve_hostname(hostname, 0, NULL, &canonname); if(result != 0) { g_debug(_("resolve_hostname(%s): %s"), hostname, gai_strerror(result)); security_seterror(&rh->sech, _("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result)); (*fn)(arg, &rh->sech, S_ERROR); return; } if (canonname == NULL) { g_debug(_("resolve_hostname(%s) did not return a canonical name"), hostname); security_seterror(&rh->sech, _("resolve_hostname(%s) did not return a canonical name\n"), hostname); (*fn)(arg, &rh->sech, S_ERROR); return; } rh->hostname = canonname; /* will be replaced */ canonname = NULL; /* steal reference */ rh->rs = tcpma_stream_client(rh, newhandle++); rh->rc->recv_security_ok = &bsd_recv_security_ok; rh->rc->prefix_packet = &bsd_prefix_packet; rh->rc->need_priv_port = 0; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = g_strdup(rh->rs->rc->hostname); ssl_dir = getconf_str(CNF_SSL_DIR); if (conf_fn) { service = conf_fn("remote_port", datap); if (!service || strlen(service) <= 1) service = AMANDA_SERVICE_NAME; g_debug("Connecting to service '%s'", service); src_ip = conf_fn("src_ip", datap); ssl_fingerprint_file = g_strdup(conf_fn("ssl_fingerprint_file", datap)); ssl_cert_file = g_strdup(conf_fn("ssl_cert_file", datap)); ssl_key_file = g_strdup(conf_fn("ssl_key_file", datap)); ssl_ca_cert_file = g_strdup(conf_fn("ssl_ca_cert_file", datap)); ssl_cipher_list = conf_fn("ssl_cipher_list", datap); ssl_check_certificate_host = atoi(conf_fn("ssl_check_certificate_host", datap)); } else { service = AMANDA_SERVICE_NAME; } if (ssl_dir) { if (!ssl_cert_file || ssl_cert_file == '\0') { ssl_cert_file = g_strdup_printf("%s/me/crt.pem", ssl_dir); } if (!ssl_key_file || ssl_key_file == '\0') { ssl_key_file = g_strdup_printf("%s/me/private/key.pem", ssl_dir); } if (!ssl_ca_cert_file || ssl_ca_cert_file == '\0') { ssl_ca_cert_file = g_strdup_printf("%s/CA/crt.pem", ssl_dir); } if (!ssl_fingerprint_file || ssl_fingerprint_file == '\0') { struct stat statbuf; ssl_fingerprint_file = g_strdup_printf("%s/remote/%s/fingerprint", ssl_dir, rh->hostname); if (stat(ssl_fingerprint_file, &statbuf) == -1) { g_free(ssl_fingerprint_file); ssl_fingerprint_file = NULL; } } } port = find_port_for_service(service, "tcp"); if (port == 0) { security_seterror(&rh->sech, _("%s/tcp unknown protocol"), service); goto error; } /* * We need to open a new connection. */ if(rh->rc->read == -1) { if (runssl(rh, port, src_ip, ssl_fingerprint_file, ssl_cert_file, ssl_key_file, ssl_ca_cert_file, ssl_cipher_list, ssl_check_certificate_host) < 0) goto error; rh->rc->refcnt++; } g_free(ssl_fingerprint_file); g_free(ssl_cert_file); g_free(ssl_key_file); g_free(ssl_ca_cert_file); /* * The socket will be opened async so hosts that are down won't * block everything. We need to register a write event * so we will know when the socket comes alive. * * Overload rh->rs->ev_read to provide a write event handle. * We also register a timeout. */ rh->fn.connect = fn; rh->arg = arg; rh->rs->ev_read = event_register((event_id_t)(rh->rs->rc->write), EV_WRITEFD, sec_connect_callback, rh); rh->ev_timeout = event_register(CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); return; error: (*fn)(arg, &rh->sech, S_ERROR); }
/* * Setup to handle new incoming connections */ static void ssl_accept( const struct security_driver *driver, char * (*conf_fn)(char *, void *), int in, int out, void (*fn)(security_handle_t *, pkt_t *), void *datap) { sockaddr_union sin; socklen_t_equiv len = sizeof(struct sockaddr); struct tcp_conn *rc; char hostname[NI_MAXHOST]; int result; char *errmsg = NULL; int err; X509 *remote_cert; char *str; X509_NAME *x509_name; char *cert_hostname; SSL_CTX *ctx; SSL *ssl; int loc; char *ssl_dir = getconf_str(CNF_SSL_DIR); char *ssl_fingerprint_file = conf_fn("ssl_fingerprint_file", datap); char *ssl_cert_file = conf_fn("ssl_cert_file", datap); char *ssl_key_file = conf_fn("ssl_key_file", datap); char *ssl_ca_cert_file = conf_fn("ssl_ca_cert_file", datap); char *ssl_cipher_list = conf_fn("ssl_cipher_list", datap); int ssl_check_host = atoi(conf_fn("ssl_check_host", datap)); int ssl_check_certificate_host = atoi(conf_fn("ssl_check_certificate_host", datap)); if (getpeername(in, (struct sockaddr *)&sin, &len) < 0) { g_debug(_("getpeername returned: %s"), strerror(errno)); return; } if ((result = getnameinfo((struct sockaddr *)&sin, len, hostname, NI_MAXHOST, NULL, 0, 0) != 0)) { g_debug(_("getnameinfo failed: %s"), gai_strerror(result)); return; } if (ssl_check_host && check_name_give_sockaddr(hostname, (struct sockaddr *)&sin, &errmsg) < 0) { amfree(errmsg); return; } if (ssl_dir) { if (!ssl_cert_file || ssl_cert_file == '\0') { ssl_cert_file = g_strdup_printf("%s/me/crt.pem", ssl_dir); } if (!ssl_key_file || ssl_key_file == '\0') { ssl_key_file = g_strdup_printf("%s/me/private/key.pem", ssl_dir); } if (!ssl_ca_cert_file || ssl_ca_cert_file == '\0') { ssl_ca_cert_file = g_strdup_printf("%s/CA/crt.pem", ssl_dir); } } if (!ssl_cert_file) { g_debug(_("ssl-cert-file must be set in amanda-remote.conf")); return; } if (!ssl_key_file) { g_debug(_("ssl-key-file must be set in amanda-remote.conf")); return; } if (!ssl_ca_cert_file) { g_debug(_("ssl_ca_cert_file must be set in amanda-remote.conf")); return; } len = sizeof(sin); init_ssl(); /* Create a SSL_CTX structure */ ctx = SSL_CTX_new(SSLv3_server_method()); if (!ctx) { g_debug(_("SSL_CTX_new failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); if (ssl_cipher_list) { g_debug("Set ssl_cipher_list to %s", ssl_cipher_list); if (SSL_CTX_set_cipher_list(ctx, ssl_cipher_list) == 0) { g_debug(_("SSL_CTX_set_cipher_list failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } } /* Load the me certificate into the SSL_CTX structure */ g_debug(_("Loading ssl-cert-file certificate %s"), ssl_cert_file); if (SSL_CTX_use_certificate_file(ctx, ssl_cert_file, SSL_FILETYPE_PEM) <= 0) { g_debug(_("Load ssl-cert-file failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } /* Load the private-key corresponding to the me certificate */ g_debug(_("Loading ssl-key-file private-key %s"), ssl_key_file); if (SSL_CTX_use_PrivateKey_file(ctx, ssl_key_file, SSL_FILETYPE_PEM) <= 0) { g_debug(_("Load ssl-key-file failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } if (ssl_ca_cert_file) { /* Load the RSA CA certificate into the SSL_CTX structure */ g_debug(_("Loading ssl-ca-cert-file ca certificate %s"), ssl_ca_cert_file); if (!SSL_CTX_load_verify_locations(ctx, ssl_ca_cert_file, NULL)) { g_debug(_("Load ssl-ca-cert-file failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } /* Set to require peer (remote) certificate verification */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); /* Set the verification depth to 1 */ SSL_CTX_set_verify_depth(ctx,1); } ssl = SSL_new(ctx); if (!ssl) { g_debug(_("SSL_new failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } SSL_set_accept_state(ssl); /* Assign the socket into the SSL structure (SSL and socket without BIO) */ SSL_set_fd(ssl, in); /* Perform SSL Handshake on the SSL me */ err = SSL_accept(ssl); if (err == -1) { g_debug(_("SSL_accept failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } /* Get the me's certificate (optional) */ remote_cert = SSL_get_peer_certificate (ssl); if (remote_cert == NULL) { g_debug(_("remote doesn't sent a certificate")); return; } x509_name = X509_get_subject_name(remote_cert); str = X509_NAME_oneline(X509_get_subject_name(remote_cert), 0, 0); auth_debug(1, _("\t subject: %s\n"), str); amfree (str); str = X509_NAME_oneline(X509_get_issuer_name(remote_cert), 0, 0); auth_debug(1, _("\t issuer: %s\n"), str); amfree(str); loc = -1; loc = X509_NAME_get_index_by_NID(x509_name, NID_commonName, loc); if (loc != -1) { X509_NAME_ENTRY *x509_entry = X509_NAME_get_entry(x509_name, loc); ASN1_STRING *asn1_string = X509_NAME_ENTRY_get_data(x509_entry); cert_hostname = (char *)ASN1_STRING_data(asn1_string); auth_debug(1, "common_name: %s\n", cert_hostname); if (ssl_check_certificate_host && check_name_give_sockaddr((char*)cert_hostname, (struct sockaddr *)&sin, &errmsg) < 0) { g_debug("Common name of certicate (%s) doesn't resolv to IP (%s)", cert_hostname, str_sockaddr(&sin)); amfree(errmsg); X509_free(remote_cert); return; } } else { g_debug("Certificate have no common name"); X509_free(remote_cert); return; } if (ssl_dir) { if (!ssl_fingerprint_file || ssl_fingerprint_file == '\0') { struct stat statbuf; ssl_fingerprint_file = g_strdup_printf("%s/remote/%s/fingerprint", ssl_dir, cert_hostname); if (stat(ssl_fingerprint_file, &statbuf) == -1) { g_free(ssl_fingerprint_file); ssl_fingerprint_file = NULL; } } } if (ssl_fingerprint_file) { g_debug(_("Loading ssl-fingerprint-file %s"), ssl_fingerprint_file); str = validate_fingerprints(remote_cert, ssl_fingerprint_file); if (str) { g_debug("%s", str); amfree(str); X509_free(remote_cert); return; } } X509_free(remote_cert); rc = sec_tcp_conn_get(hostname, 0); rc->recv_security_ok = &bsd_recv_security_ok; rc->prefix_packet = &bsd_prefix_packet; rc->need_priv_port = 0; copy_sockaddr(&rc->peer, &sin); rc->read = in; rc->write = out; rc->accept_fn = fn; rc->driver = driver; rc->conf_fn = conf_fn; rc->datap = datap; rc->ctx = ctx; rc->ssl = ssl; strncpy(rc->hostname, cert_hostname, sizeof(rc->hostname)-1); g_debug(_("SSL_cipher: %s"), SSL_get_cipher(rc->ssl)); sec_tcp_conn_read(rc); }
int main(int argc, char ** argv) { char * tapelist_name; taper_state_t state; config_overwrites_t *cfg_ovr = NULL; char *cfg_opt = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); set_pname("taper"); dbopen("server"); device_api_init(); init_taper_state(&state); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], version()); dbprintf(_("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], version()); /* Process options */ cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); if(argc > 2) { error("Too many arguments!\n"); g_assert_not_reached(); } if (argc > 1) cfg_opt = argv[1]; config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt); apply_config_overwrites(cfg_ovr); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } safe_cd(); add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_trace_log); check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST)); if (read_tapelist(tapelist_name) != 0) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("could not load tapelist \"%s\"", tapelist_name); g_assert_not_reached(); } amfree(tapelist_name); state.have_changer = changer_init(); if (state.have_changer < 0) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("changer initialization failed: %s", strerror(errno)); g_assert_not_reached(); } state.next_tape_label = NULL; state.next_tape_device = NULL; state.cur_tape = 0; if (!find_first_tape(&state)) { log_add(L_INFO, "pid-done %ld", (long)getpid()); return EXIT_SUCCESS; } while (process_driver_command(&state)); log_add(L_INFO, "pid-done %ld", (long)getpid()); return EXIT_SUCCESS; }
char * find_brand_new_tape_label(char **errmsg) { char *format; char newlabel[AUTO_LABEL_MAX_LEN]; char tmpnum[30]; /* 64-bit integers can be 21 digists... */ char tmpfmt[16]; char *auto_pos = NULL; int i; ssize_t label_len, auto_len; tape_t *tp; *errmsg = NULL; if (!getconf_seen(CNF_LABEL_NEW_TAPES)) { return NULL; } format = getconf_str(CNF_LABEL_NEW_TAPES); memset(newlabel, 0, AUTO_LABEL_MAX_LEN); label_len = 0; auto_len = -1; /* Only find the first '%' */ while (*format != '\0') { if (label_len + 4 > AUTO_LABEL_MAX_LEN) { *errmsg = _("Auto label format is too long!"); return NULL; } if (*format == '\\') { /* Copy the next character. */ newlabel[label_len++] = format[1]; format += 2; } else if (*format == '%' && auto_len == -1) { /* This is the format specifier. */ auto_pos = newlabel + label_len; auto_len = 0; while (*format == '%' && label_len < AUTO_LABEL_MAX_LEN) { newlabel[label_len++] = '%'; auto_len ++; format ++; } } else { /* Just copy a character. */ newlabel[label_len++] = *(format++); } } /* Sometimes we copy the null, sometimes not. */ if (newlabel[label_len] != '\0') { newlabel[label_len++] = '\0'; } if (auto_pos == NULL) { *errmsg = _("Auto label template contains no '%%'!"); return NULL; } g_snprintf(tmpfmt, SIZEOF(tmpfmt), "%%0%zdd", (size_t)auto_len); for (i = 1; i < INT_MAX; i ++) { g_snprintf(tmpnum, SIZEOF(tmpnum), tmpfmt, i); if (strlen(tmpnum) != (size_t)auto_len) { *errmsg = _("All possible auto-labels used."); return NULL; } strncpy(auto_pos, tmpnum, (size_t)auto_len); tp = lookup_tapelabel(newlabel); if (tp == NULL) { /* Got it. Double-check that this is a labelstr match. */ if (!match(getconf_str(CNF_LABELSTR), newlabel)) { *errmsg = g_strdup_printf(_("New label %s does not match labelstr %s from amanda.conf"), newlabel, getconf_str(CNF_LABELSTR)); return NULL; } return stralloc(newlabel); } } /* Should not get here unless you have over two billion tapes. */ *errmsg = _("Taper internal error in find_brand_new_tape_label."); return 0; }
/* This function checks the label of a single tape, which may or may not * have been loaded by the changer. With the addition of char *dev, and *slot, * it has the same interface as taper_scan. slot should be the slot where * this tape is found, or NULL if no changer is in use. * Return value is the same as taper_scan. */ int scan_read_label( char *dev, char *slot, char *desired_label, char** label, char** timestamp, char** error_message) { Device * device; char *labelstr; DeviceStatusFlags device_status; char *new_label_errmsg; g_return_val_if_fail(dev != NULL, -1); if (*error_message == NULL) *error_message = stralloc(""); *label = *timestamp = NULL; device = device_open(dev); g_assert(device != NULL); if (device->status != DEVICE_STATUS_SUCCESS ) { *error_message = newvstrallocf(*error_message, _("%sError opening device %s: %s.\n"), *error_message, dev, device_error_or_status(device)); g_object_unref(device); amfree(*timestamp); amfree(*label); return -1; } if (!device_configure(device, TRUE)) { *error_message = newvstrallocf(*error_message, _("%sError configuring device %s: %s.\n"), *error_message, dev, device_error_or_status(device)); g_object_unref(device); amfree(*timestamp); amfree(*label); return -1; } device_status = device_read_label(device); if (device_status == DEVICE_STATUS_SUCCESS && device->volume_label != NULL) { *label = g_strdup(device->volume_label); *timestamp = strdup(device->volume_time); } else if (device_status & DEVICE_STATUS_VOLUME_UNLABELED) { if (!getconf_seen(CNF_LABEL_NEW_TAPES)) { *error_message = newvstrallocf(*error_message, _("%sFound an empty or non-amanda tape.\n"), *error_message); g_object_unref(device); return -1; } /* If we got a header, but the Device doesn't think it's labeled, then this * tape probably has some data on it, so refuse to automatically label it */ if (device->volume_header && device->volume_header->type != F_EMPTY) { *error_message = newvstrallocf(*error_message, _("%sFound a non-amanda tape; check and relabel it with 'amlabel -f'\n"), *error_message); g_object_unref(device); return -1; } g_object_unref(device); *label = find_brand_new_tape_label(&new_label_errmsg); if (*label != NULL) { *timestamp = stralloc("X"); *error_message = newvstrallocf(*error_message, _("%sFound an empty tape, will label it `%s'.\n"), *error_message, *label); return 3; } *error_message = newvstrallocf(*error_message, _("%s%s.\n"), *error_message, new_label_errmsg); return -1; } else { char * label_errstr; label_errstr = g_strdup_printf(_("Error reading label: %s.\n"), device_error_or_status(device)); *error_message = newvstralloc(*error_message, *error_message, label_errstr, NULL); g_free(label_errstr); return -1; } g_assert(*label != NULL && *timestamp != NULL); g_object_unref(device); *error_message = newvstrallocf(*error_message, _("%sread label `%s', date `%s'.\n"), *error_message, *label, *timestamp); /* Register this with the barcode database, even if its not ours. */ if (slot != NULL) { changer_label(slot, *label); } if (desired_label != NULL && strcmp(*label, desired_label) == 0) { /* Got desired label. */ return 1; } /* Is this actually an acceptable tape? */ labelstr = getconf_str(CNF_LABELSTR); if(!match(labelstr, *label)) { *error_message = newvstrallocf(*error_message, _("%slabel \"%s\" doesn't match \"%s\".\n"), *error_message, *label, labelstr); return -1; } else { tape_t *tp; if (strcmp(*timestamp, "X") == 0) { /* new, labeled tape. */ return 1; } tp = lookup_tapelabel(*label); if(tp == NULL) { *error_message = newvstrallocf(*error_message, _("%slabel \"%s\" matches labelstr but it is" " not listed in the tapelist file.\n"), *error_message, *label); return -1; } else if(tp != NULL && !reusable_tape(tp)) { *error_message = newvstrallocf(*error_message, _("%sTape with label %s is still active" " and cannot be overwritten.\n"), *error_message, *label); return -1; } } /* Yay! We got a good tape! */ return 2; }
int main( int argc, char ** argv) { char *logfname; char *conf_logdir; FILE *logfile; config_overrides_t *cfg_ovr = NULL; char *cfg_opt = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); set_pname("amlogroll"); dbopen(DBG_SUBDIR_SERVER); add_amanda_log_handler(amanda_log_stderr); /* Process options */ cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc >= 2) { cfg_opt = argv[1]; } /* read configuration files */ set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } safe_cd(); /* must happen after config_init */ check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); logfname = vstralloc(conf_logdir, "/", "log", NULL); amfree(conf_logdir); if((logfile = fopen(logfname, "r")) == NULL) { error(_("could not open log %s: %s"), logfname, strerror(errno)); /*NOTREACHED*/ } amfree(logfname); add_amanda_log_handler(amanda_log_trace_log); while(get_logline(logfile)) { if(curlog == L_START) { handle_start(); if(datestamp != NULL) { break; } } } afclose(logfile); log_rename(datestamp); amfree(datestamp); dbclose(); return 0; }
int main( int argc, char ** argv) { disklist_t diskl; int no_keep; /* files per system to keep */ char **output_find_log; DIR *dir; struct dirent *adir; char **name; int useful; char *olddir; char *oldfile = NULL, *newfile = NULL; time_t today, date_keep; char *logname = NULL; struct stat stat_log; struct stat stat_old; char *conf_diskfile; char *conf_tapelist; char *conf_logdir; int dumpcycle; config_overwrites_t *cfg_ovr = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmlog"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); if (argc > 1 && strcmp(argv[1], "-t") == 0) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], version()); config_init(CONFIG_INIT_EXPLICIT_NAME, argv[1]); apply_config_overwrites(cfg_ovr); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if (read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); today = time((time_t *)NULL); dumpcycle = getconf_int(CNF_DUMPCYCLE); if(dumpcycle > 5000) dumpcycle = 5000; date_keep = today - (dumpcycle * 86400); output_find_log = find_log(); /* determine how many log to keep */ no_keep = getconf_int(CNF_TAPECYCLE) * 2; dbprintf(plural(_("Keeping %d log file\n"), _("Keeping %d log files\n"), no_keep), no_keep); conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); olddir = vstralloc(conf_logdir, "/oldlog", NULL); if (mkpdir(olddir, 0700, (uid_t)-1, (gid_t)-1) != 0) { error(_("could not create parents of %s: %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (mkdir(olddir, 0700) != 0 && errno != EEXIST) { error(_("could not create %s: %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (stat(olddir,&stat_old) == -1) { error(_("can't stat oldlog directory \"%s\": %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (!S_ISDIR(stat_old.st_mode)) { error(_("Oldlog directory \"%s\" is not a directory"), olddir); /*NOTREACHED*/ } if ((dir = opendir(conf_logdir)) == NULL) { error(_("could not open log directory \"%s\": %s"), conf_logdir,strerror(errno)); /*NOTREACHED*/ } while ((adir=readdir(dir)) != NULL) { if(strncmp(adir->d_name,"log.",4)==0) { useful=0; for (name=output_find_log;*name !=NULL; name++) { if((strlen(adir->d_name) >= 13 && strlen(*name) >= 13 && adir->d_name[12] == '.' && (*name)[12] == '.' && strncmp(adir->d_name,*name,12)==0) || strncmp(adir->d_name,*name,18)==0) { useful=1; break; } } logname=newvstralloc(logname, conf_logdir, "/" ,adir->d_name, NULL); if(stat(logname,&stat_log)==0) { if((time_t)stat_log.st_mtime > date_keep) { useful = 1; } } if(useful == 0) { oldfile = newvstralloc(oldfile, conf_logdir, "/", adir->d_name, NULL); newfile = newvstralloc(newfile, olddir, "/", adir->d_name, NULL); if (rename(oldfile,newfile) != 0) { error(_("could not rename \"%s\" to \"%s\": %s"), oldfile, newfile, strerror(errno)); /*NOTREACHED*/ } } } } closedir(dir); for (name = output_find_log; *name != NULL; name++) { amfree(*name); } amfree(output_find_log); amfree(logname); amfree(oldfile); amfree(newfile); amfree(olddir); amfree(conf_logdir); clear_tapelist(); free_disklist(&diskl); dbclose(); return 0; }
int main( int argc, char ** argv) { int foreground; int batch; int redirect; char **datearg = NULL; int nb_datearg = 0; char *conf_diskfile; char *conf_tapelist; char *conf_logfile; int conf_usetimestamps; disklist_t diskq; disk_t *dp; pid_t pid; pid_t driver_pid, reporter_pid; amwait_t exitcode; int opt; GSList *holding_list=NULL, *holding_file; int driver_pipe[2]; char date_string[100]; char date_string_standard[100]; time_t today; char *errstr; struct tm *tm; char *tapedev; char *tpchanger; char *qdisk, *qhname; GSList *datestamp_list = NULL; config_overrides_t *cfg_ovr; char **config_options; find_result_t *holding_files; disklist_t holding_disklist = { NULL, NULL }; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amflush"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); add_amanda_log_handler(amanda_log_stderr); foreground = 0; batch = 0; redirect = 1; /* process arguments */ cfg_ovr = new_config_overrides(argc/2); while((opt = getopt(argc, argv, "bfso:D:")) != EOF) { switch(opt) { case 'b': batch = 1; break; case 'f': foreground = 1; break; case 's': redirect = 0; break; case 'o': add_config_override_opt(cfg_ovr, optarg); break; case 'D': if (datearg == NULL) datearg = g_malloc(21*sizeof(char *)); if(nb_datearg == 20) { g_fprintf(stderr,_("maximum of 20 -D arguments.\n")); exit(1); } datearg[nb_datearg++] = g_strdup(optarg); datearg[nb_datearg] = NULL; break; } } argc -= optind, argv += optind; if(!foreground && !redirect) { g_fprintf(stderr,_("Can't redirect to stdout/stderr if not in forground.\n")); exit(1); } if(argc < 1) { error(_("Usage: amflush [-b] [-f] [-s] [-D date]* [-o configoption]* <confdir> [host [disk]* ]*")); /*NOTREACHED*/ } set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_EXPLICIT_NAME, argv[0]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskq); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); /* load DLEs from the holding disk, in case there's anything to flush there */ search_holding_disk(&holding_files, &holding_disklist); /* note that the dumps are added to the global disklist, so we need not * consult holding_files or holding_disklist after this. The holding-only * dumps will be filtered properly by match_disklist, setting the dp->todo * flag appropriately. */ errstr = match_disklist(&diskq, argc-1, argv+1); if (errstr) { g_printf(_("%s"),errstr); amfree(errstr); } conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); conf_usetimestamps = getconf_boolean(CNF_USETIMESTAMPS); amflush_datestamp = get_datestamp_from_time(0); if(conf_usetimestamps == 0) { amflush_timestamp = g_strdup(amflush_datestamp); } else { amflush_timestamp = get_timestamp_from_time(0); } conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); conf_logfile = g_strjoin(NULL, conf_logdir, "/log", NULL); if (access(conf_logfile, F_OK) == 0) { run_amcleanup(get_config_name()); } if (access(conf_logfile, F_OK) == 0) { char *process_name = get_master_process(conf_logfile); error(_("%s exists: %s is already running, or you must run amcleanup"), conf_logfile, process_name); /*NOTREACHED*/ } driver_program = g_strjoin(NULL, amlibexecdir, "/", "driver", NULL); reporter_program = g_strjoin(NULL, sbindir, "/", "amreport", NULL); logroll_program = g_strjoin(NULL, amlibexecdir, "/", "amlogroll", NULL); tapedev = getconf_str(CNF_TAPEDEV); tpchanger = getconf_str(CNF_TPCHANGER); if (tapedev == NULL && tpchanger == NULL) { error(_("No tapedev or tpchanger specified")); } /* if dates were specified (-D), then use match_datestamp * against the list of all datestamps to turn that list * into a set of existing datestamps (basically, evaluate the * expressions into actual datestamps) */ if(datearg) { GSList *all_datestamps; GSList *datestamp; int i, ok; all_datestamps = holding_get_all_datestamps(); for(datestamp = all_datestamps; datestamp != NULL; datestamp = datestamp->next) { ok = 0; for(i=0; i<nb_datearg && ok==0; i++) { ok = match_datestamp(datearg[i], (char *)datestamp->data); } if (ok) datestamp_list = g_slist_insert_sorted(datestamp_list, g_strdup((char *)datestamp->data), g_compare_strings); } slist_free_full(all_datestamps, g_free); } else { /* otherwise, in batch mode, use all datestamps */ if(batch) { datestamp_list = holding_get_all_datestamps(); } /* or allow the user to pick datestamps */ else { datestamp_list = pick_datestamp(); } } if(!datestamp_list) { g_printf(_("Could not find any Amanda directories to flush.\n")); exit(1); } holding_list = holding_get_files_for_flush(datestamp_list); if (holding_list == NULL) { g_printf(_("Could not find any valid dump image, check directory.\n")); exit(1); } if (access(conf_logfile, F_OK) == 0) { char *process_name = get_master_process(conf_logfile); error(_("%s exists: someone started %s"), conf_logfile, process_name); /*NOTREACHED*/ } log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); if(!batch) confirm(datestamp_list); for(dp = diskq.head; dp != NULL; dp = dp->next) { if(dp->todo) { char *qname; qname = quote_string(dp->name); log_add(L_DISK, "%s %s", dp->host->hostname, qname); amfree(qname); } } if(!foreground) { /* write it before redirecting stdout */ puts(_("Running in background, you can log off now.")); puts(_("You'll get mail when amflush is finished.")); } if(redirect) redirect_stderr(); if(!foreground) detach(); add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_trace_log); today = time(NULL); tm = localtime(&today); if (tm) { strftime(date_string, 100, "%a %b %e %H:%M:%S %Z %Y", tm); strftime(date_string_standard, 100, "%Y-%m-%d %H:%M:%S %Z", tm); } else { error(_("BAD DATE")); /* should never happen */ } g_fprintf(stderr, _("amflush: start at %s\n"), date_string); g_fprintf(stderr, _("amflush: datestamp %s\n"), amflush_timestamp); g_fprintf(stderr, _("amflush: starttime %s\n"), amflush_timestamp); g_fprintf(stderr, _("amflush: starttime-locale-independent %s\n"), date_string_standard); log_add(L_START, _("date %s"), amflush_timestamp); /* START DRIVER */ if(pipe(driver_pipe) == -1) { error(_("error [opening pipe to driver: %s]"), strerror(errno)); /*NOTREACHED*/ } if((driver_pid = fork()) == 0) { /* * This is the child process. */ dup2(driver_pipe[0], 0); close(driver_pipe[1]); config_options = get_config_options(3); config_options[0] = "driver"; config_options[1] = get_config_name(); config_options[2] = "nodump"; safe_fd(-1, 0); execve(driver_program, config_options, safe_env()); error(_("cannot exec %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } else if(driver_pid == -1) { error(_("cannot fork for %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } driver_stream = fdopen(driver_pipe[1], "w"); if (!driver_stream) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } g_fprintf(driver_stream, "DATE %s\n", amflush_timestamp); for(holding_file=holding_list; holding_file != NULL; holding_file = holding_file->next) { dumpfile_t file; holding_file_get_dumpfile((char *)holding_file->data, &file); if (holding_file_size((char *)holding_file->data, 1) <= 0) { g_debug("%s is empty - ignoring", (char *)holding_file->data); log_add(L_INFO, "%s: removing file with no data.", (char *)holding_file->data); holding_file_unlink((char *)holding_file->data); dumpfile_free_data(&file); continue; } /* search_holding_disk should have already ensured that every * holding dumpfile has an entry in the dynamic disklist */ dp = lookup_disk(file.name, file.disk); assert(dp != NULL); /* but match_disklist may have indicated we should not flush it */ if (dp->todo == 0) continue; qdisk = quote_string(file.disk); qhname = quote_string((char *)holding_file->data); g_fprintf(stderr, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); g_debug("flushing '%s'", (char *)holding_file->data); g_fprintf(driver_stream, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); amfree(qdisk); amfree(qhname); dumpfile_free_data(&file); } g_fprintf(stderr, "ENDFLUSH\n"); fflush(stderr); g_fprintf(driver_stream, "ENDFLUSH\n"); fflush(driver_stream); fclose(driver_stream); /* WAIT DRIVER */ while(1) { if((pid = wait(&exitcode)) == -1) { if(errno == EINTR) { continue; } else { error(_("wait for %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } } else if (pid == driver_pid) { break; } } slist_free_full(datestamp_list, g_free); datestamp_list = NULL; slist_free_full(holding_list, g_free); holding_list = NULL; if(redirect) { /* rename errfile */ char *errfile, *errfilex, *nerrfilex, number[100]; int tapecycle; int maxdays, days; struct stat stat_buf; errfile = g_strjoin(NULL, conf_logdir, "/amflush", NULL); errfilex = NULL; nerrfilex = NULL; tapecycle = getconf_int(CNF_TAPECYCLE); maxdays = tapecycle + 2; days = 1; /* First, find out the last existing errfile, */ /* to avoid ``infinite'' loops if tapecycle is infinite */ g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); while ( days < maxdays && stat(errfilex,&stat_buf)==0) { days++; g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); } g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); nerrfilex = NULL; while (days > 1) { amfree(nerrfilex); nerrfilex = errfilex; days--; g_snprintf(number,100,"%d",days); errfilex = g_strjoin(NULL, errfile, ".", number, NULL); if (rename(errfilex, nerrfilex) != 0) { error(_("cannot rename \"%s\" to \"%s\": %s"), errfilex, nerrfilex, strerror(errno)); /*NOTREACHED*/ } } errfilex = newvstralloc(errfilex, errfile, ".1", NULL); if (rename(errfile,errfilex) != 0) { error(_("cannot rename \"%s\" to \"%s\": %s"), errfilex, nerrfilex, strerror(errno)); /*NOTREACHED*/ } amfree(errfile); amfree(errfilex); amfree(nerrfilex); } /* * Have amreport generate report and send mail. Note that we do * not bother checking the exit status. If it does not work, it * can be rerun. */ if((reporter_pid = fork()) == 0) { /* * This is the child process. */ config_options = get_config_options(3); config_options[0] = "amreport"; config_options[1] = get_config_name(); config_options[2] = "--from-amdump"; safe_fd(-1, 0); execve(reporter_program, config_options, safe_env()); error(_("cannot exec %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } else if(reporter_pid == -1) { error(_("cannot fork for %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } while(1) { if((pid = wait(&exitcode)) == -1) { if(errno == EINTR) { continue; } else { error(_("wait for %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } } else if (pid == reporter_pid) { break; } } log_add(L_INFO, "pid-done %ld", (long)getpid()); /* * Call amlogroll to rename the log file to its datestamped version. * Since we exec at this point, our exit code will be that of amlogroll. */ config_options = get_config_options(2); config_options[0] = "amlogroll"; config_options[1] = get_config_name(); safe_fd(-1, 0); execve(logroll_program, config_options, safe_env()); error(_("cannot exec %s: %s"), logroll_program, strerror(errno)); /*NOTREACHED*/ return 0; /* keep the compiler happy */ }