├── LICENSE ├── README.md └── pkg_ping.c /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | BSD 2-Clause License 3 | 4 | Copyright (c) 2016 - 2025 Luke N Small, thinkitdoitdone@gmail.com 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 25 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 28 | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Major update: 2 | It fork()s a 5th potential (yet essential) parallel process to scrape the download speed from ftp(1), 3 | send it back to the parent process and uses that bandwidth and the response speed to average out what mirrors are the best, not based upon the order alone, 4 | but based upon translating it to a linear equation for more equitable rankings so super fast and super responsive mirrors will be weighed stronger! 5 | However you may choose to purely rate by the most responsive or the fastest instead! 6 | 7 | New flags: -a, -b, and -r 8 | 9 | ### It determines and prints the fastest OpenBSD mirror(s) for your version and architecture for the /etc/installurl file and if run as root, will write the fastest successful one to disk unless -f is used. 10 | 11 | Perhaps some of you may be put off by the source code containing a hard-coded mirror snippet array. 12 | If you don't trust the array, you can run it with the -g flag and it will print out another hard-coded 13 | mirror source code section generated from openbsd.org domain mirrors from the OpenBSD project. 14 | I designed this feature for you to substitute my generated code section. 15 | 16 | Compiler optimizations for speed is probably not worth the extra second of compile time. Waiting for ftp calls and dns queries will take up the vast majority of the 17 | run-time; everything else happens in the blink of an eye. 18 | 19 | pledge() is updated throughout. Because of how unveil() is designed, unveil() limits are created up front and 20 | immediately takes away the possibility to unveil() any further. To run smoothly, this program may need to call itself. 21 | If it is called from another program such as a C program. it is intended to run from /usr/local/bin/pkg_ping . This solves many problems including needing to be root to install it. 22 | 23 | It automatically discovers whether you are running a release vs a current or beta snapshot! 24 | 25 | It defaults to precaching your dns server by looking up a mirror's ip address(es) 26 | so there is no inconsistency caused by determining ftp download speed with inconsistent dns query times. 27 | 28 | It restarts for most initial ftp call error cases which can be fixed by selecting a different random mirror. 29 | 30 | pkg_ping uses pledge and unveil for OpenBSD version 6.4 and later. I don't recommend running it altered without pledge() or unveil(). 31 | The use of /etc/installurl came about in 6.1 is also required to store to disk. 32 | OpenBSD 5.8-6.0 is supported in the "ancient" branch which uses pkg.conf(5) and starting with 5.9 uses pledge(). 33 | 34 | It uses several commandline options: 35 | 36 | -6 causes it to only lookup ipv6 addresses on mirrors. 37 | Maybe you want to make an ipv6 only box, but want to test it with ipv4 connected first? 38 | 39 | -a: makes -V or zero -v take it's time and not shorten the time out and evaluate average time. Otherwise for -vv and above, it has no effect. 40 | Average is the default setting otherwise. 41 | 42 | -b: rate purely by bandwidth 43 | 44 | -d causes the fork()ed DNS caching process to be skipped. 45 | 46 | -D is "Debug" mode. It makes the ftp calls after the initial one short circuit. and sets up a timer. 47 | I use it along with -d to look at performance. It uses about a third of a second for me. 48 | 49 | -f prohibits a fork()ed process from writing the fastest mirror to file even if it has the power to do so as root. 50 | 51 | -g generates the large https list from which to retrieve and parse "ftplist", which you no doubt, noticed if 52 | you looked at the source code. It downloads an 11 byte timestamp which is in all mirrors, whereas not all mirrors 53 | might have snapshots or desired release of your architecture or version. It presets options such as minimum 54 | verboseness of -v, -f, and finally: -S because the mirror list needs to be securely downloaded. 55 | This flag will also reset variables set by -O, -p and -n. 56 | 57 | -h will print the "help" options. 58 | 59 | -l (letter ell) will automatically loop a specified integer number of times if there are repeated potentially correctable errors. 60 | It will randomly select a different mirror each time it runs. 61 | It will return a value of 2 when the looping is exhausted. If it isn't specified, a 20x loop will be started. 62 | when it loops, it will detect if the last argv argument starts with "-l" if it does, it will ignore it to minimize the 63 | -l arguments. Then, in the instance of the first time, it will append a "-l19" to loop 19 more times. 64 | You may specify up to "-l 9999" It won't loop unless it needs to do so. 65 | 66 | -O will override and search for snapshot mirrors if it is a release; and will search for release mirrors if it a snapshot. 67 | Useful when you are running a pre-release snapshot without available release mirrors or...are just curious? 68 | 69 | -p searches for previous release package folders! It subtracts .1 from your version and searches for the release. 70 | 71 | -n searches for next release package folders! It adds .1 to your version and searches for the release. 72 | 73 | If both -n and -p are specified, it will default to the last argument specified. 74 | 75 | -r: rate purely by responsiveness like before 76 | 77 | -s will accept floating-point timeout like 1.5 seconds using strtold() and handrolled validation, eg. "-s 1.5" . Default 5. 78 | If -g is specified -s defaults to 10. 79 | 80 | -S (“Secure only”) option will convert the http mirrors to https mirrors. Otherwise, http mirrors will be chosen. 81 | http mirrors are likely faster than all https mirror selections, however they pass over the internet without encryption. 82 | for pkg_add, syspatch, sysupgrade, etc., integrity is still preserved by not using -S, but it will not provide 83 | secrecy...maybe you don't want the internets to know you're downloading hot-babe! LOL! 84 | 85 | -u will make it avoid loading mirrors with "USA" in the label for encryption export compliance 86 | (if that's still a thing) if you are searching from outside of the USA and Canada. 87 | I'm not sure if this eliminates all mirrors located in the USA. Mirrors with "(CDN)" label may be from the USA. 88 | Use your best judgement. If -u is used, usa_cmp() WILL NOT be used which will sort USA mirrors followed by 89 | CDN mirrors then followed by Canada mirrors. 90 | 91 | 92 | -U will only load mirrors with "USA", "Canada", and "CDN" in the label. This can be used with -u to only get 93 | Canada and CDN mirrors I suppose. 94 | 95 | 96 | -v will show when it is fetching "ftplist" from one of the many hard coded mirrors, prints out the results 97 | sorted in reverse order by time or if it is timed out, or a download error, 98 | subsorts whether it is a USA mirror, further subsorts alphabetically. 99 | prints a line for each mirror which you can copy and paste into a root terminal to "install" a mirror. 100 | 101 | -vv (an additional -v) will also make it print out the information of the mirrors in real time. 102 | 103 | -vvv (an additional -v) will also show ftp call output to mirrors; which includes a progress bar. 104 | The progress bar could be interesting if you are on dial-up. Is that still a thing? 105 | 106 | -vvvv (an additional -v) will also show dns lookup output if -d is not used. It will temporarily print a * with less -v's to indicate dns caching. 107 | Further -v arguments are ignored 108 | 109 | -V will stop all output except error messages. It overrides all -v instances. 110 | It's useful I suppose, if run from a script or daemon as root so that it writes the result to file. 111 | I won't stop you if you run ./pkg_ping -Vf .... Maybe you need to heat your house? 112 | 113 | pkg_ping will shorten the timeout period to the download time of the fastest previous mirror throughout ftp timing calls 114 | if no -v or if -V is used, so if you want the fastest single result, don't use -v or you could use -V, but it won't print the result to the screen. 115 | 116 | If it is run as root, it will make ftp calling processes change to the pkg_fetch user and ftp will revert to its environment which only has read access to the /var/empty directory, 117 | and ftp(1) doesn't unveil() so it probably is safer to run as root. 118 | 119 | If the parent process spins up dns caching, file writing and is calling ftp, it can be running 4 processes at one time, all with very different pledge sets. 120 | 121 | If it returns 1, something very bad has occurred or the timeout value is too low to find a successful mirror; 122 | something that running it again won't likely solve. 123 | 124 | If an error is thrown in the processes that precache dns records and writes the mirror to disk, it will restart. 125 | It will also restart if downloading 'ftplist' becomes unresponsive past a wait time defined in 'timeout0'. 126 | timeout0 specifies the maximum time it will wait to download the fresh mirror list: "ftplist" 127 | 'timeout0' can be extended by defining a larger -s value than what is hard-coded. 128 | 129 | I've observed at least one instance in which the dns caching process stalled for such a long time that 130 | I gave up on it. I make it restart if it takes longer than 50 seconds for a single dns caching attempt. 131 | If the timeout is too short, it could cause many loops which may both exhaust the quantity of -l loops 132 | which may cause a needless failure and may needlessly and repeatedly beat up on the mirrors. 133 | 134 | 135 | cc pkg_ping.c -o /usr/local/bin/pkg_ping 136 | 137 | cc pkg_ping.c -march=native -mtune=native -O3 -flto -pipe -o /usr/local/bin/pkg_ping 138 | 139 | Example usages: 140 | 141 | pkg_ping -vs1.5 -vvu 142 | 143 | /usr/local/bin/pkg_ping -vSvs 2 144 | -------------------------------------------------------------------------------- /pkg_ping.c: -------------------------------------------------------------------------------- 1 | /* 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2016 - 2025, Luke N Small, thinkitdoitdone@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 25 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 28 | * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | 33 | /* 34 | * Originally used the following from "Dan Mclaughlin" 35 | * on openbsd-misc mailing list 36 | * 37 | * 38 | * ftp -o - http://www.openbsd.org/ftp.html | \ 39 | * sed -n \ 40 | * -e 's:$::' \ 41 | * -e 's: \([^<]*\)<.*:\1:p' \ 42 | * -e 's:^\( [hfr].*\):\1:p' 43 | */ 44 | 45 | /* 46 | * As root: 47 | * cc pkg_ping.c -o /usr/local/bin/pkg_ping 48 | * 49 | * If you want bleeding edge performance, you can try: 50 | * 51 | 52 | As root: 53 | cc pkg_ping.c -march=native -mtune=native -flto -O3 -o /usr/local/bin/pkg_ping 54 | 55 | * run with: /usr/local/bin/pkg_ping 56 | * 57 | * if there are no other pkg_ping files in your execution path: 58 | * you can run with: pkg_ping 59 | * 60 | * You won't see ANY appreciable performance gain between the 61 | * getaddrinfo(3) and ftp(1) calls which fetch data over the network. 62 | * Everything else happens in likely less than third of a second 63 | * after the first ftp call starts to return its results. 64 | * 65 | * program designed to be viewed with tabs which are 8 characters wide 66 | */ 67 | 68 | #include 69 | 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | 88 | typedef struct { 89 | long double diff; 90 | long double speed; 91 | long double diff_rating; 92 | long double speed_rating; 93 | 94 | char *label; 95 | char *http; 96 | 97 | int diff_rank; 98 | int speed_rank; 99 | }MIRROR; 100 | 101 | extern char *malloc_options; 102 | 103 | /* strlen("http://") == 7 */ 104 | static int h = 7; 105 | static int array_length = 0; 106 | static int array_max = 200; 107 | static MIRROR *array = NULL; 108 | 109 | /* .5 second for an ftp SIGINT to turn into a SIGKILL */ 110 | static const struct timespec timeout_kill = { 0, 500000000 }; 111 | 112 | static int kq = -1; 113 | 114 | static char *diff_string = NULL; // initialized later 115 | static char *line = NULL; 116 | static char *line0 = NULL; 117 | static char *tag = NULL; 118 | 119 | static const size_t dns_socket_len = 1256; 120 | 121 | /* 122 | * Called once with atexit. It's the only function called with atexit 123 | * and free_array isn't called elsewhere 124 | */ 125 | static void 126 | free_array(void) 127 | { 128 | MIRROR *ac = array + array_length; 129 | 130 | while (array < ac) { 131 | --ac; 132 | free(ac->label); 133 | free(ac->http); 134 | } 135 | free(array); 136 | free(diff_string); 137 | free(line); 138 | free(line0); 139 | free(tag); 140 | free(malloc_options); 141 | } 142 | 143 | static long double almost_zero = 0.0L; 144 | 145 | /* 146 | * print long double which is <1 and >0, without the leading '0' 147 | * eg. 0.25 is printed: .25 148 | * it doesn't get here unless diff <1 and >= 0 149 | */ 150 | static void 151 | sub_one_print(long double diff) 152 | { 153 | int i = 0; 154 | if ((diff < almost_zero) && (diff >= 0.0L)) { 155 | (void)printf("0"); 156 | return; 157 | } 158 | if ((diff >= 1.0L) || (diff < 0.0L)) { 159 | errx(1, "Shouldn't ever get here line: %d", __LINE__); 160 | } 161 | 162 | i = snprintf(diff_string, 12, "%.9Lf", diff); 163 | if (i != 11) { 164 | if (i < 0) { 165 | err(1, "snprintf, line: %d\n", __LINE__); 166 | } else { 167 | err(1, "'line': %s, snprintf, line: %d\n", 168 | diff_string, __LINE__); 169 | } 170 | } 171 | (void)printf("%s", 1 + diff_string); 172 | } 173 | 174 | static int 175 | usa_cmp(const void *a, const void *b) 176 | { 177 | char *one_label = ((const MIRROR *) a)->label; 178 | char *two_label = ((const MIRROR *) b)->label; 179 | 180 | /* prioritize the USA mirrors first */ 181 | int temp = (int)(strstr(one_label, "USA") != NULL); 182 | if (temp != (int)(strstr(two_label, "USA") != NULL)) { 183 | if (temp) { 184 | return (-1); 185 | } 186 | return 1; 187 | } 188 | 189 | if (temp) { 190 | return 0; 191 | } 192 | 193 | /* prioritize Content Delivery Network "CDN" mirrors next */ 194 | temp = (int)(strstr(one_label, "CDN") != NULL); 195 | if (temp != (int)(strstr(two_label, "CDN") != NULL)) { 196 | if (temp) { 197 | return (-1); 198 | } 199 | return 1; 200 | } 201 | 202 | if (temp) { 203 | return 0; 204 | } 205 | 206 | /* prioritize Canada mirrors last */ 207 | temp = (int)(strstr(one_label, "Canada") != NULL); 208 | if (temp != (int)(strstr(two_label, "Canada") != NULL)) { 209 | if (temp) { 210 | return (-1); 211 | } 212 | return 1; 213 | } 214 | return 0; 215 | } 216 | 217 | /* 218 | * compare the labels alphabetically by proper decreasing 219 | * hierarchy which are in reverse order between commas. 220 | * 221 | * checks to make sure these procedures are safe, are performed in main 222 | * It can assume all commas in the labels are followed by a space 223 | */ 224 | static int 225 | label_cmp_minus_usa(const void *a, const void *b) 226 | { 227 | int ret = 0; 228 | const char *one_label = ((const MIRROR *) a)->label; 229 | const char *two_label = ((const MIRROR *) b)->label; 230 | 231 | // strlen(", ") == 2 232 | int rc = 2; 233 | int bc = 2; 234 | 235 | /* start with the last comma */ 236 | 237 | const char *red = strrchr(one_label, ','); 238 | const char *blu = strrchr(two_label, ','); 239 | 240 | if (red == NULL) { 241 | red = one_label; 242 | rc = 0; 243 | } 244 | if (blu == NULL) { 245 | blu = two_label; 246 | bc = 0; 247 | } 248 | 249 | ret = strcmp( 250 | red + rc, 251 | blu + bc 252 | ); 253 | 254 | while ((ret == 0) && rc && bc) { 255 | 256 | /* 257 | * search for a comma before the one 258 | * found in the previous iteration 259 | */ 260 | 261 | for (;;) { 262 | if (one_label >= red) { 263 | rc = 0; 264 | break; 265 | } 266 | --red; 267 | if (*red == ',') { 268 | break; 269 | } 270 | } 271 | 272 | for (;;) { 273 | if (two_label >= blu) { 274 | bc = 0; 275 | break; 276 | } 277 | --blu; 278 | if (*blu == ',') { 279 | break; 280 | } 281 | } 282 | 283 | ret = strcmp( 284 | red + rc, 285 | blu + bc 286 | ); 287 | } 288 | 289 | if (ret == 0) { 290 | 291 | /* 292 | * rc and bc are NOT both non-zero here 293 | * 294 | * if (rc || bc): 295 | * Either red or blu has no more comma 296 | * separated entries while remaining, equal. 297 | * The one with fewer commas is preferred first. 298 | */ 299 | if (bc) { 300 | return (-1); 301 | } 302 | if (rc) { 303 | return 1; 304 | } 305 | 306 | 307 | /* 308 | * exactly equal labels: 309 | * Checking for this condition initially 310 | * with a label strcmp() doesn't 311 | * provide useful information unless 312 | * the labels are exactly equal. 313 | * It isn't worth wasting time testing 314 | * for it initially because of its rarity. 315 | */ 316 | return strcmp( 317 | ((const MIRROR *) a)->http + h, 318 | ((const MIRROR *) b)->http + h 319 | ); 320 | } 321 | return ret; 322 | } 323 | 324 | static int 325 | diff_cmp_pure(const void *a, const void *b) 326 | { 327 | int ret = 0; 328 | const long double one_diff = ((const MIRROR *) a)->diff; 329 | const long double two_diff = ((const MIRROR *) b)->diff; 330 | 331 | if (one_diff < two_diff) { 332 | return (-1); 333 | } 334 | if (one_diff > two_diff) { 335 | return 1; 336 | } 337 | 338 | /* 339 | * Prioritize mirrors near to USA next. 340 | * They most likely didn't succeed past here. 341 | */ 342 | ret = usa_cmp(a, b); 343 | if (ret) { 344 | return ret; 345 | } 346 | 347 | /* reverse subsort label_cmp_minus_usa */ 348 | return label_cmp_minus_usa(b, a); 349 | } 350 | 351 | static int 352 | diff_cmp(const void *a, const void *b) 353 | { 354 | int ret = 0; 355 | const long double one_speed = ((const MIRROR *) a)->speed; 356 | const long double two_speed = ((const MIRROR *) b)->speed; 357 | 358 | const long double one_diff = ((const MIRROR *) a)->diff; 359 | const long double two_diff = ((const MIRROR *) b)->diff; 360 | 361 | if (one_speed > two_speed) { 362 | return (-1); 363 | } 364 | if (one_speed < two_speed) { 365 | return 1; 366 | } 367 | 368 | 369 | if (one_diff < two_diff) { 370 | return (-1); 371 | } 372 | if (one_diff > two_diff) { 373 | return 1; 374 | } 375 | 376 | /* 377 | * Prioritize mirrors near to USA next. 378 | * They most likely didn't succeed past here. 379 | */ 380 | ret = usa_cmp(a, b); 381 | if (ret) { 382 | return ret; 383 | } 384 | 385 | /* reverse subsort label_cmp_minus_usa */ 386 | return label_cmp_minus_usa(b, a); 387 | } 388 | 389 | /* 390 | * at this time, diff values represent the length of their http char* 391 | * stripped of the leading "http://" or "https://" and if it exists, 392 | * stripped of the trailing "/pub/OpenBSD". 393 | */ 394 | static int 395 | diff_cmp_g(const void *a, const void *b) 396 | { 397 | /* sort those with greater diff values first */ 398 | 399 | const int diff = ( 400 | (const int) ((const MIRROR *) b)->diff 401 | - 402 | (const int) ((const MIRROR *) a)->diff 403 | ); 404 | 405 | if (!diff) { 406 | 407 | return strcmp( 408 | ((const MIRROR *) a)->http, 409 | ((const MIRROR *) b)->http 410 | ); 411 | 412 | } 413 | return diff; 414 | } 415 | 416 | /* 417 | * diff_cmp_g can be used in the place of this function, but it is 418 | * far more efficient to avoid the many unnecessary strcmp() for mirrors 419 | * which have been turned to diff == 0; to be excised from the output. 420 | */ 421 | static int 422 | diff_cmp_g2(const void *a, const void *b) 423 | { 424 | const int one_len = (const int) ((const MIRROR *) a)->diff; 425 | const int two_len = (const int) ((const MIRROR *) b)->diff; 426 | 427 | /* 428 | * If either are an OpenBSD.org mirror... 429 | * (which means a non-zero diff) 430 | * 431 | * Vast majority of the time both will be zero 432 | * if so, dont process further. 433 | * 434 | * Otherwise, process like diff_cmp_g 435 | */ 436 | if (one_len || two_len) { 437 | 438 | /* sort those with greater len values first */ 439 | 440 | const int diff = two_len - one_len; 441 | if (!diff) { 442 | 443 | return strcmp( 444 | ((const MIRROR *) a)->http, 445 | ((const MIRROR *) b)->http 446 | ); 447 | 448 | } 449 | return diff; 450 | } 451 | return 0; 452 | } 453 | 454 | static int 455 | label_cmp(const void *a, const void *b) 456 | { 457 | /* prioritize mirrors near to USA first */ 458 | const int ret = usa_cmp(a, b); 459 | if (ret) { 460 | return ret; 461 | } 462 | 463 | return label_cmp_minus_usa(a, b); 464 | } 465 | 466 | static int 467 | unified_cmp(const void *a, const void *b) 468 | { 469 | const long double one_unified_rating = 470 | (((const MIRROR *) a)->diff_rating + 1.0L) 471 | * 472 | (((const MIRROR *) a)->speed_rating + 1.0L); 473 | 474 | 475 | const long double two_unified_rating = 476 | (((const MIRROR *) b)->diff_rating + 1.0L) 477 | * 478 | (((const MIRROR *) b)->speed_rating + 1.0L); 479 | 480 | 481 | if (one_unified_rating > two_unified_rating) { 482 | return (-1); 483 | } else if (one_unified_rating < two_unified_rating) { 484 | return 1; 485 | } else { 486 | return 0; 487 | } 488 | } 489 | 490 | static void 491 | manpage(void) 492 | { 493 | (void)printf("[-6 (only return IPv6 compatible mirrors)]\n"); 494 | 495 | (void)printf( 496 | "[-a (rate by an Average of responsiveness and bandwidth!\n"); 497 | (void)printf(" This is the default when -v's"); 498 | (void)printf(" and no -V are chosen.)]\n"); 499 | 500 | (void)printf("[-b (rate by the Bandwidth of the download!)]\n"); 501 | 502 | (void)printf( 503 | "[-D (Debug mode. Short circuit mirror downloads.\n "); 504 | (void)printf("Show elapsed time since ftplist starts downloading.)]\n"); 505 | 506 | (void)printf("[-d (don't cache DNS)]\n"); 507 | 508 | (void)printf( 509 | "[-f (don't automatically write to File if run as root)]\n"); 510 | 511 | (void)printf("[-G (Generate source ftp list: all)]\n"); 512 | 513 | (void)printf("[-g (Generate source ftp list: only accessible ones)]\n"); 514 | 515 | (void)printf("[-h (print this Help message and exit)]\n"); 516 | 517 | (void)printf( 518 | "[-l (ell) quantity of attempts the program will restart\n"); 519 | (void)printf( 520 | " in a Loop for recoverable errors (default 20)]\n"); 521 | 522 | (void)printf("[-n (search for mirrors with the Next release!)]\n"); 523 | 524 | (void)printf( 525 | "[-O (if you're running a snapshot, it will Override it and\n"); 526 | (void)printf(" search for release mirrors. "); 527 | (void)printf("If you're running a release,\n"); 528 | (void)printf(" it will Override it and "); 529 | (void)printf("search for snapshot mirrors.)\n"); 530 | 531 | (void)printf("[-p (search for mirrors with the Previous release!)]\n"); 532 | 533 | (void)printf( 534 | "[-r (rate by how quickly it Responds to the download!)]\n"); 535 | 536 | (void)printf("[-S (converts http mirrors into Secure https mirrors\n"); 537 | (void)printf(" http mirrors still preserve file integrity!)]\n"); 538 | 539 | (void)printf("[-s timeout in Seconds (eg. -s 2.3) (default 10 if -g\n"); 540 | (void)printf(" is specified. Otherwise default 5)]\n"); 541 | 542 | (void)printf("[-U (USA, CDN and Canada mirrors Only."); 543 | (void)printf("\n "); 544 | (void)printf("This will likely be faster if you are in these areas."); 545 | (void)printf("\n "); 546 | (void)printf("The program will absolutely take less runtime.)]"); 547 | (void)printf("\n"); 548 | 549 | (void)printf("[-u (no USA mirrors to comply "); 550 | (void)printf("with USA encryption export laws.)]\n"); 551 | 552 | (void)printf( 553 | "[-V (no Verbose output. No output except error messages)]\n"); 554 | 555 | (void)printf( 556 | "[-v (increase Verbosity. It recognizes up to 4 of these)]\n\n"); 557 | 558 | 559 | (void)printf("More information at: "); 560 | (void)printf("https://github.com/lukensmall/pkg_ping\n\n"); 561 | } 562 | 563 | static __attribute__((noreturn)) void 564 | dns_cache_d(const int dns_socket, const int secure, 565 | const int six, const int verbose) 566 | { 567 | int i = 0; 568 | int g = 0; 569 | int c = 0; 570 | struct addrinfo *res0 = NULL; 571 | struct addrinfo *res = NULL; 572 | 573 | /* 574 | from: /usr/src/include/netdb.h 575 | struct addrinfo { 576 | int ai_flags; 577 | int ai_family; 578 | int ai_socktype; 579 | int ai_protocol; 580 | socklen_t ai_addrlen; 581 | struct sockaddr *ai_addr; 582 | char *ai_canonname; 583 | struct addrinfo *ai_next; 584 | }; 585 | */ 586 | const struct addrinfo hints = 587 | { AI_FQDN, AF_UNSPEC, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; 588 | 589 | struct sockaddr_in *sa4 = NULL; 590 | uint32_t sui4 = 0; 591 | 592 | struct sockaddr_in6 *sa6 = NULL; 593 | u_char *suc6 = NULL; 594 | 595 | int max = 0; 596 | int i_temp = 0; 597 | int i_max = 0; 598 | char six_available = '0'; 599 | 600 | const char *dns_line0 = (secure) ? "https" : "http"; 601 | const char *dns_line0_alt = (secure) ? "443" : "80"; 602 | 603 | const char hexadec[16] = { '0','1','2','3', 604 | '4','5','6','7', 605 | '8','9','a','b', 606 | 'c','d','e','f' }; 607 | 608 | char *dns_line = (char*)calloc(dns_socket_len, sizeof(char)); 609 | if (dns_line == NULL) { 610 | (void)printf("calloc\n"); 611 | goto dns_exit1; 612 | } 613 | 614 | if (pledge("stdio dns", NULL) == -1) { 615 | (void)printf("%s ", strerror(errno)); 616 | (void)printf("dns_cache_d pledge, line: %d\n", __LINE__); 617 | _exit(1); 618 | } 619 | 620 | dns_loop: 621 | 622 | i = (int)read(dns_socket, dns_line, dns_socket_len); 623 | if (i == 0) { 624 | free(dns_line); 625 | (void)close(dns_socket); 626 | _exit(0); 627 | } 628 | 629 | if (i == dns_socket_len) { 630 | (void)printf("i == dns_socket_len, line: %d\n", __LINE__); 631 | goto dns_exit1; 632 | } 633 | 634 | if (i == -1) { 635 | (void)printf("%s ", strerror(errno)); 636 | (void)printf("read error line: %d\n", __LINE__); 637 | goto dns_exit1; 638 | } 639 | dns_line[i] = '\0'; 640 | 641 | if (verbose == 4) { 642 | (void)printf("DNS caching: %s\n", dns_line); 643 | } 644 | 645 | 646 | if (getaddrinfo(dns_line, dns_line0, &hints, &res0)) { 647 | 648 | c = getaddrinfo(dns_line, dns_line0_alt, &hints, &res0); 649 | 650 | if (c) { 651 | if (verbose == 4) { 652 | (void)printf("%s\n", gai_strerror((int)c)); 653 | } 654 | i = (int)write(dns_socket, "f", 1); 655 | if (i < 1) { 656 | (void)printf("%s ", strerror(errno)); 657 | (void)printf("write error line: %d\n", 658 | __LINE__); 659 | goto dns_exit1; 660 | } 661 | goto dns_loop; 662 | } 663 | } 664 | 665 | if ((verbose < 4) && (six == 0)) { 666 | for (res = res0; res; res = res->ai_next) { 667 | 668 | if (res->ai_family == AF_INET) { 669 | 670 | /* 671 | * compiler complains of potential misalignment 672 | */ 673 | // sa4 = (struct sockaddr_in *) res->ai_addr; 674 | 675 | memcpy(&sa4, &res->ai_addr, 676 | sizeof(struct sockaddr_in *)); 677 | 678 | sui4 = sa4->sin_addr.s_addr; 679 | 680 | /* 681 | * I have an unbound dns blocklist where I 682 | * force unwanted domains to resolve to 683 | * 0.0.0.0 which translates to sui4 == 0 684 | * This shouldn't impact functionality 685 | * for others. 686 | */ 687 | if (sui4 == 0U) { 688 | continue; 689 | } 690 | break; 691 | } 692 | 693 | if (res->ai_family == AF_INET6) { 694 | break; 695 | } 696 | } 697 | 698 | if (res == NULL) { 699 | i = (int)write(dns_socket, "u", 1); 700 | } else { 701 | i = (int)write(dns_socket, "1", 1); 702 | } 703 | 704 | if (i != 1) { 705 | if (i == -1) { 706 | (void)printf("%s ", strerror(errno)); 707 | } 708 | (void)printf("write error line: %d\n", __LINE__); 709 | goto dns_exit1; 710 | } 711 | freeaddrinfo(res0); 712 | goto dns_loop; 713 | } 714 | 715 | six_available = 'u'; 716 | 717 | for (res = res0; res; res = res->ai_next) { 718 | 719 | if (res->ai_family == AF_INET) { 720 | 721 | /* 722 | * compiler complains of potential misalignment 723 | */ 724 | // sa4 = (struct sockaddr_in *) res->ai_addr; 725 | 726 | memcpy(&sa4, &res->ai_addr, 727 | sizeof(struct sockaddr_in *)); 728 | 729 | sui4 = sa4->sin_addr.s_addr; 730 | 731 | /* 732 | * I have an unbound dns blocklist where I 733 | * force unwanted domains to resolve to 734 | * 0.0.0.0 which translates to sui4 == 0 735 | * I don't expect a negative impact 736 | * to functionality for others. 737 | */ 738 | if ((six_available == 'u') && sui4) { 739 | six_available = '0'; 740 | } 741 | 742 | if (six) { 743 | continue; 744 | } 745 | 746 | (void)printf(" %hhu.%hhu.%hhu.%hhu\n", 747 | (uint8_t) sui4, 748 | (uint8_t)(sui4 >> 8), 749 | (uint8_t)(sui4 >> 16), 750 | (uint8_t)(sui4 >> 24)); 751 | continue; 752 | } 753 | 754 | if (res->ai_family != AF_INET6) { 755 | continue; 756 | } 757 | 758 | six_available = '1'; 759 | 760 | if (verbose < 4) { 761 | break; 762 | } 763 | 764 | (void)printf(" "); 765 | 766 | /* 767 | * compiler complains of potential misalignment 768 | */ 769 | // sa6 = (struct sockaddr_in6 *) res->ai_addr; 770 | 771 | memcpy(&sa6, &res->ai_addr, sizeof(struct sockaddr_in6 *)); 772 | 773 | suc6 = sa6->sin6_addr.s6_addr; 774 | 775 | c = 0; 776 | max = 0; 777 | i_max = -1; 778 | 779 | /* 780 | * load largest >1 gap beginning into i_max 781 | * and the length of the gap into max 782 | */ 783 | for (i = 0; i < 16; i += 2) { 784 | 785 | if ( suc6[i] || suc6[i + 1] ) { 786 | c = 0; 787 | continue; 788 | } 789 | 790 | if (c == 0) { 791 | i_temp = i; 792 | c = 1; 793 | continue; 794 | } 795 | 796 | ++c; 797 | 798 | if (max < c) { 799 | max = c; 800 | i_max = i_temp; 801 | } 802 | } 803 | 804 | for (i = 0; i < 16; i += 2) { 805 | 806 | if (i) { 807 | (void)printf(":"); 808 | } 809 | 810 | if (i == i_max) { 811 | if (i == 0) { 812 | (void)printf("::"); 813 | } else { 814 | (void)printf(":"); 815 | } 816 | i += 2 * max; 817 | if (i >= 16) { 818 | break; 819 | } 820 | } 821 | 822 | g = i + 1; 823 | 824 | if (suc6[i] / (u_char)16) { 825 | (void)printf("%c%c%c%c", 826 | hexadec[suc6[i] / (u_char)16], 827 | hexadec[suc6[i] % (u_char)16], 828 | hexadec[suc6[g] / (u_char)16], 829 | hexadec[suc6[g] % (u_char)16]); 830 | 831 | } else if (suc6[i]) { // Here: suc6[i] == suc6[i] % 16 832 | (void)printf("%c%c%c", 833 | hexadec[suc6[i] ], 834 | hexadec[suc6[g] / (u_char)16], 835 | hexadec[suc6[g] % (u_char)16]); 836 | 837 | } else if (suc6[g] / (u_char)16) { 838 | (void)printf("%c%c", 839 | hexadec[suc6[g] / (u_char)16], 840 | hexadec[suc6[g] % (u_char)16]); 841 | } else { 842 | // Here: suc6[g] == suc6[g] % 16 843 | (void)printf("%c", 844 | hexadec[suc6[g] ]); 845 | } 846 | } 847 | (void)printf("\n"); 848 | } 849 | freeaddrinfo(res0); 850 | 851 | i = (int)write(dns_socket, &six_available, 1); 852 | 853 | if (i != 1) { 854 | if (i == -1) { 855 | (void)printf("%s ", strerror(errno)); 856 | } 857 | (void)printf("write error line: %d\n", __LINE__); 858 | goto dns_exit1; 859 | } 860 | 861 | goto dns_loop; 862 | 863 | dns_exit1: 864 | 865 | free(dns_line); 866 | (void)close(dns_socket); 867 | _exit(1); 868 | } 869 | 870 | /* 871 | * I considered keeping this functionality in main(), but 872 | * if there's a possibility of the main() getting overrun, 873 | * this process performs some sanity checks to, among 874 | * other things, prevent /etc/installurl from becoming a 875 | * massive file which fills up the partition. 876 | */ 877 | static __attribute__((noreturn)) void 878 | file_d(const int write_pipe, const int secure, 879 | const int debug, const int verbose) 880 | { 881 | 882 | int i = 0; 883 | int ret = 1; 884 | 885 | char *file_w = NULL; 886 | FILE *pkg_write = NULL; 887 | const size_t max_file_length = 1302; 888 | const size_t received_max = 1 + max_file_length - 2; 889 | ssize_t received = 0; 890 | 891 | 892 | 893 | if (pledge("stdio cpath wpath", NULL) == -1) { 894 | (void)printf("%s ", strerror(errno)); 895 | (void)printf("pledge, line: %d\n", __LINE__); 896 | _exit(1); 897 | } 898 | 899 | if (max_file_length <= 7 + (const size_t)secure + 2 + 1) { 900 | errx(1, "max_file_length is too short"); 901 | } 902 | 903 | file_w = (char*)malloc(max_file_length); 904 | if (file_w == NULL) { 905 | (void)printf("malloc\n"); 906 | _exit(1); 907 | } 908 | 909 | received = read(write_pipe, file_w, received_max); 910 | 911 | if (received == -1) { 912 | (void)printf("%s ", strerror(errno)); 913 | (void)close(write_pipe); 914 | (void)printf("read error occurred, line: %d\n", __LINE__); 915 | (void)printf("/etc/installurl not written.\n"); 916 | goto file_cleanup; 917 | } 918 | 919 | (void)close(write_pipe); 920 | 921 | if (received == 0) { 922 | (void)printf("program exited without writing.\n"); 923 | (void)printf("/etc/installurl not written.\n"); 924 | goto file_cleanup; 925 | } 926 | 927 | if (received == (ssize_t)received_max) { 928 | (void)printf("received mirror is too large\n"); 929 | (void)printf("/etc/installurl not written.\n"); 930 | goto file_cleanup; 931 | } 932 | 933 | (void)memcpy(file_w + received, "\n", 1 + 1); 934 | 935 | if (secure) { 936 | if (strncmp(file_w, "https://", 8)) { 937 | (void)printf("file_w does't begin with "); 938 | (void)printf("\"https://\", line: %d\n", __LINE__); 939 | (void)printf("/etc/installurl not written.\n"); 940 | goto file_cleanup; 941 | } 942 | } else { 943 | if (strncmp(file_w, "http://", 7)) { 944 | (void)printf("file_w does't begin with "); 945 | (void)printf("\"http://\", line: %d\n", __LINE__); 946 | (void)printf("/etc/installurl not written.\n"); 947 | goto file_cleanup; 948 | } 949 | } 950 | 951 | /* unlink() to prevent possible symlinks by...root? */ 952 | if (debug) { 953 | if (verbose > 0) { 954 | (void)printf("\nDebug mode: file not written.\n"); 955 | } else { 956 | (void)printf("Debug mode: file not written.\n"); 957 | } 958 | } else { 959 | 960 | /* unlink() to prevent possible symlinks by...root? */ 961 | (void)unlink("/etc/installurl"); 962 | pkg_write = fopen("/etc/installurl", "w"); 963 | 964 | if (pledge("stdio wpath", NULL) == -1) { 965 | (void)printf("%s ", strerror(errno)); 966 | (void)printf("pledge, line: %d\n", __LINE__); 967 | goto file_cleanup; 968 | } 969 | 970 | if (verbose > 0) { 971 | (void)printf("\n"); 972 | } 973 | 974 | if (pkg_write == NULL) { 975 | (void)printf("%s ", strerror(errno)); 976 | (void)printf("/etc/installurl not opened.\n"); 977 | goto file_cleanup; 978 | } 979 | 980 | i = (int)fwrite(file_w, 1, (size_t)received + 1, pkg_write); 981 | (void)fclose(pkg_write); 982 | if (i < (int)received + 1) { 983 | (void)printf("write error occurred, line: %d\n", 984 | __LINE__); 985 | goto file_cleanup; 986 | } 987 | } 988 | 989 | if (pledge("stdio", NULL) == -1) { 990 | (void)printf("%s ", strerror(errno)); 991 | (void)printf("pledge, line: %d\n", __LINE__); 992 | goto file_cleanup; 993 | } 994 | 995 | if (verbose >= 0) { 996 | (void)printf("/etc/installurl: %s", file_w); 997 | } 998 | 999 | ret = 0; 1000 | 1001 | file_cleanup: 1002 | 1003 | free(file_w); 1004 | _exit(ret); 1005 | } 1006 | 1007 | static __attribute__((noreturn)) void 1008 | restart(int argc, char *argv[], const int loop, const int verbose) 1009 | { 1010 | int c; 1011 | const int len = 10; 1012 | 1013 | const int n 1014 | = argc - (int)((argc > 1) && (!strncmp(argv[argc - 1], "-l", 2))); 1015 | 1016 | char **new_args = calloc((size_t)n + 1 + 1, sizeof(char *)); 1017 | if (new_args == NULL) { 1018 | errx(1, "calloc"); 1019 | } 1020 | 1021 | if (loop == 0) { 1022 | free(new_args); 1023 | errx(2, "Looping exhausted: Try again."); 1024 | } 1025 | 1026 | if (verbose != -1) { 1027 | (void)printf("restarting...loop: %d\n", loop); 1028 | } 1029 | 1030 | (void)memcpy(new_args, argv, (size_t)n * sizeof(char *)); 1031 | 1032 | new_args[n] = (char*)calloc(len, sizeof(char)); 1033 | if (new_args[n] == NULL) { 1034 | errx(1, "calloc"); 1035 | } 1036 | c = snprintf(new_args[n], len, "-l%d", loop - 1); 1037 | if ((c >= len) || (c < 0)) { 1038 | if (c < 0) { 1039 | err(1, "snprintf, line: %d\n", __LINE__); 1040 | } else { 1041 | err(1, "new_args[n]: %s, snprintf, line: %d\n", 1042 | new_args[n], __LINE__); 1043 | } 1044 | } 1045 | 1046 | (void)close(kq); 1047 | 1048 | 1049 | /* hard-code to /usr/local/bin/pkg_ping */ 1050 | 1051 | (void)execv("/usr/local/bin/pkg_ping", new_args); 1052 | err(1, "execv failed, line: %d", __LINE__); 1053 | } 1054 | 1055 | static void 1056 | easy_ftp_kill(const pid_t ftp_pid) 1057 | { 1058 | struct kevent ke; 1059 | EV_SET(&ke, ftp_pid, EVFILT_PROC, EV_ADD | 1060 | EV_ONESHOT, NOTE_EXIT, 0, NULL); 1061 | 1062 | /* kevent registration returns -1, if ftp_pid is already dead */ 1063 | errno = 0; 1064 | (void)kevent(kq, &ke, 1, NULL, 0, NULL); 1065 | if (errno) { 1066 | if (errno != ESRCH) { 1067 | (void)printf("%s ", strerror(errno)); 1068 | (void)printf("kevent, line: %d\n", __LINE__); 1069 | /* Don't exit. Already dying. */ 1070 | } 1071 | } else { 1072 | 1073 | (void)kill(ftp_pid, SIGINT); 1074 | 1075 | /* 1076 | * give it time to gracefully abort, and play nice 1077 | * with the server before killing it with prejudice 1078 | */ 1079 | if (!kevent(kq, NULL, 0, &ke, 1, &timeout_kill)) { 1080 | (void)kill(ftp_pid, SIGKILL); 1081 | } 1082 | 1083 | } 1084 | (void)waitpid(ftp_pid, NULL, 0); 1085 | } 1086 | 1087 | int 1088 | main(int argc, char *argv[]) 1089 | { 1090 | 1091 | #ifndef __OpenBSD__ 1092 | #error Only run on OpenBSD 1093 | #endif 1094 | 1095 | int entry_line = __LINE__; 1096 | 1097 | 1098 | /* GENERATED CODE BEGINS HERE */ 1099 | 1100 | 1101 | const char *ftp_list[62] = { 1102 | 1103 | "mirrors.syringanetworks.net","openbsd.mirror.constant.com", 1104 | "plug-mirror.rcac.purdue.edu","cloudflare.cdn.openbsd.org", 1105 | "ftp.halifax.rwth-aachen.de","ftp.rnl.tecnico.ulisboa.pt", 1106 | "openbsd.mirrors.hoobly.com","mirror.raiolanetworks.com", 1107 | "mirrors.ocf.berkeley.edu","mirror.hs-esslingen.de","mirrors.pidginhost.com", 1108 | "openbsd.cs.toronto.edu","*artfiles.org/openbsd","mirror.planetunix.net", 1109 | "www.mirrorservice.org","mirror.aarnet.edu.au","openbsd.c3sl.ufpr.br", 1110 | "ftp.usa.openbsd.org","ftp2.eu.openbsd.org","ftp2.fr.openbsd.org", 1111 | "mirror.leaseweb.com","mirror.telepoint.bg","mirrors.gigenet.com", 1112 | "openbsd.eu.paket.ua","ftp.eu.openbsd.org","ftp.fr.openbsd.org", 1113 | "ftp.lysator.liu.se","mirror.freedif.org","mirror.fsmg.org.nz", 1114 | "mirror.ungleich.ch","mirrors.aliyun.com","mirrors.dotsrc.org", 1115 | "openbsd.ipacct.com","ftp.hostserver.de","mirrors.chroot.ro", 1116 | "mirrors.sonic.net","mirrors.ucr.ac.cr","openbsd.as250.net","mirror.group.one", 1117 | "mirror.litnet.lt","mirror.yandex.ru","mirrors.ircam.fr","openbsd.paket.ua", 1118 | "cdn.openbsd.org","ftp.OpenBSD.org","ftp.jaist.ac.jp","mirror.ihost.md", 1119 | "mirror.junda.nl","mirror.ox.ac.uk","mirrors.mit.edu","repo.jing.rocks", 1120 | "ftp.icm.edu.pl","mirror.rise.ph","ftp.cc.uoc.gr","ftp.spline.de", 1121 | "www.ftp.ne.jp","ftp.nluug.nl","ftp.riken.jp","ftp.psnc.pl","ftp.bit.nl", 1122 | "ftp.fau.de","ftp.uio.no" 1123 | 1124 | }; 1125 | 1126 | const int ftp_list_index = 62; 1127 | 1128 | 1129 | 1130 | /* Trusted OpenBSD.org subdomain mirrors for generating this section */ 1131 | 1132 | const char *ftp_list_g[8] = { 1133 | 1134 | "cloudflare.cdn.openbsd.org","ftp.usa.openbsd.org","ftp2.eu.openbsd.org", 1135 | "ftp2.fr.openbsd.org","ftp.eu.openbsd.org","ftp.fr.openbsd.org", 1136 | "cdn.openbsd.org","ftp.OpenBSD.org" 1137 | 1138 | }; 1139 | 1140 | const int ftp_list_index_g = 8; 1141 | 1142 | 1143 | /* GENERATED CODE ENDS HERE */ 1144 | 1145 | 1146 | int exit_line = __LINE__; 1147 | 1148 | size_t tag_len = 0; 1149 | 1150 | int sort_ret = 0; 1151 | 1152 | int root_user = (int)(getuid() == 0); 1153 | 1154 | int responsiveness = 0; 1155 | int bandwidth = 0; 1156 | int average = 1; 1157 | int to_file = root_user; 1158 | int num = 0; 1159 | int current = 0; 1160 | int secure = 0; 1161 | int generate = 0; 1162 | int all = 0; /* this shouldn't be 1 unless generate is too */ 1163 | int override = 0; 1164 | int six = 0; 1165 | int previous = 0; 1166 | int next = 0; 1167 | int s_set = 0; 1168 | int debug = 0; 1169 | 1170 | int dns_cache = 1; 1171 | int usa = 1; 1172 | int USA = 0; 1173 | 1174 | long double S = 0.0L; 1175 | 1176 | pid_t dns_cache_d_pid = 0; 1177 | pid_t write_pid = 0; 1178 | pid_t ftp_pid = 0; 1179 | 1180 | int std_err = 0; 1181 | int z = 0; 1182 | int i = 0; 1183 | int c = 0; 1184 | int n = 0; 1185 | int j = 0; 1186 | 1187 | int pos_max = 0; 1188 | int loop = 20; 1189 | int pos = 0; 1190 | int verbose = 0; 1191 | 1192 | size_t len = 0; 1193 | 1194 | int dns_cache_d_socket[2] = { -1, -1 }; 1195 | int write_pipe[2] = { -1, -1 }; 1196 | int ftp_out[2] = { -1, -1 }; 1197 | int ftp_helper_out[2] = { -1, -1 }; 1198 | int block_socket[2] = { -1, -1 }; 1199 | 1200 | struct timespec start = { 0, 0 }; 1201 | struct timespec end = { 0, 0 }; 1202 | 1203 | struct timespec timeout = { 0, 0 }; 1204 | struct timespec startD = { 0, 0 }; 1205 | struct timespec endD = { 0, 0 }; 1206 | 1207 | char *line_temp = NULL; 1208 | char *release = NULL; 1209 | 1210 | char *current_time = NULL; 1211 | char v = '\0'; 1212 | 1213 | 1214 | /* 1215 | from: /usr/src/sys/sys/event.h 1216 | struct kevent { 1217 | __uintptr_t ident; 1218 | short filter; 1219 | unsigned short flags; 1220 | unsigned int fflags; 1221 | __int64_t data; 1222 | void *udata; 1223 | }; 1224 | */ 1225 | struct kevent ke = { 0, 0, 0, 0, 0, NULL }; 1226 | 1227 | /* 5 second default mirror timeout */ 1228 | long double s = 5.0L; 1229 | 1230 | /* 10 seconds and 0 nanoseconds to download ftplist */ 1231 | struct timespec timeout_ftp_list = { 10, 0 }; 1232 | 1233 | 1234 | /* 1235 | from: /usr/src/sys/sys/ttycom.h 1236 | struct winsize { 1237 | unsigned short ws_row; rows, in characters 1238 | unsigned short ws_col; columns, in characters 1239 | unsigned short ws_xpixel; horizontal size, pixels 1240 | unsigned short ws_ypixel; vertical size, pixels 1241 | }; 1242 | */ 1243 | struct winsize w = { 0, 0, 0, 0 }; 1244 | 1245 | MIRROR *ac = NULL; 1246 | int pos_maxl = 0; 1247 | int pos_maxh = 0; 1248 | int pos_maxb = 0; 1249 | int pos1 = 0; 1250 | 1251 | int num1 = 0; 1252 | int num2 = 0; 1253 | int num3 = 0; 1254 | char *host = NULL; 1255 | char *cut = NULL; 1256 | 1257 | malloc_options = strdup("CFGJJjU"); 1258 | if (malloc_options == NULL) { 1259 | err(1, "malloc"); 1260 | } 1261 | 1262 | kq = kqueue(); 1263 | if (kq == -1) { 1264 | errx(1, "kqueue() error, line :%d", __LINE__); 1265 | } 1266 | 1267 | errno = 0; 1268 | almost_zero = strtold(".000000001", NULL); 1269 | if (errno) { 1270 | err(1, "almost_zero == 0, line: %d", __LINE__); 1271 | } 1272 | 1273 | i = pledge("stdio exec proc cpath wpath dns id unveil tty", NULL); 1274 | if (i == -1) { 1275 | err(1, "pledge, line: %d", __LINE__); 1276 | } 1277 | 1278 | i = ioctl(0, TIOCGWINSZ, &w); 1279 | if (i == -1) { 1280 | err(1, "ioctl, line: %d", __LINE__); 1281 | } 1282 | 1283 | if (unveil("/usr/bin/ftp", "x") == -1) { 1284 | err(1, "unveil, line: %d", __LINE__); 1285 | } 1286 | 1287 | if (unveil("/usr/local/bin/pkg_ping", "x") == -1) { 1288 | err(1, "unveil, line: %d", __LINE__); 1289 | } 1290 | 1291 | if (to_file) { 1292 | 1293 | if (unveil("/etc/installurl", "cw") == -1) { 1294 | err(1, "unveil, line: %d", __LINE__); 1295 | } 1296 | 1297 | if (pledge("stdio exec proc cpath wpath dns id", NULL) == -1) { 1298 | err(1, "pledge, line: %d", __LINE__); 1299 | } 1300 | } else { 1301 | if (pledge("stdio exec proc dns id", NULL) == -1) { 1302 | err(1, "pledge, line: %d", __LINE__); 1303 | } 1304 | } 1305 | 1306 | diff_string = (char*)calloc(11 + 1, sizeof(char)); 1307 | if (diff_string == NULL) { 1308 | errx(1, "calloc"); 1309 | } 1310 | 1311 | if (argc < 1) { 1312 | (void)printf("argc cannot be less than 1!\n"); 1313 | } 1314 | 1315 | if (argc >= 30) { 1316 | i = (int)(!strncmp(argv[argc - 1], "-l", 2)); 1317 | if ((argc - i) >= 30) { 1318 | errx(1, "keep argument count under 30"); 1319 | } 1320 | } 1321 | 1322 | for(c = 1; c < argc; ++c) { 1323 | if (strnlen(argv[c], 35) == 35) { 1324 | errx(1, "keep argument lengths under 35"); 1325 | } 1326 | } 1327 | 1328 | 1329 | for(;;) { 1330 | c = getopt(argc, argv, "6abDdfGghl:nOprSs:uUVv"); 1331 | if (c == -1) { 1332 | break; 1333 | } 1334 | switch (c) { 1335 | case '6': 1336 | six = 1; 1337 | break; 1338 | case 'a': 1339 | average = 2; 1340 | bandwidth = 0; 1341 | responsiveness = 0; 1342 | break; 1343 | case 'b': 1344 | average = 0; 1345 | bandwidth = 1; 1346 | responsiveness = 0; 1347 | break; 1348 | case 'D': 1349 | debug = 1; 1350 | break; 1351 | case 'd': 1352 | dns_cache = 0; 1353 | break; 1354 | case 'f': 1355 | to_file = 0; 1356 | if (pledge("stdio exec proc dns id", NULL) == -1) { 1357 | err(1, "pledge, line: %d", __LINE__); 1358 | } 1359 | break; 1360 | case 'G': 1361 | all = 1; 1362 | generate = 1; 1363 | break; 1364 | case 'g': 1365 | generate = 1; 1366 | break; 1367 | case 'h': 1368 | manpage(); 1369 | return 0; 1370 | case 'l': 1371 | if (strlen(optarg) >= 5) { 1372 | (void)printf("keep -l argument under "); 1373 | (void)printf("5 characters long.\n"); 1374 | return 1; 1375 | } 1376 | 1377 | c = 0; 1378 | loop = 0; 1379 | do { 1380 | if ((optarg[c] < '0') || (optarg[c] > '9')) { 1381 | (void)printf("-l argument "); 1382 | (void)printf("only accepts "); 1383 | (void)printf("numeric characters\n"); 1384 | return 1; 1385 | } 1386 | loop = (loop * 10) + (int)(optarg[c] - '0'); 1387 | ++c; 1388 | } while (optarg[c] != '\0'); 1389 | break; 1390 | case 'n': 1391 | previous = 0; 1392 | next = 1; 1393 | break; 1394 | case 'O': 1395 | override = 1; 1396 | break; 1397 | case 'p': 1398 | next = 0; 1399 | previous = 1; 1400 | break; 1401 | case 'r': 1402 | average = 0; 1403 | bandwidth = 0; 1404 | responsiveness = 1; 1405 | break; 1406 | case 'S': 1407 | secure = 1; 1408 | break; 1409 | case 's': 1410 | 1411 | if (!strcmp(optarg, ".")) { 1412 | errx(1, "-s argument should not be: \".\""); 1413 | } 1414 | 1415 | if (strlen(optarg) >= 15) { 1416 | (void)printf("keep -s argument under "); 1417 | (void)printf("15 characters long\n"); 1418 | return 1; 1419 | } 1420 | 1421 | i = 0; 1422 | c = 0; 1423 | do { 1424 | if ((optarg[c] >= '0') && (optarg[c] <= '9')) { 1425 | ++c; 1426 | continue; 1427 | } 1428 | ++i; 1429 | if ((optarg[c] == '.') && (i == 1)) { 1430 | ++c; 1431 | continue; 1432 | } 1433 | 1434 | (void)printf("-s argument should only "); 1435 | (void)printf("have numeric "); 1436 | (void)printf("characters and a maximum "); 1437 | (void)printf("of one decimal point\n"); 1438 | return 1; 1439 | 1440 | } while (optarg[c] != '\0'); 1441 | 1442 | errno = 0; 1443 | s = strtold(optarg, &line_temp); 1444 | 1445 | if (errno || (optarg == line_temp)) { 1446 | (void)printf("\"%s\" is an invalid ", optarg); 1447 | (void)printf("argument for -s\n"); 1448 | return 1; 1449 | } 1450 | 1451 | free(current_time); 1452 | current_time = strdup(optarg); 1453 | if (current_time == NULL) { 1454 | errx(1, "strdup"); 1455 | } 1456 | 1457 | break; 1458 | case 'u': 1459 | usa = 0; 1460 | break; 1461 | case 'U': 1462 | USA = 1; 1463 | break; 1464 | case 'V': 1465 | verbose = -1; 1466 | break; 1467 | case 'v': 1468 | if (verbose == -1) { 1469 | break; 1470 | } 1471 | ++verbose; 1472 | if (verbose > 4) { 1473 | verbose = 4; 1474 | } 1475 | break; 1476 | default: 1477 | manpage(); 1478 | return 1; 1479 | } 1480 | } 1481 | if (optind < argc) { 1482 | manpage(); 1483 | errx(1, "non-option ARGV-element: %s", argv[optind]); 1484 | } 1485 | 1486 | if (generate) { 1487 | if (all) { 1488 | verbose = 1; 1489 | dns_cache = 0; 1490 | } else if (verbose < 1) { 1491 | verbose = 1; 1492 | } 1493 | secure = 1; 1494 | next = 0; 1495 | previous = 0; 1496 | override = 0; 1497 | to_file = 0; 1498 | if (pledge("stdio exec proc dns id", NULL) == -1) { 1499 | err(1, "pledge, line: %d", __LINE__); 1500 | } 1501 | 1502 | /* change default 's' value if not specified */ 1503 | if (current_time == NULL) { 1504 | s = 10.0L; 1505 | } 1506 | } 1507 | 1508 | if (s > 1000.0L) { 1509 | errx(1, "try an -s less than, equal to 1000"); 1510 | } 1511 | 1512 | 1513 | /* 1514 | * 1/64th is represented exactly within 1515 | * binary datatype long double 1516 | */ 1517 | if (s < 0.015625L) { 1518 | errx(1, "try an -s greater than or equal to 0.015625 (1/64)"); 1519 | } 1520 | 1521 | if ((dns_cache == 0) && (verbose == 4)) { 1522 | verbose = 3; 1523 | } 1524 | 1525 | if (dns_cache) { 1526 | 1527 | if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 1528 | PF_UNSPEC, dns_cache_d_socket) == -1) { 1529 | err(1, "socketpair, line: %d\n", __LINE__); 1530 | } 1531 | 1532 | dns_cache_d_pid = fork(); 1533 | switch(dns_cache_d_pid) { 1534 | case -1: 1535 | err(1, "dns_cache_d fork, line: %d\n", 1536 | __LINE__); 1537 | case 0: 1538 | (void)close(dns_cache_d_socket[1]); 1539 | dns_cache_d(dns_cache_d_socket[0], 1540 | secure, six, verbose); 1541 | /* function cannot return */ 1542 | default: 1543 | break; 1544 | } 1545 | (void)close(dns_cache_d_socket[0]); 1546 | } 1547 | 1548 | if (to_file) { 1549 | 1550 | if (pipe2(write_pipe, O_CLOEXEC) == -1) { 1551 | err(1, "pipe2, line: %d", __LINE__); 1552 | } 1553 | 1554 | write_pid = fork(); 1555 | switch(write_pid) { 1556 | case -1: 1557 | err(1, "file_d fork, line: %d\n", __LINE__); 1558 | case 0: 1559 | (void)close(dns_cache_d_socket[1]); 1560 | (void)close(write_pipe[STDOUT_FILENO]); 1561 | file_d(write_pipe[STDIN_FILENO], 1562 | secure, debug, verbose); 1563 | /* function cannot return */ 1564 | default: 1565 | break; 1566 | } 1567 | (void)close(write_pipe[STDIN_FILENO]); 1568 | } 1569 | 1570 | 1571 | if (root_user) { 1572 | if (pledge("stdio exec proc id", NULL) == -1) { 1573 | err(1, "pledge, line: %d", __LINE__); 1574 | } 1575 | } else { 1576 | if (pledge("stdio exec proc", NULL) == -1) { 1577 | err(1, "pledge, line: %d", __LINE__); 1578 | } 1579 | } 1580 | 1581 | if (pipe(ftp_out) == -1) { 1582 | err(1, "pipe, line: %d", __LINE__); 1583 | } 1584 | 1585 | ftp_pid = fork(); 1586 | if (ftp_pid == (pid_t) 0) { 1587 | 1588 | if (root_user) { 1589 | /* 1590 | * user _pkgfetch: ftp will regain read pledge 1591 | * just to chroot to /var/empty leaving 1592 | * read access to an empty directory 1593 | */ 1594 | if (seteuid(57)) { 1595 | errx(1, "seteuid error, line: %d", __LINE__); 1596 | } 1597 | } 1598 | 1599 | if (pledge("stdio exec", NULL) == -1) { 1600 | err(1, "pledge, line: %d", __LINE__); 1601 | } 1602 | 1603 | (void)close(ftp_out[STDIN_FILENO]); 1604 | 1605 | n = 1300; 1606 | line = (char*)malloc((size_t)n); 1607 | if (line == NULL) { 1608 | (void)printf("malloc\n"); 1609 | _exit(1); 1610 | } 1611 | 1612 | if (generate) { 1613 | 1614 | i = (int)arc4random_uniform(ftp_list_index_g); 1615 | 1616 | if (ftp_list_g[i][0] == '*') { 1617 | i = snprintf(line, (ulong)n, 1618 | "https://%s/ftplist", 1619 | 1 + ftp_list_g[i]); 1620 | } else { 1621 | i = snprintf(line, (ulong)n, 1622 | "https://%s/pub/OpenBSD/ftplist", 1623 | ftp_list_g[i]); 1624 | } 1625 | 1626 | } else { 1627 | 1628 | i = (int)arc4random_uniform(ftp_list_index); 1629 | 1630 | if (ftp_list[i][0] == '*') { 1631 | i = snprintf(line, (ulong)n, 1632 | "https://%s/ftplist", 1633 | 1 + ftp_list[i]); 1634 | } else { 1635 | i = snprintf(line, (ulong)n, 1636 | "https://%s/pub/OpenBSD/ftplist", 1637 | ftp_list[i]); 1638 | } 1639 | } 1640 | 1641 | if ((i >= n) || (i < 0)) { 1642 | if (i < 0) { 1643 | (void)printf("%s", strerror(errno)); 1644 | } else { 1645 | (void)printf("'line': %s,", line); 1646 | } 1647 | (void)printf(" snprintf, line: %d\n", __LINE__); 1648 | return 1; 1649 | } 1650 | 1651 | if (verbose >= 2) { 1652 | (void)printf("%s\n", line); 1653 | } else if (verbose >= 0) { 1654 | (void)printf("$"); 1655 | (void)fflush(stdout); 1656 | } 1657 | 1658 | 1659 | if (dup2(ftp_out[STDOUT_FILENO], STDOUT_FILENO) == -1) { 1660 | (void)printf("%s ", strerror(errno)); 1661 | (void)printf("ftp STDOUT dup2, line: %d\n", __LINE__); 1662 | _exit(1); 1663 | } 1664 | 1665 | 1666 | if (verbose >= 2) { 1667 | (void)execl("/usr/bin/ftp", "ftp", "-vimo-", 1668 | line, NULL); 1669 | } else { 1670 | (void)execl("/usr/bin/ftp", "ftp", "-ViMo-", 1671 | line, NULL); 1672 | } 1673 | 1674 | 1675 | (void)fprintf(stderr, "%s ", strerror(errno)); 1676 | (void)fprintf(stderr, "ftp 1 (void)execl failed, line: %d\n", 1677 | __LINE__); 1678 | _exit(1); 1679 | } 1680 | if (ftp_pid == -1) { 1681 | err(1, "ftp 1 fork, line: %d", __LINE__); 1682 | } 1683 | 1684 | (void)close(ftp_out[STDOUT_FILENO]); 1685 | 1686 | 1687 | /* Let's do some work while ftp is downloading ftplist */ 1688 | 1689 | 1690 | if (kq == -1) { 1691 | err(1, "kqueue! line: %d", __LINE__); 1692 | } 1693 | 1694 | S = (long double) timeout_ftp_list.tv_sec + 1695 | (long double) timeout_ftp_list.tv_nsec / 1000000000.0L; 1696 | 1697 | if (s > S) { 1698 | timeout_ftp_list.tv_sec = (time_t) s; 1699 | timeout_ftp_list.tv_nsec = 1700 | (long) ( 1701 | ( 1702 | s - (long double)timeout_ftp_list.tv_sec 1703 | ) * 1000000000.0L 1704 | ); 1705 | } 1706 | 1707 | S = s; 1708 | 1709 | // create 'current_time', if it does't exist 1710 | if (current_time == NULL) { 1711 | n = 20; 1712 | current_time = (char*)malloc((size_t)n); 1713 | if (current_time == NULL) { 1714 | easy_ftp_kill(ftp_pid); 1715 | errx(1, "malloc"); 1716 | } 1717 | i = snprintf(current_time, (ulong)n, "%Lf", s); 1718 | if ((i >= n) || (i < 0)) { 1719 | if (i < 0) { 1720 | (void)printf("%s", strerror(errno)); 1721 | } else { 1722 | (void)printf("current_time: %s,", current_time); 1723 | } 1724 | (void)printf(" snprintf, line: %d\n", __LINE__); 1725 | easy_ftp_kill(ftp_pid); 1726 | return 1; 1727 | } 1728 | } else { 1729 | s_set = 1; 1730 | } 1731 | 1732 | /* 1733 | * trim extra zeroes after decimal point in 'current_time' 1734 | */ 1735 | if (strchr(current_time, '.') != NULL) { 1736 | i = 0; 1737 | n = (int)strlen(current_time) - 1; 1738 | while (current_time[n] == '0') { 1739 | i = n; 1740 | --n; 1741 | } 1742 | 1743 | /* if they are all zeroes after '.' then remove '.' */ 1744 | if (current_time[n] == '.') { 1745 | i = n; 1746 | } 1747 | 1748 | if (i) { 1749 | char *time0; 1750 | 1751 | current_time[i] = '\0'; 1752 | time0 = current_time; 1753 | current_time = strdup(time0); 1754 | if (current_time == NULL) { 1755 | easy_ftp_kill(ftp_pid); 1756 | errx(1, "strdup"); 1757 | } 1758 | free(time0); 1759 | } 1760 | } 1761 | 1762 | 1763 | if (previous) { 1764 | if (verbose >= 2) { 1765 | (void)printf("showing the previous "); 1766 | (void)printf("release availability!\n\n"); 1767 | } 1768 | } else if (next) { 1769 | if (verbose >= 2) { 1770 | (void)printf("showing the next "); 1771 | (void)printf("release availability!\n\n"); 1772 | } 1773 | } else if (generate == 0) { 1774 | const int mib[2] = { CTL_KERN, KERN_VERSION }; 1775 | 1776 | /* retrieve length of results of "sysctl kern.version" */ 1777 | if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 1778 | (void)printf("%s ", strerror(errno)); 1779 | (void)printf("sysctl, line: %d", __LINE__); 1780 | easy_ftp_kill(ftp_pid); 1781 | return 1; 1782 | } 1783 | 1784 | line = (char*)malloc(len); 1785 | if (line == NULL) { 1786 | easy_ftp_kill(ftp_pid); 1787 | errx(1, "malloc"); 1788 | } 1789 | 1790 | /* read results of "sysctl kern.version" into 'line' */ 1791 | if (sysctl(mib, 2, line, &len, NULL, 0) == -1) { 1792 | (void)printf("%s ", strerror(errno)); 1793 | (void)printf("sysctl, line: %d", __LINE__); 1794 | easy_ftp_kill(ftp_pid); 1795 | return 1; 1796 | } 1797 | 1798 | /* Discovers if the kernel is not a release version */ 1799 | if (strstr(line, "current") || strstr(line, "beta")) { 1800 | current = 1; 1801 | } 1802 | 1803 | freezero(line, len); 1804 | line = NULL; 1805 | 1806 | if (override) { 1807 | current = !current; 1808 | } 1809 | 1810 | if (verbose >= 2) { 1811 | if (current) { 1812 | (void)printf("showing snapshot mirrors\n\n"); 1813 | } else { 1814 | (void)printf("showing release mirrors\n\n"); 1815 | } 1816 | } 1817 | } 1818 | 1819 | if (generate) { 1820 | 1821 | tag = strdup("/timestamp"); 1822 | if (tag == NULL) { 1823 | easy_ftp_kill(ftp_pid); 1824 | errx(1, "strdup"); 1825 | } 1826 | 1827 | tag_len = strlen(tag); 1828 | 1829 | } else { 1830 | 1831 | struct utsname name; 1832 | size_t s_temp = 0; 1833 | 1834 | if (uname(&name) == -1) { 1835 | (void)printf("%s ", strerror(errno)); 1836 | (void)printf("uname, line: %d", __LINE__); 1837 | easy_ftp_kill(ftp_pid); 1838 | return 1; 1839 | } 1840 | 1841 | if (next && !strcmp(name.release, "9.9")) { 1842 | release = strdup("10.0"); 1843 | i = 0; 1844 | } else if (previous && !strcmp(name.release, "10.0")) { 1845 | release = strdup("9.9"); 1846 | i = 0; 1847 | } else { 1848 | release = strdup(name.release); 1849 | i = 1; 1850 | } 1851 | 1852 | if (release == NULL) { 1853 | easy_ftp_kill(ftp_pid); 1854 | errx(1, "strdup"); 1855 | } 1856 | 1857 | if (i && (next || previous)) { 1858 | 1859 | long double f_temp; 1860 | n = (int)strlen(release) + 1; 1861 | 1862 | if (n == (3 + 1)) 1863 | { 1864 | if ( 1865 | ((release[0] < '0') || 1866 | (release[0] > '9')) 1867 | || 1868 | (release[1] != '.') 1869 | || 1870 | ((release[2] < '0') || 1871 | (release[2] > '9')) 1872 | ) { 1873 | errx(1, "%s%s%d", 1874 | "release is somehow ", 1875 | "a bad format, line: ", 1876 | __LINE__); 1877 | } 1878 | // eg. 7.5 1879 | f_temp = (release[0] - '0') 1880 | + ((release[2] - '0') / 10.0L); 1881 | 1882 | } else if (n == (4 + 1)) { 1883 | 1884 | if ( 1885 | ( 1886 | (release[0] < '0') || 1887 | (release[0] > '9') 1888 | ) 1889 | || 1890 | ( 1891 | (release[1] < '0') || 1892 | (release[1] > '9') 1893 | ) 1894 | || 1895 | (release[2] != '.') 1896 | || 1897 | ( 1898 | (release[3] < '0') || 1899 | (release[3] > '9') 1900 | ) 1901 | ) { 1902 | errx(1, "%s%s%d", 1903 | "release is somehow ", 1904 | "a bad format, line: ", 1905 | __LINE__); 1906 | } 1907 | // eg. 10.0 1908 | f_temp = ((release[0] - '0') * 10.0L) + 1909 | (long double) (release[1] - '0') + 1910 | ((release[3] - '0') / 10.0L); 1911 | 1912 | } else { 1913 | errx(1, "release got huge! line: %d", __LINE__); 1914 | } 1915 | 1916 | if (previous) { 1917 | f_temp -= 0.1L; 1918 | } else /* if (next) */ { 1919 | f_temp += 0.1L; 1920 | } 1921 | 1922 | i = snprintf(release, (ulong)n, "%.1Lf", f_temp); 1923 | 1924 | if ((i >= n) || (i < 0)) { 1925 | if (i < 0) { 1926 | (void)printf("%s", strerror(errno)); 1927 | } else { 1928 | (void)printf("release: %s,", release); 1929 | } 1930 | (void)printf(" snprintf, line: %d\n", __LINE__); 1931 | easy_ftp_kill(ftp_pid); 1932 | return 1; 1933 | } 1934 | } 1935 | 1936 | if (current) { 1937 | tag_len = strlen("/snapshots/") + 1938 | strlen(name.machine) + strlen("/SHA256"); 1939 | 1940 | tag = (char*)malloc(tag_len + 1); 1941 | if (tag == NULL) { 1942 | easy_ftp_kill(ftp_pid); 1943 | errx(1, "malloc"); 1944 | } 1945 | 1946 | i = snprintf(tag, tag_len + 1, 1947 | "/snapshots/%s/SHA256", name.machine); 1948 | } else { 1949 | tag_len = strlen("/") + strlen(release) + 1950 | strlen("/") + strlen(name.machine) + 1951 | strlen("/SHA256"); 1952 | 1953 | tag = (char*)malloc(tag_len + 1); 1954 | if (tag == NULL) { 1955 | easy_ftp_kill(ftp_pid); 1956 | errx(1, "malloc"); 1957 | } 1958 | 1959 | i = snprintf(tag, tag_len + 1, 1960 | "/%s/%s/SHA256", release, name.machine); 1961 | } 1962 | 1963 | explicit_bzero(&name, sizeof(struct utsname)); 1964 | 1965 | s_temp = (size_t)i; 1966 | 1967 | if ((s_temp >= (tag_len + 1)) || (i < 0)) { 1968 | if (i < 0) { 1969 | (void)printf("%s", strerror(errno)); 1970 | } else { 1971 | (void)printf("tag: %s,", tag); 1972 | } 1973 | (void)printf(" snprintf, line: %d\n", __LINE__); 1974 | easy_ftp_kill(ftp_pid); 1975 | return 1; 1976 | } 1977 | } 1978 | 1979 | 1980 | /* if the index for line[] can exceed 1254, it will error out */ 1981 | line = (char*)calloc(dns_socket_len - 1, sizeof(char)); 1982 | if (line == NULL) { 1983 | easy_ftp_kill(ftp_pid); 1984 | errx(1, "calloc"); 1985 | } 1986 | 1987 | array = (MIRROR*)calloc((size_t)array_max, sizeof(MIRROR)); 1988 | if (array == NULL) { 1989 | easy_ftp_kill(ftp_pid); 1990 | errx(1, "calloc"); 1991 | } 1992 | 1993 | (void)atexit(free_array); 1994 | 1995 | z = ftp_out[STDIN_FILENO]; 1996 | 1997 | /* 1998 | * I use kevent here, just so I can restart 1999 | * the program again if ftp is sluggish 2000 | */ 2001 | EV_SET(&ke, z, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL); 2002 | i = kevent(kq, &ke, 1, &ke, 1, &timeout_ftp_list); 2003 | 2004 | if (i == -1) { 2005 | if ( (verbose == 0) || (verbose == 1) ) { 2006 | (void)printf("\b \b%s ", strerror(errno)); 2007 | (void)fflush(stdout); 2008 | } else { 2009 | (void)printf("%s ", strerror(errno)); 2010 | } 2011 | 2012 | (void)printf("kevent, timeout_ftp_list may be too large. "); 2013 | (void)printf("line: %d\n", __LINE__); 2014 | easy_ftp_kill(ftp_pid); 2015 | return 1; 2016 | } 2017 | 2018 | if ( (verbose == 0) || (verbose == 1) ) { 2019 | (void)printf("\b \b"); 2020 | (void)fflush(stdout); 2021 | } 2022 | 2023 | if (i != 1) { 2024 | 2025 | easy_ftp_kill(ftp_pid); 2026 | 2027 | (void)close(z); 2028 | 2029 | if (dns_cache) { 2030 | (void)close(dns_cache_d_socket[1]); 2031 | (void)waitpid(dns_cache_d_pid, NULL, 0); 2032 | } 2033 | if (to_file) { 2034 | (void)close(write_pipe[STDOUT_FILENO]); 2035 | (void)waitpid(write_pid, NULL, 0); 2036 | } 2037 | restart(argc, argv, loop, verbose); 2038 | } 2039 | 2040 | 2041 | 2042 | if (debug) { 2043 | (void)clock_gettime(CLOCK_REALTIME, &startD); 2044 | } 2045 | 2046 | while (read(z, &v, 1) == 1) { 2047 | if (pos >= (int)(dns_socket_len - 2)) { 2048 | line[pos] = '\0'; 2049 | (void)printf("'line': %s\n", line); 2050 | (void)printf("pos got too big! line: %d\n", __LINE__); 2051 | easy_ftp_kill(ftp_pid); 2052 | return 1; 2053 | } 2054 | 2055 | if (num == 0) { 2056 | 2057 | if (v != ' ') { 2058 | line[pos] = v; 2059 | ++pos; 2060 | continue; 2061 | } 2062 | line[pos] = '\0'; 2063 | ++pos; 2064 | 2065 | /* safety check */ 2066 | if (strncmp(line, "http://", 7)) { 2067 | (void)printf("'line': %s\n", line); 2068 | (void)printf("bad http format, line: %d\n", 2069 | __LINE__); 2070 | easy_ftp_kill(ftp_pid); 2071 | return 1; 2072 | } 2073 | 2074 | if (secure) { 2075 | 2076 | ++pos; 2077 | if (pos_max < pos) { 2078 | pos_max = pos; 2079 | } 2080 | 2081 | array[array_length].http = 2082 | (char*)malloc((size_t)pos); 2083 | 2084 | if (array[array_length].http == NULL) { 2085 | easy_ftp_kill(ftp_pid); 2086 | errx(1, "malloc"); 2087 | } 2088 | 2089 | (void)memcpy(array[array_length].http, 2090 | "https", 5); 2091 | 2092 | /* strlen("http") == 4 */ 2093 | (void)memcpy(5 + array[array_length].http, 2094 | 4 + line, 2095 | (ulong)pos - 5); 2096 | 2097 | } else { 2098 | 2099 | if (pos_max < pos) { 2100 | pos_max = pos; 2101 | } 2102 | 2103 | array[array_length].http = strdup(line); 2104 | 2105 | if (array[array_length].http == NULL) { 2106 | easy_ftp_kill(ftp_pid); 2107 | errx(1, "strdup"); 2108 | } 2109 | } 2110 | 2111 | pos = 0; 2112 | num = 1; 2113 | continue; 2114 | } 2115 | 2116 | if ((pos == 0) && (v == ' ')) { 2117 | continue; 2118 | } 2119 | 2120 | if (v != '\n') { 2121 | line[pos] = v; 2122 | ++pos; 2123 | continue; 2124 | } 2125 | 2126 | 2127 | /* 2128 | * wipes out spaces at the end of the label 2129 | */ 2130 | while ((pos > 0) && (line[pos - 1] == ' ')) { 2131 | --pos; 2132 | } 2133 | 2134 | line[pos] = '\0'; 2135 | ++pos; 2136 | 2137 | if ((usa == 0) && strstr(line, "USA")) { 2138 | free(array[array_length].http); 2139 | num = 0; 2140 | pos = 0; 2141 | continue; 2142 | } 2143 | 2144 | if ((USA == 1) && 2145 | 2146 | ( 2147 | (strstr(line, "USA" ) == NULL) && 2148 | (strstr(line, "CDN" ) == NULL) && 2149 | (strstr(line, "Canada") == NULL) 2150 | ) 2151 | 2152 | ) { 2153 | free(array[array_length].http); 2154 | num = 0; 2155 | pos = 0; 2156 | continue; 2157 | } 2158 | 2159 | /* 2160 | * I decided to be aggressive and deduplicate and wipe out 2161 | * spaces after each comma and rewrite them to have one. 2162 | * This more cleanly enforces with memmove()s 2163 | * what I want without ever hard-failing on tests for 2164 | * label_cmp_minus_usa() and without 2165 | * pointer arithmetic which may be error-prone. 2166 | */ 2167 | 2168 | /* 2169 | * rewrites 'line' (label) to not have double spaces. 2170 | * Will likely never succeed. 2171 | */ 2172 | while ((line_temp = strstr(line, " ")) != NULL) { 2173 | (void)memmove(line_temp + 1, 2174 | line_temp + 2, 2175 | (size_t)((line + pos) - (line_temp + 2))); 2176 | --pos; 2177 | } 2178 | 2179 | /* 2180 | * rewrites 'line' (label) to have NO space after every comma 2181 | * when it most likely does. 2182 | * Everything indicates this trend will continue. 2183 | * This will clear them. 2184 | */ 2185 | while ((line_temp = strstr(line, ", ")) != NULL) { 2186 | (void)memmove(line_temp + 1, 2187 | line_temp + 2, 2188 | (size_t)((line + pos) - (line_temp + 2))); 2189 | --pos; 2190 | } 2191 | 2192 | /* 2193 | * rewrites 'line' (label) to have space after every comma 2194 | * which was most likely cleared, but we don't want a user 2195 | * error in writing the label to disable the software. 2196 | */ 2197 | line_temp = strchr(line, ','); 2198 | while (line_temp && pos < (int)(dns_socket_len - 2)) { 2199 | /* 2200 | * make room for a space 2201 | */ 2202 | (void)memmove(line_temp + 2, 2203 | line_temp + 1, 2204 | (size_t)((line + pos) - (line_temp + 1))); 2205 | ++pos; 2206 | line_temp[1] = ' '; 2207 | line_temp = strchr(line_temp + 2, ','); 2208 | } 2209 | 2210 | if (pos >= (int)(dns_socket_len - 2)) { 2211 | errx(1, "too many unladen commas. line %d", __LINE__); 2212 | } 2213 | 2214 | /* 2215 | * Not a fan of "The " in "The Netherlands" in here 2216 | * I think it sticks out when it's sorted. 2217 | * 2218 | * If the label has a "The " after the last ", " 2219 | * or if it has no comma and starts with "The ", 2220 | * this will surgically remove it. 2221 | */ 2222 | line_temp = strrchr(line, ','); 2223 | if (line_temp) { 2224 | if (!strncmp(line_temp + 2, "The ", 4)) { 2225 | (void)memmove(line_temp + 2, 2226 | line_temp + 6, 2227 | (size_t) 2228 | ((line + pos) - (line_temp + 6)) 2229 | ); 2230 | } 2231 | } else if (!strncmp(line, "The ", 4)) { 2232 | (void)memmove(line, line + 4, 2233 | (size_t)pos - 4 2234 | ); 2235 | } 2236 | 2237 | array[array_length].label = strdup(line); 2238 | if (array[array_length].label == NULL) { 2239 | free(array[array_length].http); 2240 | easy_ftp_kill(ftp_pid); 2241 | errx(1, "strdup"); 2242 | } 2243 | 2244 | ++array_length; 2245 | 2246 | if (array_length >= array_max) { 2247 | 2248 | MIRROR *array_temp = array; 2249 | 2250 | array_max += 100; 2251 | 2252 | if (array_max >= 5000) { 2253 | easy_ftp_kill(ftp_pid); 2254 | errx(1, "array_max got insanely large"); 2255 | } 2256 | 2257 | array = recallocarray(array_temp, 2258 | (size_t)array_length, 2259 | (size_t)array_max, 2260 | sizeof(MIRROR)); 2261 | 2262 | if (array == NULL) { 2263 | free(array_temp); 2264 | easy_ftp_kill(ftp_pid); 2265 | errx(1, "recallocarray"); 2266 | } 2267 | } 2268 | 2269 | pos = 0; 2270 | num = 0; 2271 | } 2272 | 2273 | (void)close(z); 2274 | 2275 | (void)waitpid(ftp_pid, &z, 0); 2276 | 2277 | /* 2278 | * 'ftplist' download error: 2279 | * It's caused by no internet, bad dns resolution; 2280 | * Or from a faulty mirror or its bad dns info 2281 | */ 2282 | if (z || (array_length == 0)) { 2283 | 2284 | if (verbose >= 0) { 2285 | (void)printf("There was an 'ftplist' "); 2286 | (void)printf("download problem.\n"); 2287 | } 2288 | 2289 | if (dns_cache) { 2290 | (void)close(dns_cache_d_socket[1]); 2291 | (void)waitpid(dns_cache_d_pid, NULL, 0); 2292 | } 2293 | if (to_file) { 2294 | (void)close(write_pipe[STDOUT_FILENO]); 2295 | (void)waitpid(write_pid, NULL, 0); 2296 | } 2297 | restart(argc, argv, loop, verbose); 2298 | } 2299 | 2300 | /* if "secure", h = strlen("https://") instead of strlen("http://") */ 2301 | h += secure; 2302 | 2303 | pos_max += tag_len; 2304 | 2305 | if (pos_max > (int)sizeof(line)) { 2306 | free(line); 2307 | line = (char*)calloc((size_t)pos_max, sizeof(char)); 2308 | if (line == NULL) { 2309 | errx(1, "calloc"); 2310 | } 2311 | } 2312 | 2313 | /* 2314 | * if verbose > 1, make mirrors near USA first, then subsort by label. 2315 | * otherwise, make mirrors near USA first, then don't care. 2316 | * 2317 | * Searching through mirrors near USA on verbose < 1 is more likely 2318 | * to find the faster mirrors to shrink 'timeout' earlier to make the 2319 | * runtime as short as possible. 2320 | */ 2321 | if (usa == 0) { 2322 | if (verbose > 1) { 2323 | sort_ret = heapsort(array, (ulong)array_length, 2324 | sizeof(MIRROR), label_cmp_minus_usa); 2325 | } else { 2326 | /* else don't sort */ 2327 | sort_ret = 0; 2328 | } 2329 | } else { 2330 | if (verbose > 1) { 2331 | sort_ret = heapsort(array, (ulong)array_length, 2332 | sizeof(MIRROR), label_cmp); 2333 | } else if (verbose < 1) { 2334 | sort_ret = heapsort(array, (ulong)array_length, 2335 | sizeof(MIRROR), usa_cmp); 2336 | } else { 2337 | /* else don't sort */ 2338 | sort_ret = 0; 2339 | } 2340 | } 2341 | 2342 | if (sort_ret) 2343 | err(1, "sort failed, line %d", __LINE__); 2344 | 2345 | if (six) { 2346 | if (verbose >= 3) { 2347 | line0 = strdup("-vim6o-"); 2348 | } else { 2349 | line0 = strdup("-viM6o-"); 2350 | } 2351 | } else { 2352 | if (verbose >= 3) { 2353 | line0 = strdup("-vimo-"); 2354 | } else { 2355 | line0 = strdup("-viMo-"); 2356 | } 2357 | } 2358 | if (line0 == NULL) { 2359 | errx(1, "strdup"); 2360 | } 2361 | 2362 | timeout.tv_sec = (time_t) s; 2363 | timeout.tv_nsec = 2364 | (long) ((s - 2365 | (long double) timeout.tv_sec) * 1000000000.0L); 2366 | 2367 | std_err = dup(STDERR_FILENO); 2368 | if (std_err == -1) { 2369 | err(1, "dup, line: %d\n", __LINE__); 2370 | } 2371 | 2372 | if (fcntl(std_err, F_SETFD, FD_CLOEXEC) == -1) { 2373 | err(1, "fcntl, line: %d\n", __LINE__); 2374 | } 2375 | 2376 | /* 2377 | pos_maxl = 0; 2378 | pos_maxh = 0; 2379 | pos_maxb = 0; 2380 | pos1 = 0; 2381 | 2382 | num1 = 0; 2383 | num2 = 0; 2384 | num3 = 0; 2385 | */ 2386 | 2387 | /* calculations for preventing ugly line wraps in realtime output */ 2388 | if (verbose >= 2) { 2389 | 2390 | ac = array + array_length; 2391 | i = (array_length >= 100) + 10; 2392 | 2393 | while (array < ac) { 2394 | --ac; 2395 | pos = (int)strlen(ac->label); 2396 | if (pos > pos_maxl) { 2397 | pos_maxl = pos; 2398 | } 2399 | 2400 | host = ac->http + h; 2401 | cut = strchr(host, '/'); 2402 | if (cut == NULL) { 2403 | pos1 = (int)strlen(host); 2404 | } else { 2405 | pos1 = (int)(cut - host); 2406 | } 2407 | 2408 | if (pos1 > pos_maxh) { 2409 | pos_maxh = pos1; 2410 | } 2411 | 2412 | pos += pos1; 2413 | 2414 | if (pos > pos_maxb) { 2415 | pos_maxb = pos; 2416 | } 2417 | } 2418 | 2419 | num1 = ((w.ws_col - i) >= (pos_maxl + pos_max)); 2420 | num2 = ((w.ws_col - i) >= (pos_maxl + pos_maxh)); 2421 | num3 = ((w.ws_col - i) >= pos_maxb); 2422 | } 2423 | 2424 | 2425 | host = h + line; 2426 | 2427 | (void)memcpy(line, array[0].http, (ulong)h); 2428 | 2429 | pos_max -= h; 2430 | 2431 | // if (all) skip 2432 | for (c = (all) ? (int)array_length : 0; c < (int)array_length; ++c) { 2433 | 2434 | n = (int)strlcpy(host, array[c].http + h, (ulong)pos_max); 2435 | (void)memcpy(host + n, tag, (ulong)tag_len + 1); 2436 | 2437 | 2438 | /* strchr always succeeds. 'tag' starts with '/' */ 2439 | cut = strchr(host, '/'); 2440 | 2441 | if (verbose >= 2) { 2442 | if (verbose == 4) { 2443 | (void)printf("\n\n\n\n"); 2444 | } else if (verbose == 3) { 2445 | (void)printf("\n\n"); 2446 | } else { 2447 | (void)printf("\n"); 2448 | } 2449 | 2450 | if (array_length >= 100) { 2451 | (void)printf("%3d : ", (int)array_length - c); 2452 | } else { 2453 | (void)printf("%2d : ", (int)array_length - c); 2454 | } 2455 | 2456 | if (num2) { 2457 | 2458 | i = (int)strlen(array[c].label); 2459 | j = ((int)pos_maxl + 1 - i) / 2; 2460 | n = (int)pos_maxl - (i + j); 2461 | 2462 | for (; j > 0; --j) { 2463 | (void)printf(" "); 2464 | } 2465 | 2466 | (void)printf("%s", array[c].label); 2467 | 2468 | for (; n > 0; --n) { 2469 | (void)printf(" "); 2470 | } 2471 | 2472 | if (num1) { 2473 | (void)printf(" : %s\n", line); 2474 | } else { 2475 | *cut = '\0'; 2476 | (void)printf(" : %s\n", host); 2477 | *cut = '/'; 2478 | } 2479 | 2480 | } else if (num3) { 2481 | *cut = '\0'; 2482 | (void)printf("%s : ", array[c].label); 2483 | (void)printf("%s\n", host); 2484 | *cut = '/'; 2485 | } else { 2486 | (void)printf("%s\n", array[c].label); 2487 | } 2488 | 2489 | } else if ((verbose >= 0)) { 2490 | i = (int)array_length - c; 2491 | if (c) { 2492 | if ( (i == 9) || (i == 99) ) { 2493 | (void)printf("\b \b"); 2494 | } 2495 | n = i; 2496 | do { 2497 | (void)printf("\b"); 2498 | n /= 10; 2499 | } while (n); 2500 | } 2501 | (void)printf("%d", i); 2502 | (void)fflush(stdout); 2503 | } 2504 | 2505 | 2506 | 2507 | n = (int)(cut - host); 2508 | 2509 | if (dns_cache) { 2510 | 2511 | /* 2 minutes for dns_cache_d to respond */ 2512 | const struct timespec timeout_d = { 120, 0 }; 2513 | 2514 | 2515 | i = (int)write(dns_cache_d_socket[1], host, (size_t)n); 2516 | if (i < n) { 2517 | goto restart_dns_err; 2518 | } 2519 | 2520 | if ((verbose >= 0) && (verbose <= 3)) { 2521 | (void)printf("*"); 2522 | (void)fflush(stdout); 2523 | } 2524 | 2525 | 2526 | 2527 | /* 2528 | * I use kevent here, just so I can restart 2529 | * the program again if DNS daemon is stuck 2530 | */ 2531 | EV_SET(&ke, dns_cache_d_socket[1], EVFILT_READ, 2532 | EV_ADD | EV_ONESHOT, 0, 0, NULL); 2533 | i = kevent(kq, &ke, 1, &ke, 1, &timeout_d); 2534 | 2535 | if ((verbose >= 0) && (verbose <= 3)) { 2536 | (void)printf("\b \b"); 2537 | (void)fflush(stdout); 2538 | } 2539 | 2540 | if (i == -1) { 2541 | (void)printf("%s ", strerror(errno)); 2542 | (void)printf("kevent, timeout_d may "); 2543 | (void)printf("be too large. "); 2544 | (void)printf("line: %d\n", __LINE__); 2545 | return 1; 2546 | } 2547 | 2548 | if (i != 1) { 2549 | 2550 | (void)kill(dns_cache_d_pid, SIGKILL); 2551 | goto restart_dns_err; 2552 | } 2553 | 2554 | 2555 | i = (int)read(dns_cache_d_socket[1], &v, 1); 2556 | 2557 | if (i != 1) { 2558 | 2559 | restart_dns_err: 2560 | 2561 | if (verbose >= 2) { 2562 | (void)printf("dns_cache "); 2563 | (void)printf("process issues\n\n"); 2564 | } 2565 | else if (verbose >= 0) { 2566 | n = (int)array_length - c; 2567 | do { 2568 | (void)printf("\b \b"); 2569 | n /= 10; 2570 | } while (n); 2571 | } 2572 | 2573 | (void)close(dns_cache_d_socket[1]); 2574 | (void)waitpid(dns_cache_d_pid, NULL, 0); 2575 | 2576 | if (to_file) { 2577 | (void)close(write_pipe[STDOUT_FILENO]); 2578 | (void)waitpid(write_pid, NULL, 0); 2579 | } 2580 | 2581 | restart(argc, argv, loop, verbose); 2582 | } 2583 | 2584 | if (six && (v == '0')) { 2585 | if (verbose >= 2) { 2586 | (void)printf("IPv6 DNS record "); 2587 | (void)printf("not found.\n"); 2588 | } 2589 | array[c].diff = s + 2; 2590 | continue; 2591 | } else if (v == 'f') { 2592 | if (verbose >= 2) { 2593 | (void)printf("DNS record not found.\n"); 2594 | } 2595 | array[c].diff = s + 3; 2596 | continue; 2597 | } else if (v == 'u') { 2598 | //~ if (generate) { 2599 | //~ if (verbose >= 2) { 2600 | //~ (void)printf("BLOCKED "); 2601 | //~ (void)printf("subdomain "); 2602 | //~ (void)printf("passes!\n"); 2603 | //~ } 2604 | //~ array[c].diff = s / 2.0L; 2605 | //~ } else { 2606 | if (verbose >= 2) { 2607 | (void)printf("BLOCKED "); 2608 | (void)printf("subdomain!\n"); 2609 | } 2610 | array[c].diff = s + 4.0L; 2611 | //~ } 2612 | continue; 2613 | } 2614 | } 2615 | 2616 | 2617 | if (socketpair(AF_UNIX, SOCK_STREAM, 2618 | PF_UNSPEC, block_socket) == -1) { 2619 | err(1, "socketpair"); 2620 | } 2621 | 2622 | if (pipe(ftp_helper_out) == -1) { 2623 | err(1, "pipe, line: %d", __LINE__); 2624 | } 2625 | 2626 | ftp_pid = fork(); 2627 | if (ftp_pid == (pid_t) 0) { 2628 | 2629 | int ftp_2_ftp_helper[2] = { -1, -1 }; 2630 | 2631 | pid_t ftp_helper_pid = -1; 2632 | 2633 | (void)close(kq); 2634 | 2635 | if (socketpair(AF_UNIX, SOCK_STREAM, 2636 | PF_UNSPEC, ftp_2_ftp_helper) == -1) { 2637 | err(1, "socketpair"); 2638 | } 2639 | 2640 | ftp_helper_pid = fork(); 2641 | if (ftp_helper_pid == (pid_t) 0) { 2642 | 2643 | int ret = 1; 2644 | 2645 | if (pledge("stdio", NULL) == -1) { 2646 | err(1, "pledge, line: %d", __LINE__); 2647 | } 2648 | 2649 | (void)close(block_socket[STDIN_FILENO]); 2650 | (void)close(block_socket[STDOUT_FILENO]); 2651 | 2652 | (void)close(ftp_2_ftp_helper[STDOUT_FILENO]); 2653 | (void)close(ftp_helper_out[STDIN_FILENO]); 2654 | 2655 | free(line); 2656 | 2657 | n = 100; 2658 | line = (char*)calloc((size_t)n, sizeof(char)); 2659 | if (line == NULL) { 2660 | (void)printf("calloc\n"); 2661 | _exit(1); 2662 | } 2663 | 2664 | num = 0; 2665 | pos = 0; 2666 | 2667 | z = ftp_2_ftp_helper[STDIN_FILENO]; 2668 | if (write(z, &v, 1) != 1) { 2669 | errx(1, "write error, line: %d", 2670 | __LINE__); 2671 | } 2672 | 2673 | while (read(z, &v, 1) == 1) { 2674 | char *g = NULL; 2675 | long double t = 0.0L; 2676 | char *endptr = NULL; 2677 | 2678 | if ((int)pos >= (n - 2)) { 2679 | line[pos] = '\0'; 2680 | (void)printf("'line': "); 2681 | (void)printf("%s\n", line); 2682 | (void)printf("pos got too big"); 2683 | (void)printf("! line: %d\n", 2684 | __LINE__); 2685 | _exit(1); 2686 | } 2687 | 2688 | if (verbose >= 2) { 2689 | (void)printf("%c", v); 2690 | (void)fflush(stdout); 2691 | } 2692 | 2693 | if (num == 0) { 2694 | if (v != '(') { 2695 | continue; 2696 | } 2697 | num = 1; 2698 | continue; 2699 | } 2700 | 2701 | if (v != ')') { 2702 | line[pos] = v; 2703 | ++pos; 2704 | continue; 2705 | } 2706 | 2707 | line[pos] = '\0'; 2708 | 2709 | /* 2710 | * excerpt of ptransfer() in 2711 | * /usr/src/usr.bin/ftp/util.c 2712 | * 2713 | * meg = 0; 2714 | * if (bs > (1024 * 1024)) 2715 | * meg = 1; 2716 | * 2717 | * pace = bs / (1024.0 * (meg ? 1024.0 : 1.0)); 2718 | * (void)snprintf(buf, sizeof(buf), 2719 | * "%lld byte%s %s in %lld.%02d seconds (%lld.%02d %sB/s)\n", 2720 | * (long long)bytes, bytes == 1 ? "" : "s", direction, 2721 | * (long long)elapsed, (int)(elapsed * 100.0) % 100, 2722 | * (long long)pace, (int)(pace * 100.0) % 100, 2723 | * meg ? "M" : "K"); 2724 | */ 2725 | g = strchr(line, ' '); 2726 | if (g == NULL) { 2727 | break; 2728 | } 2729 | 2730 | *g = '\0'; 2731 | 2732 | errno = 0; 2733 | t = strtold(line, &endptr); 2734 | if (errno || t <= 0 || (endptr != g)) { 2735 | if (endptr != g) { 2736 | (void)printf("endptr"); 2737 | (void)printf(" != g\n"); 2738 | } 2739 | break; 2740 | } 2741 | 2742 | ++g; 2743 | if (*g == 'M') { 2744 | t *= 1024.0L * 1024.0L; 2745 | } else if (*g == 'K') { 2746 | t *= 1024.0L; 2747 | } else { 2748 | (void)printf("bad read, line"); 2749 | (void)printf(" %d\n", __LINE__); 2750 | break; 2751 | } 2752 | 2753 | i = (int)write( 2754 | ftp_helper_out[STDOUT_FILENO], 2755 | &t, sizeof(long double)); 2756 | 2757 | if (i != (int)sizeof(long double)) { 2758 | (void)printf("bad write, line"); 2759 | (void)printf(" %d", __LINE__); 2760 | break; 2761 | } 2762 | 2763 | if (verbose >= 2) 2764 | { 2765 | while (read(z, &v, 1) == 1) { 2766 | (void)printf("%c", v); 2767 | (void)fflush(stdout); 2768 | } 2769 | } 2770 | ret = 0; 2771 | break; 2772 | } 2773 | (void)close(ftp_helper_out[STDOUT_FILENO]); 2774 | (void)close(ftp_2_ftp_helper[STDIN_FILENO]); 2775 | free(line); 2776 | line = NULL; 2777 | _exit(ret); 2778 | } 2779 | if (ftp_helper_pid == -1) { 2780 | err(1, "ftp 1 fork, line: %d", __LINE__); 2781 | } 2782 | 2783 | (void)close(ftp_2_ftp_helper[STDIN_FILENO]); 2784 | (void)close(ftp_helper_out[STDIN_FILENO]); 2785 | (void)close(ftp_helper_out[STDOUT_FILENO]); 2786 | 2787 | 2788 | if (root_user) { 2789 | /* 2790 | * user _pkgfetch: ftp will regain read pledge 2791 | * just to chroot to /var/empty leaving 2792 | * read access to an empty directory 2793 | */ 2794 | if (seteuid(57)) 2795 | { 2796 | errx(1, "seteuid error, line: %d", 2797 | __LINE__); 2798 | } 2799 | } 2800 | 2801 | 2802 | if (read(ftp_2_ftp_helper[STDOUT_FILENO], &v, 1) != 1) { 2803 | errx(1, "read error, line: %d", __LINE__); 2804 | } 2805 | 2806 | if (dup2(ftp_2_ftp_helper[STDOUT_FILENO], 2807 | STDERR_FILENO) == -1) { 2808 | (void)printf("%s ", strerror(errno)); 2809 | (void)printf("ftp STDERR dup2,"); 2810 | (void)printf(" line: %d\n", __LINE__); 2811 | _exit(1); 2812 | } 2813 | 2814 | (void)close(STDOUT_FILENO); 2815 | 2816 | 2817 | 2818 | 2819 | (void)close(block_socket[STDOUT_FILENO]); 2820 | /* 2821 | * the read() for this write() is to ensure 2822 | * that the process is alive for 2823 | * the parent kevent call. 2824 | * It standardizes the timing of the ftp calling 2825 | * process, and it is written as an efficient way 2826 | * to signal the process to resume without ugly code. 2827 | */ 2828 | 2829 | if (write(block_socket[STDIN_FILENO], &v, 1) != 1) { 2830 | errx(1, "write error, line: %d", __LINE__); 2831 | } 2832 | 2833 | // intended to short-circuit 2834 | (void)read(block_socket[STDIN_FILENO], &v, 1); 2835 | (void)close(block_socket[STDIN_FILENO]); 2836 | 2837 | if (debug || all) { 2838 | _exit(0); 2839 | } 2840 | 2841 | 2842 | 2843 | (void)execl("/usr/bin/ftp", "ftp", line0, line, NULL); 2844 | 2845 | /* I nullified stdout, so printf won't work */ 2846 | (void)dprintf(std_err, "%s ", strerror(errno)); 2847 | (void)dprintf(std_err, "ftp 2 (void)execl() failed, "); 2848 | (void)dprintf(std_err, "line: %d\n", __LINE__); 2849 | _exit(1); 2850 | } 2851 | if (ftp_pid == -1) { 2852 | err(1, "ftp 2 fork, line: %d", __LINE__); 2853 | } 2854 | 2855 | 2856 | (void)close(ftp_helper_out[STDOUT_FILENO]); 2857 | 2858 | (void)close(block_socket[STDIN_FILENO]); 2859 | 2860 | EV_SET(&ke, ftp_pid, EVFILT_PROC, EV_ADD | 2861 | EV_ONESHOT, NOTE_EXIT, 0, NULL); 2862 | if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) { 2863 | (void)printf("%s ", strerror(errno)); 2864 | (void)printf("kevent register fail,"); 2865 | (void)printf(" line: %d\n", __LINE__); 2866 | easy_ftp_kill(ftp_pid); 2867 | return 1; 2868 | } 2869 | 2870 | 2871 | if (read(block_socket[STDOUT_FILENO], &v, 1) != 1) { 2872 | errx(1, "read error, line: %d", __LINE__); 2873 | } 2874 | (void)close(block_socket[STDOUT_FILENO]); 2875 | 2876 | (void)clock_gettime(CLOCK_REALTIME, &start); 2877 | i = kevent(kq, NULL, 0, &ke, 1, &timeout); 2878 | (void)clock_gettime(CLOCK_REALTIME, &end); 2879 | 2880 | if (i == -1) { 2881 | (void)printf("%s ", strerror(errno)); 2882 | (void)printf("kevent, line: %d", __LINE__); 2883 | easy_ftp_kill(ftp_pid); 2884 | return 1; 2885 | } 2886 | 2887 | /* timeout occurred before ftp() exit was received */ 2888 | if (i == 0) { 2889 | 2890 | (void)kill(ftp_pid, SIGINT); 2891 | 2892 | /* 2893 | * give it time to gracefully abort, play 2894 | * nice with the server and reap event 2895 | */ 2896 | i = kevent(kq, NULL, 0, &ke, 1, &timeout_kill); 2897 | if (i == -1) { 2898 | err(1, "kevent, line: %d", __LINE__); 2899 | } 2900 | 2901 | if (i == 0) { 2902 | 2903 | (void)kill(ftp_pid, SIGKILL); 2904 | if (verbose >= 2) { 2905 | (void)printf("killed\n"); 2906 | } 2907 | if (kevent(kq, NULL, 0, &ke, 1, NULL) == -1) { 2908 | err(1, "kevent, line: %d", __LINE__); 2909 | } 2910 | } 2911 | 2912 | (void)waitpid(ftp_pid, NULL, 0); 2913 | (void)close(ftp_helper_out[STDIN_FILENO]); 2914 | 2915 | if (verbose >= 2) { 2916 | (void)printf("Timeout\n"); 2917 | } 2918 | array[c].diff = s; 2919 | continue; 2920 | } 2921 | (void)waitpid(ftp_pid, &z, 0); 2922 | 2923 | if (z) { 2924 | array[c].diff = s + 1; 2925 | if (verbose >= 2) { 2926 | (void)printf("Download Error\n"); 2927 | } 2928 | 2929 | (void)close(ftp_helper_out[STDIN_FILENO]); 2930 | continue; 2931 | } 2932 | 2933 | if (!debug && !all) { 2934 | z = ftp_helper_out[STDIN_FILENO]; 2935 | if (read(z, &array[c].speed, sizeof(long double)) 2936 | < (ssize_t)sizeof(long double)) { 2937 | restart(argc, argv, loop, verbose); 2938 | } 2939 | } 2940 | 2941 | (void)close(ftp_helper_out[STDIN_FILENO]); 2942 | 2943 | array[c].diff = 2944 | (long double) (end.tv_sec - start.tv_sec ) + 2945 | (long double) (end.tv_nsec - start.tv_nsec) / 1000000000.0L; 2946 | 2947 | if (verbose >= 2) { 2948 | if (array[c].diff >= s) { 2949 | array[c].diff = s; 2950 | (void)printf("Timeout\n"); 2951 | } else if ( 2952 | (array[c].diff < 1) && 2953 | (array[c].diff >= 0) 2954 | ) { 2955 | sub_one_print(array[c].diff); 2956 | (void)printf("\n"); 2957 | } else { 2958 | (void)printf("%.9Lf\n", array[c].diff); 2959 | } 2960 | } else if ((average != 2) && !bandwidth && (verbose <= 0) 2961 | && (array[c].diff < S)) { 2962 | S = array[c].diff; 2963 | timeout.tv_sec = (time_t)(S + 0.125L); 2964 | timeout.tv_nsec = 2965 | (long) ( 2966 | ( 2967 | (S + 0.125L) - 2968 | (long double) timeout.tv_sec 2969 | ) * 1000000000.0L 2970 | ); 2971 | 2972 | } else if (array[c].diff > s) { 2973 | array[c].diff = s; 2974 | } 2975 | } 2976 | 2977 | free(line0); 2978 | line0 = NULL; 2979 | 2980 | if (dns_cache) { 2981 | (void)close(dns_cache_d_socket[1]); 2982 | (void)waitpid(dns_cache_d_pid, NULL, 0); 2983 | } 2984 | 2985 | if (pledge("stdio exec", NULL) == -1) { 2986 | err(1, "pledge, line: %d", __LINE__); 2987 | } 2988 | 2989 | if ((verbose == 0) || (verbose == 1)) { 2990 | (void)printf("\b \b"); 2991 | (void)fflush(stdout); 2992 | } 2993 | free(line); 2994 | line = NULL; 2995 | (void)close(kq); 2996 | 2997 | if (verbose <= 0) { 2998 | 2999 | if (average == 2) { 3000 | 3001 | int se = -1; 3002 | 3003 | if ( 3004 | heapsort(array, (size_t)array_length, 3005 | sizeof(MIRROR), diff_cmp_pure) 3006 | ) { 3007 | err(1, "sort failed, line %d", __LINE__); 3008 | } 3009 | 3010 | c = (int)array_length; 3011 | do { 3012 | --c; 3013 | if (array[c].diff < s) { 3014 | se = c; 3015 | break; 3016 | } 3017 | } while (c); 3018 | 3019 | if (se == -1) { 3020 | goto no_good; 3021 | } 3022 | 3023 | if ( 3024 | heapsort(array, (size_t)se + 1, sizeof(MIRROR), 3025 | diff_cmp) 3026 | ) { 3027 | err(1, "sort failed, line %d", __LINE__); 3028 | } 3029 | 3030 | for (c = 0; c <= se; ++c) { 3031 | long double t; 3032 | array[c].speed_rank = 1 + se - c; 3033 | 3034 | /* 3035 | * translate speed values into a linear 3036 | * equation (y == speed) with minimum 3037 | * and maximum y values and determine an 3038 | * x value from 0 to 100. This makes very 3039 | * good speeds stand out from the rest 3040 | * and evaluated accordingly. 3041 | */ 3042 | t = array[c].speed - array[se].speed; 3043 | t *= 100.0L; 3044 | t /= array[0].speed - array[se].speed; 3045 | 3046 | array[c].speed_rating = t; 3047 | } 3048 | 3049 | if ( 3050 | heapsort(array, (size_t)se + 1, 3051 | sizeof(MIRROR), diff_cmp_pure) 3052 | ) { 3053 | err(1, "sort failed, line %d", __LINE__); 3054 | } 3055 | 3056 | for (c = 0; c <= se; ++c) { 3057 | long double t; 3058 | array[c].diff_rank = 1 + se - c; 3059 | 3060 | /* 3061 | * translate speed values into a linear 3062 | * equation (y == speed) with minimum 3063 | * and maximum y values and determine an 3064 | * x value from 0 to 100. This makes very 3065 | * good speeds stand out from the rest 3066 | * and evaluated accordingly. 3067 | */ 3068 | t = array[c].diff - array[0].diff; 3069 | t *= 100.0L; 3070 | t /= array[se].diff - array[0].diff; 3071 | 3072 | array[c].diff_rating = 100.0L - t; 3073 | } 3074 | 3075 | if ( 3076 | heapsort(array, (size_t)se + 1, 3077 | sizeof(MIRROR), unified_cmp) 3078 | ) { 3079 | err(1, "sort failed, line %d", __LINE__); 3080 | } 3081 | 3082 | } else { 3083 | 3084 | if (responsiveness || average) { 3085 | /* 3086 | * perform sort for responsiveness 3087 | * ignore passive 'average' with a 3088 | * passive verbose 3089 | */ 3090 | sort_ret = heapsort(array, (size_t)array_length, 3091 | sizeof(MIRROR), diff_cmp_pure); 3092 | } else /* if (bandwidth) */ { 3093 | sort_ret = heapsort(array, (size_t)array_length, 3094 | sizeof(MIRROR), diff_cmp); 3095 | } 3096 | 3097 | if (sort_ret) { 3098 | err(1, "sort failed, line %d", __LINE__); 3099 | } 3100 | } 3101 | 3102 | } else { 3103 | int ds = -1; 3104 | int de = -1; 3105 | 3106 | int ts = -1; 3107 | int te = -1; 3108 | 3109 | int se = -1; 3110 | int se0 = -1; 3111 | 3112 | int first = 0; 3113 | 3114 | 3115 | MIRROR *slowest; 3116 | 3117 | int diff_topper = 0; 3118 | 3119 | long double t = 0; 3120 | int speed_shift = 0; 3121 | int pos_maxd = 0; 3122 | int pos_maxt = 0; 3123 | 3124 | size_t bbuf_size = 50; 3125 | char *bbuf = NULL; 3126 | 3127 | sort_ret = heapsort(array, (size_t)array_length, sizeof(MIRROR), 3128 | diff_cmp_pure); 3129 | 3130 | if (sort_ret) { 3131 | err(1, "sort failed, line %d", __LINE__); 3132 | } 3133 | 3134 | c = (int)array_length; 3135 | do { 3136 | --c; 3137 | if (array[c].diff < s) { 3138 | se = c; 3139 | break; 3140 | } 3141 | 3142 | if (array[c].diff > s) { 3143 | if (de == -1) { 3144 | ds = c; 3145 | de = c; 3146 | } else { 3147 | ds = c; 3148 | } 3149 | } else { 3150 | if (te == -1) { 3151 | ts = c; 3152 | te = c; 3153 | } else { 3154 | ts = c; 3155 | } 3156 | } 3157 | 3158 | } while (c); 3159 | 3160 | se0 = se; 3161 | 3162 | if (se == -1) { 3163 | goto no_good; 3164 | } 3165 | 3166 | if (generate == 0) { 3167 | goto generate_jump; 3168 | } 3169 | 3170 | if (all) 3171 | { 3172 | se = array_length - 1; 3173 | se0 = se; 3174 | } 3175 | 3176 | /* 3177 | * load diff with what will be printed http lengths 3178 | * then process http for printing 3179 | */ 3180 | n = 1; 3181 | ac = array + se + 1; 3182 | while (array < ac) { 3183 | --ac; 3184 | cut = ac->http += h; 3185 | j = (int)strlen(cut); 3186 | 3187 | if (j <= 12) { 3188 | (ac->http -= 1)[0] = '*'; 3189 | ac->diff = j + 1; 3190 | } else if (strcmp(cut += j -= 12, "/pub/OpenBSD")) { 3191 | (ac->http -= 1)[0] = '*'; 3192 | ac->diff = j + 13; 3193 | } else { 3194 | *cut = '\0'; 3195 | ac->diff = j; 3196 | } 3197 | 3198 | if (n) { 3199 | 3200 | cut = strchr(ac->http, '/'); 3201 | 3202 | if (cut == NULL) { 3203 | cut = ac->http + (int)ac->diff; 3204 | } 3205 | 3206 | if (((cut - ac->http) > 12) && 3207 | ( 3208 | !strncmp(cut - 12, ".openbsd.org", 12) 3209 | 3210 | || 3211 | 3212 | !strncmp(cut - 12, ".OpenBSD.org", 12) 3213 | ) 3214 | ) { 3215 | n = 0; 3216 | } 3217 | } 3218 | } 3219 | 3220 | 3221 | 3222 | if (n) { 3223 | 3224 | (void)printf("Couldn't find any openbsd.org mirrors."); 3225 | (void)printf("\nTry again with a larger timeout!\n"); 3226 | 3227 | ac = array + se0 + 1; 3228 | while (array < ac) { 3229 | --ac; 3230 | if (ac->http[0] == '*') { 3231 | ac->http -= h - 1; 3232 | } else { 3233 | ac->http -= h; 3234 | } 3235 | } 3236 | 3237 | free(current_time); 3238 | 3239 | return 1; 3240 | } 3241 | 3242 | /* 3243 | * sort by longest length first, subsort http alphabetically 3244 | * It makes it kinda look like a flower. 3245 | */ 3246 | if ( 3247 | heapsort(array, (size_t)se + 1, sizeof(MIRROR), 3248 | diff_cmp_g) 3249 | ) { 3250 | err(1, "sort failed, line %d", __LINE__); 3251 | } 3252 | 3253 | (void)printf("\n\n"); 3254 | (void)printf(" "); 3255 | (void)printf("/* GENERATED CODE BEGINS HERE */\n\n\n"); 3256 | (void)printf(" const char *ftp_list[%d] = {\n\n", 3257 | se + 1); 3258 | 3259 | 3260 | /* n = 0; */ 3261 | for (c = 0; c < se; ++c) { 3262 | 3263 | /* 3264 | * 3 is the size of the printed: "", 3265 | */ 3266 | 3267 | if ((((int)array[c].diff) + 3) > 80) { 3268 | (void)printf("\"%s\",\n", array[first].http); 3269 | ++first; 3270 | } else { 3271 | break; 3272 | } 3273 | } 3274 | 3275 | if (c == se) { 3276 | goto gen_skip1; 3277 | } 3278 | 3279 | for (; c <= se; ++c) { 3280 | 3281 | /* 3282 | * 3 is the size of the printed: "", 3283 | * if (c == se) it doesn't print the comma 3284 | */ 3285 | 3286 | i = ((int)array[c].diff) + 3 - (c == se); 3287 | n += i; 3288 | 3289 | /* 3290 | * overflow: 3291 | * mirrors printed on each line 3292 | * will not exceed 80 characters 3293 | */ 3294 | if (n > 80) { 3295 | 3296 | /* center the printed mirrors. Err to right */ 3297 | for (j = (80+1 - (n - i)) / 2; j > 0; --j) { 3298 | (void)printf(" "); 3299 | } 3300 | do { 3301 | (void)printf("\"%s\",", 3302 | array[first].http); 3303 | ++first; 3304 | } while (first < c); 3305 | (void)printf("\n"); 3306 | n = i; 3307 | 3308 | } 3309 | } 3310 | 3311 | /* center the printed mirrors. Err to right */ 3312 | for (j = (80+1 - n) / 2; j > 0; --j) { 3313 | (void)printf(" "); 3314 | } 3315 | while (first < se) { 3316 | (void)printf("\"%s\",", array[first].http); 3317 | ++first; 3318 | } 3319 | gen_skip1: 3320 | (void)printf("\"%s\"\n\n", array[se].http); 3321 | 3322 | (void)printf(" };\n\n"); 3323 | (void)printf(" const int ftp_list_index = %d;\n\n\n\n", 3324 | se + 1); 3325 | 3326 | 3327 | /* 3328 | * make non-openbsd.org mirrors: diff == 0 3329 | * and stop them from being displayed 3330 | */ 3331 | ac = array + se + 1; 3332 | while (array < ac) { 3333 | --ac; 3334 | cut = strchr(ac->http, '/'); 3335 | if (cut == NULL) { 3336 | cut = ac->http + (int)ac->diff; 3337 | } 3338 | if (((cut - ac->http) <= 12) || 3339 | ( 3340 | strncmp(cut - 12, ".openbsd.org", 12) 3341 | 3342 | && 3343 | 3344 | strncmp(cut - 12, ".OpenBSD.org", 12) 3345 | ) 3346 | ) { 3347 | ac->diff = 0; 3348 | --se; 3349 | } 3350 | } 3351 | 3352 | /* 3353 | * sort by longest length first, 3354 | * if diff > 0 then 3355 | * subsort http alphabetically 3356 | */ 3357 | if ( 3358 | heapsort(array, (size_t)se0 + 1, sizeof(MIRROR), 3359 | diff_cmp_g2) 3360 | ) { 3361 | err(1, "sort failed, line %d", __LINE__); 3362 | } 3363 | 3364 | (void)printf(" /* Trusted OpenBSD.org subdomain "); 3365 | (void)printf("mirrors for generating this section */\n\n"); 3366 | (void)printf(" const char "); 3367 | (void)printf("*ftp_list_g[%d] = {\n\n", se + 1); 3368 | 3369 | 3370 | n = 0; 3371 | first = 0; 3372 | 3373 | for (c = 0; c < se; ++c) { 3374 | 3375 | /* 3376 | * 3 is the size of the printed: "", 3377 | */ 3378 | 3379 | if ((((int)array[c].diff) + 3) > 80) { 3380 | (void)printf("\"%s\",\n", array[first].http); 3381 | ++first; 3382 | } else { 3383 | break; 3384 | } 3385 | } 3386 | 3387 | if (c == se) { 3388 | goto gen_skip2; 3389 | } 3390 | 3391 | for (; c <= se; ++c) { 3392 | 3393 | /* 3394 | * 3 is the size of the printed: "", 3395 | * if (c == se) it doesn't print the comma 3396 | */ 3397 | 3398 | i = ((int)array[c].diff) + 3 - (c == se); 3399 | n += i; 3400 | 3401 | /* 3402 | * overflow: 3403 | * mirrors printed on each line 3404 | * will not exceed 80 characters 3405 | */ 3406 | if (n > 80) { 3407 | 3408 | /* center the printed mirrors. Err to right */ 3409 | for (j = (80+1 - (n - i)) / 2; j > 0; --j) { 3410 | (void)printf(" "); 3411 | } 3412 | do { 3413 | (void)printf("\"%s\",", 3414 | array[first].http); 3415 | ++first; 3416 | } while (first < c); 3417 | (void)printf("\n"); 3418 | n = i; 3419 | } 3420 | } 3421 | 3422 | /* center the printed mirrors. Err to right */ 3423 | for (j = (80+1 - n) / 2; j > 0; --j) { 3424 | (void)printf(" "); 3425 | } 3426 | while (first < se) { 3427 | (void)printf("\"%s\",", array[first].http); 3428 | ++first; 3429 | } 3430 | gen_skip2: 3431 | (void)printf("\"%s\"\n\n", array[se].http); 3432 | 3433 | (void)printf(" };\n\n"); 3434 | (void)printf(" const int ftp_list_index_g = %d;\n\n\n", 3435 | se + 1); 3436 | (void)printf(" "); 3437 | (void)printf("/* GENERATED CODE ENDS HERE */\n\n\n\n"); 3438 | (void)printf("Replace section after line: %d,", entry_line); 3439 | (void)printf(" but before line: %d with the", exit_line); 3440 | (void)printf(" code above.\n\n"); 3441 | 3442 | ac = array + se0 + 1; 3443 | while (array < ac) { 3444 | --ac; 3445 | if (ac->http[0] == '*') { 3446 | ac->http -= h - 1; 3447 | } else { 3448 | ac->http -= h; 3449 | } 3450 | } 3451 | 3452 | free(current_time); 3453 | current_time = NULL; 3454 | 3455 | if (debug) { 3456 | goto debug_display; 3457 | } 3458 | 3459 | return 0; 3460 | 3461 | generate_jump: 3462 | 3463 | 3464 | sort_ret = heapsort(array, (size_t)se + 1, sizeof(MIRROR), 3465 | diff_cmp); 3466 | 3467 | if (sort_ret) { 3468 | err(1, "sort failed, line %d", __LINE__); 3469 | } 3470 | 3471 | for (c = 0; c <= se; ++c) { 3472 | array[c].speed_rank = 1 + se - c; 3473 | 3474 | /* 3475 | * translate speed values into a linear 3476 | * equation (y == speed) with minimum 3477 | * and maximum y values and determine an 3478 | * x value from 0 to 100. This makes very 3479 | * good speeds stand out from the rest 3480 | * and evaluated accordingly. 3481 | */ 3482 | t = array[c].speed - array[se].speed; 3483 | t *= 100.0L; 3484 | t /= array[0].speed - array[se].speed; 3485 | 3486 | array[c].speed_rating = t; 3487 | } 3488 | 3489 | if ( 3490 | heapsort(array, (size_t)se + 1, sizeof(MIRROR), 3491 | diff_cmp_pure) 3492 | ) { 3493 | err(1, "sort failed, line %d", __LINE__); 3494 | } 3495 | 3496 | for (c = 0; c <= se; ++c) { 3497 | array[c].diff_rank = 1 + se - c; 3498 | 3499 | /* 3500 | * translate speed values into a linear 3501 | * equation (y == speed) with minimum 3502 | * and maximum y values and determine an 3503 | * x value from 0 to 100. This makes very 3504 | * good speeds stand out from the rest 3505 | * and evaluated accordingly. 3506 | */ 3507 | t = array[c].diff - array[0].diff; 3508 | t *= 100.0L; 3509 | t /= array[se].diff - array[0].diff; 3510 | 3511 | array[c].diff_rating = 100.0L - t; 3512 | } 3513 | 3514 | 3515 | 3516 | if (average) { 3517 | sort_ret = heapsort(array, (size_t)(se + 1), 3518 | sizeof(MIRROR), unified_cmp); 3519 | } else if (bandwidth) { 3520 | sort_ret = heapsort(array, (size_t)(se + 1), 3521 | sizeof(MIRROR), diff_cmp); 3522 | } else { 3523 | sort_ret = 0; 3524 | } 3525 | 3526 | if (sort_ret) { 3527 | err(1, "sort failed, line %d", __LINE__); 3528 | } 3529 | 3530 | if (de != -1) { 3531 | (void)printf("\n\nDOWNLOAD ERROR MIRRORS:\n\n"); 3532 | } else if (te != -1) { 3533 | (void)printf("\n\nTIMEOUT MIRRORS:\n\n"); 3534 | } else { 3535 | (void)printf("\n\nSUCCESSFUL MIRRORS:\n\n"); 3536 | } 3537 | 3538 | slowest = array + se; 3539 | ac = slowest; 3540 | 3541 | while (array < ac) { 3542 | --ac; 3543 | if (diff_cmp_pure(ac, slowest) > 0) { 3544 | slowest = ac; 3545 | } 3546 | } 3547 | 3548 | diff_topper = 0; 3549 | i = 1; 3550 | while (slowest->diff >= i) { 3551 | i *= 10; 3552 | ++diff_topper; 3553 | if (diff_topper == 4) { 3554 | break; 3555 | } 3556 | } 3557 | 3558 | ac = array + se; 3559 | pos_maxl = (int)strlen(ac->label); 3560 | 3561 | while (array < ac) { 3562 | --ac; 3563 | pos = (int)strlen(ac->label); 3564 | if (pos > pos_maxl) { 3565 | pos_maxl = pos; 3566 | } 3567 | } 3568 | 3569 | 3570 | pos_maxt = 0; 3571 | 3572 | if (te != -1) { 3573 | for (c = te; c >= ts; --c) { 3574 | pos = (int)strlen(array[c].label); 3575 | if (pos > pos_maxt) { 3576 | pos_maxt = pos; 3577 | } 3578 | } 3579 | } 3580 | 3581 | 3582 | pos_maxd = 0; 3583 | 3584 | if (de != -1) { 3585 | for (c = de; c >= ds; --c) { 3586 | pos = (int)strlen(array[c].label); 3587 | if (pos > pos_maxd) { 3588 | pos_maxd = pos; 3589 | } 3590 | } 3591 | } 3592 | 3593 | bbuf_size = 50; 3594 | bbuf = (char*)malloc(bbuf_size); 3595 | if (bbuf == NULL) { 3596 | errx(1, "malloc"); 3597 | } 3598 | 3599 | speed_shift = 0; 3600 | 3601 | ac = array + se + 1; 3602 | 3603 | while (array < ac) { 3604 | --ac; 3605 | 3606 | t = ac->speed; 3607 | 3608 | if (t >= (1024.0L * 1024.0L)) { 3609 | j = snprintf(bbuf, bbuf_size, "%.2Lf", 3610 | t / (1024.0L * 1024.0L)); 3611 | } else { 3612 | j = snprintf(bbuf, bbuf_size, "%.2Lf", 3613 | t / 1024.0L); 3614 | } 3615 | 3616 | if (j > speed_shift) { 3617 | speed_shift = j; 3618 | } 3619 | } 3620 | 3621 | 3622 | 3623 | 3624 | 3625 | c = (int)array_length; 3626 | ac = array + c; 3627 | 3628 | while (array < ac) { 3629 | --ac; 3630 | 3631 | if (array_length >= 100) { 3632 | (void)printf("\n%3d : ", c); 3633 | } else { 3634 | (void)printf("\n%2d : ", c); 3635 | } 3636 | 3637 | i = (int)strlen(ac->label); 3638 | 3639 | --c; 3640 | if (c <= se) { 3641 | 3642 | j = ((int)pos_maxl + 1 - i) / 2; 3643 | n = (int)pos_maxl - (i + j); 3644 | for (; j > 0; --j) { 3645 | (void)printf(" "); 3646 | } 3647 | 3648 | (void)printf("%s", ac->label); 3649 | 3650 | for (; n > 0; --n) { 3651 | (void)printf(" "); 3652 | } 3653 | 3654 | (void)printf(" : "); 3655 | 3656 | if ((ac->diff < 1) && (ac->diff >= 0)) { 3657 | switch (diff_topper) { 3658 | case 1: 3659 | (void)printf(" "); 3660 | break; 3661 | case 2: 3662 | (void)printf(" "); 3663 | break; 3664 | case 3: 3665 | (void)printf(" "); 3666 | break; 3667 | default: 3668 | (void)printf(" "); 3669 | break; 3670 | } 3671 | sub_one_print(ac->diff); 3672 | } else { 3673 | switch (diff_topper) { 3674 | case 1: 3675 | (void)printf("%1.9Lf", 3676 | ac->diff); 3677 | break; 3678 | case 2: 3679 | (void)printf("%2.9Lf", 3680 | ac->diff); 3681 | break; 3682 | case 3: 3683 | (void)printf("%3.9Lf", 3684 | ac->diff); 3685 | break; 3686 | default: 3687 | (void)printf("%4.9Lf", 3688 | ac->diff); 3689 | break; 3690 | } 3691 | } 3692 | (void)printf(" seconds : "); 3693 | 3694 | t = (long double)ac->speed; 3695 | 3696 | 3697 | if (t >= (1024L * 1024L)) { 3698 | j = snprintf(bbuf, bbuf_size, "%.2Lf", 3699 | t / (1024.0L * 1024.0L)); 3700 | } else { 3701 | j = snprintf(bbuf, bbuf_size, "%.2Lf", 3702 | t / 1024.0L); 3703 | } 3704 | 3705 | n = speed_shift - j; 3706 | 3707 | while(n-- > 0) { 3708 | (void)printf(" "); 3709 | } 3710 | 3711 | if (t >= (1024.0L * 1024.0L)) { 3712 | (void)printf("%.2Lf MB/s\n", 3713 | t / (1024.0L * 1024.0L)); 3714 | } else { 3715 | (void)printf("%.2Lf KB/s\n", 3716 | t / 1024.0L); 3717 | } 3718 | 3719 | 3720 | 3721 | i = 2 + (array_length >= 100); 3722 | 3723 | i += 3 + pos_maxl; 3724 | 3725 | for (; i > 0; --i) { 3726 | (void)printf(" "); 3727 | } 3728 | 3729 | (void)printf(" : "); 3730 | 3731 | 3732 | if (se >= 99) { 3733 | 3734 | /* 3735 | * j = snprintf(bbuf, bbuf_size, 3736 | * "time rank: %3d", 3737 | * 1 + se - (ac->diff_rank - 1)); 3738 | */ 3739 | 3740 | j = 14; 3741 | 3742 | i = (diff_topper + 18 + 1 - j) / 2; 3743 | n = i; 3744 | 3745 | for (; i > 0; --i) { 3746 | (void)printf(" "); 3747 | } 3748 | 3749 | (void)printf("time rank: %3d", 3750 | 1 + se - (ac->diff_rank - 1)); 3751 | 3752 | n = diff_topper + 18 - (n + j); 3753 | 3754 | for (; n > 0; --n) { 3755 | (void)printf(" "); 3756 | } 3757 | 3758 | (void)printf(" : speed rank: %3d", 3759 | 1 + se - (ac->speed_rank - 1)); 3760 | } else if (se >= 9) { 3761 | 3762 | /* 3763 | * j = snprintf(bbuf, bbuf_size, 3764 | * "time rank: %2d", 3765 | * 1 + se - (ac->diff_rank - 1)); 3766 | */ 3767 | 3768 | j = 13; 3769 | 3770 | i = (diff_topper + 18 + 1 - j) / 2; 3771 | n = i; 3772 | 3773 | for (; i > 0; --i) { 3774 | (void)printf(" "); 3775 | } 3776 | 3777 | (void)printf("time rank: %2d", 3778 | 1 + se - (ac->diff_rank - 1)); 3779 | 3780 | n = diff_topper + 18 - (n + j); 3781 | 3782 | for (; n > 0; --n) { 3783 | (void)printf(" "); 3784 | } 3785 | 3786 | (void)printf(" : speed rank: %2d", 3787 | 1 + se - (ac->speed_rank - 1)); 3788 | } else { 3789 | 3790 | /* 3791 | * j = snprintf(bbuf, bbuf_size, 3792 | * "time rank: %d", 3793 | * 1 + se - (ac->diff_rank - 1)); 3794 | */ 3795 | 3796 | j = 12; 3797 | 3798 | i = (diff_topper + 18 + 1 - j) / 2; 3799 | n = i; 3800 | 3801 | for (; i > 0; --i) { 3802 | (void)printf(" "); 3803 | } 3804 | 3805 | (void)printf("time rank: %d", 3806 | 1 + se - (ac->diff_rank - 1)); 3807 | 3808 | n = diff_topper + 18 - (n + j); 3809 | 3810 | for (; n > 0; --n) { 3811 | (void)printf(" "); 3812 | } 3813 | 3814 | (void)printf(" : speed rank: %d", 3815 | 1 + se - (ac->speed_rank - 1)); 3816 | } 3817 | 3818 | (void)printf("\n"); 3819 | 3820 | if (array_length >= 100) { 3821 | i = 3; 3822 | } 3823 | else { 3824 | i = 2; 3825 | } 3826 | 3827 | i += 3 + pos_maxl; 3828 | 3829 | for (; i > 0; --i) { 3830 | (void)printf(" "); 3831 | } 3832 | 3833 | (void)printf(" : "); 3834 | 3835 | 3836 | 3837 | 3838 | j = snprintf(bbuf, bbuf_size, 3839 | "t rating: %.3LF", 3840 | ac->diff_rating); 3841 | 3842 | i = (diff_topper + 18 + 1 - j) / 2; 3843 | n = i; 3844 | 3845 | for (; i > 0; --i) { 3846 | (void)printf(" "); 3847 | } 3848 | 3849 | (void)printf("t rating: %.3LF", 3850 | ac->diff_rating); 3851 | 3852 | n = diff_topper + 18 - (n + j); 3853 | 3854 | for (; n > 0; --n) { 3855 | (void)printf(" "); 3856 | } 3857 | 3858 | (void)printf(" : speed rating: %.3LF", 3859 | ac->speed_rating); 3860 | 3861 | (void)printf("\n\n echo \""); 3862 | (void)printf("%s", ac->http); 3863 | (void)printf("\" > /etc/installurl\n\n\n"); 3864 | continue; 3865 | } 3866 | 3867 | cut = strchr(ac->http + h, '/'); 3868 | if (cut) { 3869 | *cut = '\0'; 3870 | } 3871 | 3872 | if (c <= te) { 3873 | 3874 | j = ((int)pos_maxt + 1 - i) / 2; 3875 | n = (int)pos_maxt - (i + j); 3876 | 3877 | for (; j > 0; --j) { 3878 | (void)printf(" "); 3879 | } 3880 | 3881 | (void)printf("%s", ac->label); 3882 | 3883 | for (; n > 0; --n) { 3884 | (void)printf(" "); 3885 | } 3886 | 3887 | (void)printf(" : "); 3888 | (void)printf("Timeout\n %s\n", 3889 | ac->http + h); 3890 | 3891 | if ((c == ts) && (se != -1)) { 3892 | (void)printf("\n\nSUCCESSFUL "); 3893 | (void)printf("MIRRORS:\n\n"); 3894 | } 3895 | 3896 | continue; 3897 | } 3898 | 3899 | j = ((int)pos_maxd + 1 - i) / 2; 3900 | n = (int)pos_maxd - (i + j); 3901 | 3902 | for (; j > 0; --j) { 3903 | (void)printf(" "); 3904 | } 3905 | 3906 | (void)printf("%s", ac->label); 3907 | 3908 | for (; n > 0; --n) { 3909 | (void)printf(" "); 3910 | } 3911 | 3912 | (void)printf(" : "); 3913 | 3914 | // If assigned this value.... If -Wfloat-equal warnings, ignore it. 3915 | if (ac->diff == (s + 1)) { 3916 | (void)printf("Download Error"); 3917 | } else if (ac->diff == (s + 2)) { 3918 | (void)printf("IPv6 DNS record not found"); 3919 | } else if (ac->diff == (s + 3)) { 3920 | (void)printf("DNS record not found"); 3921 | } else { 3922 | (void)printf("BLOCKED subdomain!"); 3923 | } 3924 | 3925 | 3926 | (void)printf("\n %s\n", ac->http + h); 3927 | 3928 | 3929 | if (c == ds) { 3930 | if (te != -1) { 3931 | (void)printf("\n\nTIMEOUT"); 3932 | (void)printf(" MIRRORS:\n\n"); 3933 | } else if (se != -1) { 3934 | (void)printf("\n\nSUCCESSFUL"); 3935 | (void)printf(" MIRRORS:\n\n"); 3936 | } 3937 | } 3938 | } 3939 | freezero(bbuf, bbuf_size); 3940 | } 3941 | 3942 | if (array[0].diff >= s) { 3943 | 3944 | no_good: 3945 | 3946 | (void)printf("No successful mirrors found.\n\n"); 3947 | 3948 | if (next) { 3949 | (void)printf("Perhaps the next release "); 3950 | (void)printf("(%s) isn't available?\n", release); 3951 | } else if (previous) { 3952 | (void)printf("Perhaps the previous release "); 3953 | (void)printf("(%s) isn't available?\n", release); 3954 | } else if (!current && !generate && override) { 3955 | (void)printf("You are probably seeking to use "); 3956 | (void)printf("the -p flag instead of -O flag "); 3957 | (void)printf("since the %s release ", release); 3958 | (void)printf("doesn't seem to be available.\n"); 3959 | } else if (!current && !generate) { 3960 | (void)printf("You are probably running a snapshot, "); 3961 | (void)printf("but it is indicating that you are"); 3962 | (void)printf(" running a release. running a release. "); 3963 | (void)printf("You should use the -O flag in that"); 3964 | (void)printf(" case.\n"); 3965 | } 3966 | if (six) { 3967 | (void)printf("If your dns system is not set up "); 3968 | (void)printf("for IPv6 connections, then "); 3969 | (void)printf("lose the -6 flag.\n\n"); 3970 | } 3971 | 3972 | if (s_set == 0) { 3973 | (void)printf("Perhaps try the -s "); 3974 | (void)printf("option to choose a timeout"); 3975 | (void)printf(" larger than the default: -s %s\n", 3976 | current_time); 3977 | } else { 3978 | (void)printf("Perhaps try with a larger -s than %s\n", 3979 | current_time); 3980 | } 3981 | 3982 | free(current_time); 3983 | free(release); 3984 | 3985 | return 1; 3986 | } 3987 | 3988 | free(current_time); 3989 | free(release); 3990 | 3991 | if (to_file) { 3992 | 3993 | n = (int)strlen(array[0].http); 3994 | 3995 | i = (int)write(write_pipe[STDOUT_FILENO], 3996 | array[0].http, (size_t)n); 3997 | 3998 | if (i < n) { 3999 | (void)printf("\nnot all of mirror sent to write_pid\n"); 4000 | restart(argc, argv, loop, verbose); 4001 | } 4002 | 4003 | (void)waitpid(write_pid, &z, 0); 4004 | 4005 | if (z) { 4006 | (void)printf("\nwrite_pid error.\n"); 4007 | restart(argc, argv, loop, verbose); 4008 | } 4009 | 4010 | } else if ((!root_user && (verbose != -1)) || (root_user && !verbose)) { 4011 | if (verbose) { 4012 | (void)printf("\n"); 4013 | } 4014 | (void)printf("As root, type: echo "); 4015 | (void)printf("\"%s\" > /etc/installurl\n", array[0].http); 4016 | } 4017 | 4018 | if (debug) { 4019 | 4020 | debug_display: 4021 | 4022 | (void)clock_gettime(CLOCK_REALTIME, &endD); 4023 | 4024 | 4025 | if (verbose != -1) { 4026 | (void)printf("\n"); 4027 | } 4028 | 4029 | (void)printf("Elapsed time: "); 4030 | 4031 | S = (long double) (endD.tv_sec - startD.tv_sec ) + 4032 | (long double) (endD.tv_nsec - startD.tv_nsec) / 4033 | 1000000000.0L; 4034 | 4035 | if ( (S < 1.0L) && (S >= 0.0L) ) { 4036 | sub_one_print(S); 4037 | (void)printf("\n"); 4038 | } else { 4039 | (void)printf("%.9Lf\n", S); 4040 | } 4041 | } 4042 | 4043 | return 0; 4044 | } 4045 | --------------------------------------------------------------------------------