📄 amadmin.c
字号:
argv+(start_argc-1)); if (errstr) { g_printf("%s", errstr); amfree(errstr); } output_find = find_dump(NULL); } sort_find_result(sort_order, &output_find); print_find_result(output_find); free_find_result(&output_find); amfree(sort_order);}/* ------------------------ */static GSList *get_file_list( int argc, char **argv, int allow_empty){ GSList * file_list = NULL; GSList * dumplist; int flags; flags = CMDLINE_PARSE_DATESTAMP; if (allow_empty) flags |= CMDLINE_EMPTY_TO_WILDCARD; dumplist = cmdline_parse_dumpspecs(argc, argv, flags); file_list = cmdline_match_holding(dumplist); dumpspec_list_free(dumplist); return file_list;}/* Given a file header, find the history element in curinfo most likely * corresponding to that dump (this is not an exact science). * * @param info: the info_t element for this DLE * @param file: the header of the file * @returns: index of the matching history element, or -1 if not found */static intholding_file_find_history( info_t *info, dumpfile_t *file){ int matching_hist_idx = -1; int nhist; int i; /* Begin by trying to find the history element matching this dump. * The datestamp on the dump is for the entire run of amdump, while the * 'date' in the history element of 'info' is the time the dump itself * began. A matching history element, then, is the earliest element * with a 'date' equal to or later than the date of the dumpfile. * * We compare using formatted datestamps; even using seconds since epoch, * we would still face timezone issues, and have to do a reverse (timezone * to gmt) translation. */ /* get to the end of the history list and search backward */ for (nhist = 0; info->history[nhist].level > -1; nhist++) /* empty loop */; for (i = nhist-1; i > -1; i--) { char *info_datestamp = get_timestamp_from_time(info->history[i].date); int order = strcmp(file->datestamp, info_datestamp); amfree(info_datestamp); if (order <= 0) { /* only a match if the levels are equal */ if (info->history[i].level == file->dumplevel) { matching_hist_idx = i; } break; } } return matching_hist_idx;}/* A holding file is 'outdated' if a subsequent dump of the same DLE was made * at the same level or a lower leve; for example, a level 2 dump is outdated if * there is a subsequent level 2, or a subsequent level 0. * * @param file: the header of the file * @returns: true if the file is outdated */static intholding_file_is_outdated( dumpfile_t *file){ info_t info; int matching_hist_idx; if (get_info(file->name, file->disk, &info) == -1) { return 0; /* assume it's not outdated */ } /* if the last level is less than the level of this dump, then * it's outdated */ if (info.last_level < file->dumplevel) return 1; /* otherwise, we need to see if this dump is the last at its level */ matching_hist_idx = holding_file_find_history(&info, file); if (matching_hist_idx == -1) { return 0; /* assume it's not outdated */ } /* compare the date of the history element with the most recent date * for this level. If they match, then this is the last dump at this * level, and we checked above for more recent lower-level dumps, so * the dump is not outdated. */ if (info.history[matching_hist_idx].date == info.inf[info.history[matching_hist_idx].level].date) { return 0; } else { return 1; }}static intremove_holding_file_from_catalog( char *filename){ static int warnings_printed; /* only print once per invocation */ dumpfile_t file; info_t info; int matching_hist_idx = -1; history_t matching_hist; /* will be a copy */ int i; if (!holding_file_get_dumpfile(filename, &file)) { g_printf(_("Could not read holding file %s\n"), filename); return 0; } if (get_info(file.name, file.disk, &info) == -1) { g_printf(_("WARNING: No curinfo record for %s:%s\n"), file.name, file.disk); return 1; /* not an error */ } matching_hist_idx = holding_file_find_history(&info, &file); if (matching_hist_idx == -1) { g_printf(_("WARNING: No dump matching %s found in curinfo.\n"), filename); return 1; /* not an error */ } /* make a copy */ matching_hist = info.history[matching_hist_idx]; /* Remove the history element itself before doing the stats */ for (i = matching_hist_idx; i <= NB_HISTORY; i++) { info.history[i] = info.history[i+1]; } info.history[NB_HISTORY].level = -1; /* Remove stats for that history element, if necessary. Doing so * will result in an inconsistent set of backups, so we warn the * user and adjust last_level to make the next dump get us a * consistent picture. */ if (matching_hist.date == info.inf[matching_hist.level].date) { /* search for an earlier dump at this level */ for (i = matching_hist_idx; info.history[i].level > -1; i++) { if (info.history[i].level == matching_hist.level) break; } if (info.history[i].level < 0) { /* not found => zero it out */ info.inf[matching_hist.level].date = (time_t)-1; /* flag as not set */ info.inf[matching_hist.level].label[0] = '\0'; } else { /* found => reconstruct stats as best we can */ info.inf[matching_hist.level].size = info.history[i].size; info.inf[matching_hist.level].csize = info.history[i].csize; info.inf[matching_hist.level].secs = info.history[i].secs; info.inf[matching_hist.level].date = info.history[i].date; info.inf[matching_hist.level].filenum = 0; /* we don't know */ info.inf[matching_hist.level].label[0] = '\0'; /* we don't know */ } /* set last_level to the level we just deleted, and set command * appropriately to make sure planner does a new dump at this level * or lower */ info.last_level = matching_hist.level; if (info.last_level == 0) { g_printf(_("WARNING: Deleting the most recent full dump; forcing a full dump at next run.\n")); SET(info.command, FORCE_FULL); } else { g_printf(_("WARNING: Deleting the most recent level %d dump; forcing a level %d dump or \nWARNING: lower at next run.\n"), info.last_level, info.last_level); SET(info.command, FORCE_NO_BUMP); } /* Search for and display any subsequent runs that depended on this one */ warnings_printed = 0; for (i = matching_hist_idx-1; i >= 0; i--) { char *datestamp; if (info.history[i].level <= matching_hist.level) break; datestamp = get_timestamp_from_time(info.history[i].date); g_printf(_("WARNING: Level %d dump made %s can no longer be accurately restored.\n"), info.history[i].level, datestamp); amfree(datestamp); warnings_printed = 1; } if (warnings_printed) g_printf(_("WARNING: (note, dates shown above are for dumps, and may be later than the\nWARNING: corresponding run date)\n")); } /* recalculate consecutive_runs based on the history: find the first run * at this level, and then count the consecutive runs at that level. This * number may be zero (if we just deleted the last run at this level) */ info.consecutive_runs = 0; for (i = 0; info.history[i].level >= 0; i++) { if (info.history[i].level == info.last_level) break; } while (info.history[i+info.consecutive_runs].level == info.last_level) info.consecutive_runs++; /* this function doesn't touch the performance stats */ /* write out the changes */ if (put_info(file.name, file.disk, &info) == -1) { g_printf(_("Could not write curinfo record for %s:%s\n"), file.name, file.disk); return 0; } return 1;}voidholding( int argc, char ** argv){ GSList *file_list; GSList *li; enum { HOLDING_USAGE, HOLDING_LIST, HOLDING_DELETE } action = HOLDING_USAGE; int long_list = 0; int outdated_list = 0; dumpfile_t file; if (argc < 4) action = HOLDING_USAGE; else if (strcmp(argv[3], "list") == 0 && argc >= 4) action = HOLDING_LIST; else if (strcmp(argv[3], "delete") == 0 && argc > 4) action = HOLDING_DELETE; switch (action) { case HOLDING_USAGE: g_fprintf(stderr, _("%s: expecting \"holding list [-l] [-d]\" or \"holding delete <host> [ .. ]\"\n"), get_pname()); usage(); return; case HOLDING_LIST: argc -= 4; argv += 4; while (argc && argv[0][0] == '-') { switch (argv[0][1]) { case 'l': long_list = 1; break; case 'd': /* have to use '-d', and not '-o', because of parse_config */ outdated_list = 1; break; default: g_fprintf(stderr, _("Unknown option -%c\n"), argv[0][1]); usage(); return; } argc--; argv++; } /* header */ if (long_list) { g_printf("%-10s %-2s %-4s %s\n", _("size (kB)"), _("lv"), _("outd"), _("dump specification")); } file_list = get_file_list(argc, argv, 1); for (li = file_list; li != NULL; li = li->next) { char *dumpstr; int is_outdated; if (!holding_file_get_dumpfile((char *)li->data, &file)) { g_fprintf(stderr, _("Error reading %s\n"), (char *)li->data); continue; } is_outdated = holding_file_is_outdated(&file); dumpstr = cmdline_format_dumpspec_components(file.name, file.disk, file.datestamp, NULL); /* only print this entry if we're printing everything, or if it's outdated and * we're only printing outdated files (-o) */ if (!outdated_list || is_outdated) { if (long_list) { g_printf("%-10lld %-2d %-4s %s\n", (long long)holding_file_size((char *)li->data, 0), file.dumplevel, is_outdated? " *":"", dumpstr); } else { g_printf("%s\n", dumpstr); } } amfree(dumpstr); } g_slist_free_full(file_list); break; case HOLDING_DELETE: argc -= 4; argv += 4; file_list = get_file_list(argc, argv, 0); for (li = file_list; li != NULL; li = li->next) { g_fprintf(stderr, _("Deleting '%s'\n"), (char *)li->data); /* remove it from the catalog */ if (!remove_holding_file_from_catalog((char *)li->data)) exit(1); /* unlink it */ if (!holding_file_unlink((char *)li->data)) { error(_("Could not delete '%s'"), (char *)li->data); } } g_slist_free_full(file_list); break; }}/* ------------------------ *//* shared code with planner.c */intbump_thresh( int level){ int bump = getconf_int(CNF_BUMPSIZE); double mult = getconf_real(CNF_BUMPMULT); while(--level) bump = (int)((double)bump * mult); return bump;}voidbumpsize( int argc, char ** argv){ int l; int conf_bumppercent = getconf_int(CNF_BUMPPERCENT); double conf_bumpmult = getconf_real(CNF_BUMPMULT); (void)argc; /* Quiet unused parameter warning */ (void)argv; /* Quiet unused parameter warning */ g_printf(_("Current bump parameters:\n")); if(conf_bumppercent == 0) { g_printf(_(" bumpsize %5d KB\t- minimum savings (threshold) to bump level 1 -> 2\n"), getconf_int(CNF_BUMPSIZE)); g_printf(_(" bumpdays %5d\t- minimum days at each level\n"), getconf_int(CNF_BUMPDAYS)); g_printf(_(" bumpmult %5.5lg\t- threshold = bumpsize * bumpmult**(level-1)\n\n"), conf_bumpmult); g_printf(_(" Bump -> To Threshold\n")); for(l = 1; l < 9; l++) g_printf(_("\t%d -> %d %9d KB\n"), l, l+1, bump_thresh(l)); putchar('\n'); } else { double bumppercent = (double)conf_bumppercent; g_printf(_(" bumppercent %3d %%\t- minimum savings (threshold) to bump level 1 -> 2\n"), conf_bumppercent); g_printf(_(" bumpdays %5d\t- minimum days at each level\n"), getconf_int(CNF_BUMPDAYS)); g_printf(_(" bumpmult %5.5lg\t- threshold = disk_size * bumppercent * bumpmult**(level-1)\n\n"), conf_bumpmult); g_printf(_(" Bump -> To Threshold\n")); for(l = 1; l < 9; l++) { g_printf(_("\t%d -> %d %7.2lf %%\n"), l, l+1, bumppercent); bumppercent *= conf_bumpmult; if(bumppercent >= 100.000) { bumppercent = 100.0;} } putchar('\n'); }}/* ----------------------------------------------- */void export_one(disk_t *dp);voidexport_db( int argc, char ** argv){ disk_t *dp; time_t curtime; char hostname[MAX_HOSTNAME_LENGTH+1]; int i; g_printf(_("CURINFO Version %s CONF %s\n"), version(), getconf_str(CNF_ORG)); curtime = time(0); if(gethostname(hostname, SIZEOF(hostname)-1) == -1) { error(_("could not determine host name: %s\n"), strerror(errno)); /*NOTREACHED*/ } hostname[SIZEOF(hostname)-1] = '\0'; g_printf(_("# Generated by:\n# host: %s\n# date: %s"), hostname, ctime(&curtime)); g_printf(_("# command:")); for(i = 0; i < argc; i++) g_printf(_(" %s"), argv[i]); g_printf(_("\n# This file can be merged back in with \"amadmin import\".\n")); g_printf(_("# Edit only with care.\n")); if(argc >= 4) diskloop(argc, argv, "export", export_one); else for(dp = diskq.head; dp != NULL; dp = dp->next) export_one(dp);}voidexport_one( disk_t * dp){ info_t info; int i,l; if(get_info(dp->host->hostname, dp->name, &info)) { g_fprintf(stderr, _("Warning: no curinfo record for %s:%s\n"), dp->host->hostname, dp->name); return; } g_printf(_("host: %s\ndisk: %s\n"), dp->host->hostname, dp->name); g_printf(_("command: %u\n"), info.command); g_printf(_("last_level: %d\n"),info.last_level); g_printf(_("consecutive_runs: %d\n"),info.consecutive_runs); g_printf(_("full-rate:")); for(i=0;i<AVG_COUNT;i++) g_printf(_(" %lf"), info.full.rate[i]); g_printf(_("\nfull-comp:")); for(i=0;i<AVG_COUNT;i++) g_printf(_(" %lf"), info.full.comp[i]); g_printf(_("\nincr-rate:")); for(i=0;i<AVG_COUNT;i++) g_printf(_(" %lf"), info.incr.rate[i]); g_printf(_("\nincr-comp:")); for(i=0;i<AVG_COUNT;i++) g_printf(_(" %lf"), info.incr.comp[i]); g_printf("\n"); for(l=0;l<DUMP_LEVELS;l++) { if(info.inf[l].date < (time_t)0 && info.inf[l].label[0] == '\0') continue; g_printf(_("stats: %d %lld %lld %jd %jd %lld %s\n"), l, (long long)info.inf[l].size, (long long)info.inf[l].csize, (intmax_t)info.inf[l].secs, (intmax_t)info.inf[l].date, (long long)info.inf[l].filenum, info.inf[l].label); } for(l=0;info.history[l].level > -1;l++) { g_printf(_("history: %d %lld %lld %jd\n"), info.history[l].level, (long long)info.history[l].size, (long long)info.history[l].csize, (intmax_t)info.history[l].date); } g_printf("//\n");}/* ----------------------------------------------- */int import_one(void);char *impget_line(void);voidimport_db( int argc, char ** argv){ int vers_maj; int vers_min; int vers_patch; int newer; char *org; char *line = NULL; char *hdr; char *s; int rc; int ch; (void)argc; /* Quiet unused parameter warning */ (void)argv; /* Quiet unused parameter warning */ /* process header line */ if((line = agets(stdin)) == NULL) { g_fprintf(stderr, _("%s: empty input.\n"), get_pname()); return; } s = line; ch = *s++; hdr = "version"; if(strncmp_const_skip(s - 1, "CURINFO Version", s, ch) != 0) { goto bad_header; } ch = *s++; skip_whitespace(s, ch); if(ch == '\0' || sscanf(s - 1, "%d.%d.%d", &vers_maj, &vers_min, &vers_patch) != 3) { goto bad_header; } skip_integer(s, ch); /* skip over major */ if(ch != '.') { goto bad_header; } ch = *s++; skip_integer(s, ch); /* skip over minor */ if(ch != '.') { goto bad_header; } ch = *s++; skip_integer(s, ch); /* skip over patch */ hdr = "comment"; if(ch == '\0') { goto bad_header; } skip_non_whitespace(s, ch);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -