| 1 |
bagpuss |
1.1 |
/* apt-spy (c) Steven Holmes, 2003. This software is licensed as detailed in the LICENSE file. */
|
| 2 |
|
|
|
| 3 |
|
|
void usage(void);
|
| 4 |
|
|
void version(void);
|
| 5 |
|
|
|
| 6 |
|
|
#include <stdio.h>
|
| 7 |
|
|
#include <stdlib.h>
|
| 8 |
|
|
#include <unistd.h>
|
| 9 |
|
|
#include <string.h>
|
| 10 |
|
|
#include <limits.h>
|
| 11 |
|
|
|
| 12 |
|
|
#include "include/update.h"
|
| 13 |
|
|
#include "include/file.h"
|
| 14 |
|
|
#include "include/parse.h"
|
| 15 |
|
|
#include "include/benchmark.h"
|
| 16 |
|
|
|
| 17 |
|
|
const char apt_spy_v[] = "v3.0-2"; /* Version */
|
| 18 |
|
|
|
| 19 |
|
|
/* Defaults */
|
| 20 |
|
|
|
| 21 |
|
|
char d_area[] = "All";
|
| 22 |
|
|
char d_out[] = "/etc/apt/sources.list"; /* Default outfile */
|
| 23 |
|
|
char d_config[] = "/etc/apt-spy.conf"; /* Default configuration file */
|
| 24 |
|
|
char d_mirror[] = "/usr/share/apt-spy/README.mirrors.txt"; /* Default mirror list */
|
| 25 |
|
|
char d_file[] = "ls-lR"; /* Default file to grab when benchmarking */
|
| 26 |
|
|
char d_update_url[] = "http://http.us.debian.org/debian/README.mirrors.txt";
|
| 27 |
|
|
|
| 28 |
|
|
int main(int argc, char *argv[])
|
| 29 |
|
|
{
|
| 30 |
|
|
int c;
|
| 31 |
|
|
char *cur_entry; /* Current entry we are benchmarking */
|
| 32 |
|
|
|
| 33 |
|
|
char *distrib = NULL; /* distrubtion to use. */
|
| 34 |
|
|
char *mirror_list = NULL; /* mirror list file */
|
| 35 |
|
|
char *config_file = NULL; /* configuraion file */
|
| 36 |
|
|
char *proxy = NULL; /* Proxy server to use */
|
| 37 |
|
|
char *infile = NULL; /* optional infile */
|
| 38 |
|
|
char *outfile = NULL; /* outfile name */
|
| 39 |
|
|
char *area = NULL; /* Area to test */
|
| 40 |
|
|
char *grab_file = NULL; /* File to grab */
|
| 41 |
|
|
char *update_url = NULL; /* URL to use for updating */
|
| 42 |
|
|
FILE *infile_p, *outfile_p; /* input/output file pointers */
|
| 43 |
|
|
FILE *config_p; /* config file pointer */
|
| 44 |
|
|
FILE *mirror_p; /* mirror list pointer */
|
| 45 |
|
|
int timeout = 15; /* time to benchmark each server */
|
| 46 |
|
|
int toplist = 0; /* Whether to write a list of 5 top servers */
|
| 47 |
|
|
|
| 48 |
|
|
unsigned int test_number = UINT_MAX; /* Number of servers to test */
|
| 49 |
|
|
|
| 50 |
|
|
server_t current, best[BESTNUMBER]; /* information structures */
|
| 51 |
|
|
|
| 52 |
|
|
/* Parse options... */
|
| 53 |
|
|
while((c = getopt(argc, argv, "a:c:d:e:f:i:m:o:p:t:u:w:vh")) != -1)
|
| 54 |
|
|
switch(c) {
|
| 55 |
|
|
case 'a':
|
| 56 |
|
|
area = optarg; /* Area to benchmark */
|
| 57 |
|
|
break;
|
| 58 |
|
|
case 'd':
|
| 59 |
|
|
distrib = optarg; /* Distribution to use */
|
| 60 |
|
|
break;
|
| 61 |
|
|
case 'c':
|
| 62 |
|
|
config_file = optarg; /* Config. file */
|
| 63 |
|
|
break;
|
| 64 |
|
|
case 'e':
|
| 65 |
|
|
test_number = atoi(optarg); /* Number of servers to test */
|
| 66 |
|
|
break;
|
| 67 |
|
|
case 'f':
|
| 68 |
|
|
grab_file = optarg; /* File relative to debian base to grab */
|
| 69 |
|
|
break;
|
| 70 |
|
|
case 'i':
|
| 71 |
|
|
infile = optarg; /* User-specified list of server to benchmark */
|
| 72 |
|
|
break;
|
| 73 |
|
|
case 'm':
|
| 74 |
|
|
mirror_list = optarg; /* Read list of servers from here */
|
| 75 |
|
|
break;
|
| 76 |
|
|
case 'o':
|
| 77 |
|
|
outfile = optarg; /* Where we output our wisdom */
|
| 78 |
|
|
break;
|
| 79 |
|
|
case 'p':
|
| 80 |
|
|
proxy = optarg; /* Proxy server to use */
|
| 81 |
|
|
break;
|
| 82 |
|
|
case 't':
|
| 83 |
|
|
timeout = atoi(optarg); /* Time to benchmark each server */
|
| 84 |
|
|
break;
|
| 85 |
|
|
case 'u':
|
| 86 |
|
|
update_url = optarg;
|
| 87 |
|
|
break;
|
| 88 |
|
|
case 'w':
|
| 89 |
|
|
toplist = 1;
|
| 90 |
|
|
outfile = optarg;
|
| 91 |
|
|
break;
|
| 92 |
|
|
case 'v':
|
| 93 |
|
|
version();
|
| 94 |
|
|
case 'h':
|
| 95 |
|
|
default:
|
| 96 |
|
|
usage(); /* display help */
|
| 97 |
|
|
/* shouldn't reach here */
|
| 98 |
|
|
}
|
| 99 |
|
|
|
| 100 |
|
|
argc -= optind;
|
| 101 |
|
|
argv += optind;
|
| 102 |
|
|
|
| 103 |
|
|
/* We require an area and distribution argument if we are not updating */
|
| 104 |
|
|
if ((argc == 0) && (distrib == NULL))
|
| 105 |
|
|
usage();
|
| 106 |
|
|
|
| 107 |
|
|
/* Setup default area argument */
|
| 108 |
|
|
if (area == NULL)
|
| 109 |
|
|
area = d_area;
|
| 110 |
|
|
|
| 111 |
|
|
/* Setup default file argument if none given */
|
| 112 |
|
|
if (grab_file == NULL)
|
| 113 |
|
|
grab_file = d_file;
|
| 114 |
|
|
|
| 115 |
|
|
/* Open mirror file. We pass argc so it can tell if we're updating or not */
|
| 116 |
|
|
mirror_p = select_mirror(mirror_list, argc);
|
| 117 |
|
|
if (mirror_p == NULL) {
|
| 118 |
|
|
perror("fopen");
|
| 119 |
|
|
fprintf(stderr, "Error opening mirror file. Exiting.\n");
|
| 120 |
|
|
exit(1);
|
| 121 |
|
|
}
|
| 122 |
|
|
|
| 123 |
|
|
/* the only possible argument now is "update", for updating the mirrors list */
|
| 124 |
|
|
if (argc == 1) {
|
| 125 |
|
|
if (strcmp(argv[0], "update") != 0) /* We only deal with one text argument */
|
| 126 |
|
|
usage();
|
| 127 |
|
|
|
| 128 |
|
|
/* If necessary, set update_url to default */
|
| 129 |
|
|
if (update_url == NULL)
|
| 130 |
|
|
update_url = d_update_url;
|
| 131 |
|
|
|
| 132 |
|
|
if (update(mirror_p, update_url, proxy) != 0) {
|
| 133 |
|
|
fprintf(stderr, "Update failed. Exiting.\n");
|
| 134 |
|
|
exit(1);
|
| 135 |
|
|
}
|
| 136 |
|
|
printf("Update complete. Exiting.\n");
|
| 137 |
|
|
exit(0);
|
| 138 |
|
|
}
|
| 139 |
|
|
|
| 140 |
|
|
/* argc should be 0. If not, there's something wrong. */
|
| 141 |
|
|
if (argc != 0)
|
| 142 |
|
|
usage();
|
| 143 |
|
|
|
| 144 |
|
|
|
| 145 |
|
|
/* We open the infile. Either a temporary file, or a user-specified one. */
|
| 146 |
|
|
infile_p = select_infile(infile);
|
| 147 |
|
|
if (infile_p == NULL) {
|
| 148 |
|
|
perror("tmpfile");
|
| 149 |
|
|
fprintf(stderr, "Failed to open infile. Exiting.\n");
|
| 150 |
|
|
exit(1);
|
| 151 |
|
|
}
|
| 152 |
|
|
|
| 153 |
|
|
/* Set up default if user hasn't specified an outfile */
|
| 154 |
|
|
if (outfile == NULL)
|
| 155 |
|
|
outfile = d_out;
|
| 156 |
|
|
|
| 157 |
|
|
/* Check output file for accessibility */
|
| 158 |
|
|
if (check_write_access(outfile) == 1) {
|
| 159 |
|
|
fprintf(stderr, "Could not open outfile. Exiting.\n");
|
| 160 |
|
|
exit(1);
|
| 161 |
|
|
}
|
| 162 |
|
|
|
| 163 |
|
|
/* Open config file */
|
| 164 |
|
|
config_p = select_config(config_file);
|
| 165 |
|
|
if (config_p == NULL) {
|
| 166 |
|
|
perror("fopen");
|
| 167 |
|
|
fprintf(stderr, "Error opening config file. Exiting.\n");
|
| 168 |
|
|
exit(1);
|
| 169 |
|
|
}
|
| 170 |
|
|
|
| 171 |
|
|
/* Fill temporary file with useful stuff if it's not user-specified. */
|
| 172 |
|
|
if (infile == NULL)
|
| 173 |
|
|
if (build_area_file(config_p, infile_p, mirror_p, area) != 0) {
|
| 174 |
|
|
fprintf(stderr, "Error building area file. Exiting.\n");
|
| 175 |
|
|
exit(1);
|
| 176 |
|
|
}
|
| 177 |
|
|
|
| 178 |
|
|
/* Make sure we're at the beginning... */
|
| 179 |
|
|
rewind(infile_p);
|
| 180 |
|
|
|
| 181 |
|
|
/* Zero the "best" structure */
|
| 182 |
|
|
for (c = 0; c < BESTNUMBER; c++)
|
| 183 |
|
|
memset(&best[c], 0, sizeof(server_t));
|
| 184 |
|
|
|
| 185 |
|
|
/* This is the main loop. It'll exit when we've exhausted the URL list or test_number is 0 */
|
| 186 |
|
|
|
| 187 |
|
|
while (((cur_entry = next_entry(infile_p)) != NULL) && test_number != 0) {
|
| 188 |
|
|
if (ferror(infile_p) != 0) {
|
| 189 |
|
|
fprintf(stderr, "Error while reading input file\n");
|
| 190 |
|
|
exit(1);
|
| 191 |
|
|
}
|
| 192 |
|
|
tokenise(¤t, cur_entry); /* Turn entry into a pretty structure */
|
| 193 |
|
|
|
| 194 |
|
|
/* Do the benchmark */
|
| 195 |
|
|
if (benchmark(¤t, proxy, timeout, grab_file) != 0) {
|
| 196 |
|
|
fprintf(stderr, "Error while performing benchmark. Exiting.\n");
|
| 197 |
|
|
exit(1);
|
| 198 |
|
|
}
|
| 199 |
|
|
|
| 200 |
|
|
decide_best(¤t, best);
|
| 201 |
|
|
free(cur_entry);
|
| 202 |
|
|
--test_number;
|
| 203 |
|
|
}
|
| 204 |
|
|
|
| 205 |
|
|
/* Open the output file... */
|
| 206 |
|
|
outfile_p = select_outfile(outfile);
|
| 207 |
|
|
if (outfile_p == NULL) {
|
| 208 |
|
|
perror("fopen");
|
| 209 |
|
|
fprintf(stderr, "Error opening output file. Exiting.\n");
|
| 210 |
|
|
exit(1);
|
| 211 |
|
|
}
|
| 212 |
|
|
|
| 213 |
|
|
/* If infile is NULL (not user specified), we just write the sources list ;) */
|
| 214 |
|
|
if (toplist == 0) {
|
| 215 |
|
|
if (write_list(outfile_p, best, distrib) != 0) {
|
| 216 |
|
|
fprintf(stderr, "Error writing output file. Exiting.");
|
| 217 |
|
|
exit(1);
|
| 218 |
|
|
}
|
| 219 |
|
|
}
|
| 220 |
|
|
/* Else we write out the top 5 servers to a file */
|
| 221 |
|
|
else {
|
| 222 |
|
|
if (write_top(infile_p, outfile_p, best) != 0) {
|
| 223 |
|
|
fprintf(stderr, "Error writing top servers list. Exiting.");
|
| 224 |
|
|
exit(1);
|
| 225 |
|
|
}
|
| 226 |
|
|
}
|
| 227 |
|
|
/* We're all done */
|
| 228 |
|
|
exit(0);
|
| 229 |
|
|
}
|
| 230 |
|
|
|
| 231 |
|
|
void usage()
|
| 232 |
|
|
{
|
| 233 |
|
|
printf("Usage: apt-spy [options]\n"
|
| 234 |
|
|
"options:\n"
|
| 235 |
|
|
"-d distribution\tDebian distribution (ie, stable). Required unless updating.\n"
|
| 236 |
|
|
"-a area\t\tArea to benchmark. (eg, Europe).\n"
|
| 237 |
|
|
"-c config\tConfiguration file to use.\n"
|
| 238 |
|
|
"-e number\tNumber of servers to benchmark before exiting.\n");
|
| 239 |
|
|
printf("-f file\t\tFile to grab when benchmarking. (relative to Debian base).\n"
|
| 240 |
|
|
"-i file\t\tSpecify input file. For use with the -w option.\n"
|
| 241 |
|
|
"-m mirror-list\tMirror list to use, or mirror-list to update when updating.\n"
|
| 242 |
|
|
"-o output-file\tWhere to put output.\n"
|
| 243 |
|
|
"-p proxy\tProxy server to use. In format <server>:[port]\n"
|
| 244 |
|
|
"-t time\t\tTime to benchmark each server for. An approximate value only.\n"
|
| 245 |
|
|
"-u update-URL\tURL to grab mirror-list from when updating.\n");
|
| 246 |
|
|
printf("-w file\t\tOutput top 5 servers to file for use with -i.\n"
|
| 247 |
|
|
"-v\t\tOutput a version number.\n"
|
| 248 |
|
|
"-h\t\tDisplay this message.\n"
|
| 249 |
|
|
"update\t\tUpdate the mirror list.\n");
|
| 250 |
|
|
exit(0);
|
| 251 |
|
|
}
|
| 252 |
|
|
|
| 253 |
|
|
void version()
|
| 254 |
|
|
{
|
| 255 |
|
|
printf("apt-spy %s\n", apt_spy_v);
|
| 256 |
|
|
exit(0);
|
| 257 |
|
|
}
|