|
rpm
5.4.4
|
00001 00005 #include "system.h" 00006 #include <stdarg.h> 00007 00008 #if defined(HAVE_MACHINE_TYPES_H) 00009 # include <machine/types.h> 00010 #endif 00011 00012 #if defined(HAVE_SYS_SOCKET_H) 00013 # include <sys/socket.h> 00014 #endif 00015 00016 #ifndef NI_MAXHOST 00017 #define NI_MAXHOST 1025 00018 #endif 00019 00020 #if defined(__LCLINT__) 00021 struct addrinfo 00022 { 00023 int ai_flags; /* Input flags. */ 00024 int ai_family; /* Protocol family for socket. */ 00025 int ai_socktype; /* Socket type. */ 00026 int ai_protocol; /* Protocol for socket. */ 00027 socklen_t ai_addrlen; /* Length of socket address. */ 00028 struct sockaddr *ai_addr; /* Socket address for socket. */ 00029 char *ai_canonname; /* Canonical name for service location. */ 00030 struct addrinfo *ai_next; /* Pointer to next in list. */ 00031 }; 00032 00033 /*@-exportheader -incondefs @*/ 00034 extern int getaddrinfo (__const char *__restrict __name, 00035 __const char *__restrict __service, 00036 __const struct addrinfo *__restrict __req, 00037 /*@out@*/ struct addrinfo **__restrict __pai) 00038 /*@modifies *__pai @*/; 00039 00040 extern int getnameinfo (__const struct sockaddr *__restrict __sa, 00041 socklen_t __salen, /*@out@*/ char *__restrict __host, 00042 socklen_t __hostlen, /*@out@*/ char *__restrict __serv, 00043 socklen_t __servlen, unsigned int __flags) 00044 /*@modifies __host, __serv @*/; 00045 00046 extern void freeaddrinfo (/*@only@*/ struct addrinfo *__ai) 00047 /*@modifies __ai @*/; 00048 /*@=exportheader =incondefs @*/ 00049 #else 00050 #include <netdb.h> /* XXX getaddrinfo et al */ 00051 #endif 00052 00053 #include <netinet/in.h> 00054 #include <arpa/inet.h> /* XXX for inet_aton and HP-UX */ 00055 00056 #if defined(HAVE_NETINET_IN_SYSTM_H) 00057 # include <sys/types.h> 00058 # include <netinet/in_systm.h> 00059 #endif 00060 00061 #if defined(WITH_XZ) 00062 #include <lzma.h> 00063 #endif 00064 00065 #include <rpmiotypes.h> 00066 #include <rpmmacro.h> /* XXX rpmioAccess needs rpmCleanPath() */ 00067 00068 #include <mongo.h> 00069 00070 #include <rpmaug.h> 00071 #include <rpmficl.h> 00072 #include <rpmjs.h> 00073 #include <rpmlua.h> /* XXX rpmioClean() calls rpmluaFree() */ 00074 #include <rpmnix.h> 00075 #include <rpmperl.h> 00076 #include <rpmpython.h> 00077 #include <rpmruby.h> 00078 #include <rpmsql.h> 00079 #include <rpmsquirrel.h> 00080 #include <rpmtcl.h> 00081 00082 #define _RPMHKP_INTERNAL /* XXX awol/crl bloom filters */ 00083 #include <rpmhkp.h> 00084 00085 #include <rpmsm.h> 00086 #include <rpmsp.h> 00087 #include <rpmsx.h> 00088 00089 #if defined(HAVE_LIBIO_H) && defined(_G_IO_IO_FILE_VERSION) 00090 #define _USE_LIBIO 1 00091 #endif 00092 00093 /* XXX HP-UX w/o -D_XOPEN_SOURCE needs */ 00094 #if !defined(HAVE_HERRNO) && (defined(hpux) || defined(__hpux) || defined(__LCLINT__)) 00095 /*@unchecked@*/ 00096 extern int h_errno; 00097 #endif 00098 00099 #ifndef IPPORT_FTP 00100 #define IPPORT_FTP 21 00101 #endif 00102 #ifndef IPPORT_HTTP 00103 #define IPPORT_HTTP 80 00104 #endif 00105 00106 #if !defined(HAVE_INET_ATON) 00107 #define inet_aton(cp,inp) rpm_inet_aton(cp,inp) 00108 static int rpm_inet_aton(const char *cp, struct in_addr *inp) 00109 /*@modifies *inp @*/ 00110 { 00111 long addr; 00112 00113 addr = inet_addr(cp); 00114 if (addr == ((long) -1)) return 0; 00115 00116 memcpy(inp, &addr, sizeof(addr)); 00117 return 1; 00118 } 00119 #endif 00120 00121 #if defined(USE_ALT_DNS) && USE_ALT_DNS 00122 #include "dns.h" 00123 #endif 00124 00125 #include <rpmio_internal.h> 00126 #undef fdFileno 00127 #undef fdOpen 00128 #define fdOpen __fdOpen 00129 #undef fdRead 00130 #define fdRead __fdRead 00131 #undef fdWrite 00132 #define fdWrite __fdWrite 00133 #undef fdClose 00134 #define fdClose __fdClose 00135 00136 #include <ugid.h> 00137 #include <rpmcb.h> 00138 #include <rpmdav.h> 00139 00140 #include "debug.h" 00141 00142 /*@access FILE @*/ /* XXX to permit comparison/conversion with void *. */ 00143 /*@access urlinfo @*/ 00144 /*@access FDSTAT_t @*/ 00145 /*@access rpmxar @*/ 00146 /*@access pgpDig @*/ 00147 00148 #define FDTO(fd) (fd ? ((FD_t)fd)->rd_timeoutsecs : -99) 00149 #define FDCPIOPOS(fd) (fd ? ((FD_t)fd)->fd_cpioPos : -99) 00150 00151 #define FDONLY(fd) assert(fdGetIo(fd) == fdio) 00152 00153 #define UFDONLY(fd) /* assert(fdGetIo(fd) == ufdio) */ 00154 00155 #define fdGetFILE(_fd) ((FILE *)fdGetFp(_fd)) 00156 00159 /*@unchecked@*/ 00160 #if _USE_LIBIO 00161 int noLibio = 0; 00162 #else 00163 int noLibio = 1; 00164 #endif 00165 00166 #define TIMEOUT_SECS 60 00167 00170 /*@unchecked@*/ 00171 static int ftpTimeoutSecs = TIMEOUT_SECS; 00172 00175 /*@unchecked@*/ 00176 int _rpmio_debug = 0; 00177 00180 /*@unchecked@*/ 00181 int _av_debug = 0; 00182 00185 /*@unchecked@*/ 00186 int _ftp_debug = 0; 00187 00190 /*@unchecked@*/ 00191 int _dav_debug = 0; 00192 00193 /* =============================================================== */ 00194 00195 const char * fdbg(FD_t fd) 00196 { 00197 static char buf[BUFSIZ]; 00198 char *be = buf; 00199 int i; 00200 00201 buf[0] = '\0'; 00202 if (fd == NULL) 00203 return buf; 00204 00205 #ifdef DYING 00206 sprintf(be, "fd %p", fd); be += strlen(be); 00207 if (fd->rd_timeoutsecs >= 0) { 00208 sprintf(be, " secs %d", fd->rd_timeoutsecs); 00209 be += strlen(be); 00210 } 00211 #endif 00212 if (fd->bytesRemain != -1) { 00213 sprintf(be, " clen %d", (int)fd->bytesRemain); 00214 be += strlen(be); 00215 } 00216 if (fd->wr_chunked) { 00217 strcpy(be, " chunked"); 00218 be += strlen(be); 00219 } 00220 *be++ = '\t'; 00221 for (i = fd->nfps; i >= 0; i--) { 00222 FDSTACK_t * fps = &fd->fps[i]; 00223 if (i != fd->nfps) 00224 *be++ = ' '; 00225 *be++ = '|'; 00226 *be++ = ' '; 00227 if (fps->io == fdio) { 00228 sprintf(be, "FD %d fp %p", fps->fdno, fps->fp); 00229 } else if (fps->io == ufdio) { 00230 sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp); 00231 #if defined(WITH_ZLIB) 00232 } else if (fps->io == gzdio) { 00233 sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno); 00234 #endif 00235 #if defined(WITH_BZIP2) 00236 } else if (fps->io == bzdio) { 00237 sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno); 00238 #endif 00239 #if defined(WITH_XZ) 00240 } else if (fps->io == lzdio) { 00241 sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno); 00242 } else if (fps->io == xzdio) { 00243 sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno); 00244 #endif 00245 } else if (fps->io == fpio) { 00246 /*@+voidabstract@*/ 00247 sprintf(be, "%s %p(%d) fdno %d", 00248 (fps->fdno < 0 ? "LIBIO" : "FP"), 00249 fps->fp, fileno(((FILE *)fps->fp)), fps->fdno); 00250 /*@=voidabstract@*/ 00251 } else { 00252 sprintf(be, "??? io %p fp %p fdno %d ???", 00253 fps->io, fps->fp, fps->fdno); 00254 } 00255 be += strlen(be); 00256 *be = '\0'; 00257 } 00258 return buf; 00259 } 00260 00261 /* =============================================================== */ 00262 FD_t fdDup(int fdno) 00263 { 00264 FD_t fd; 00265 int nfdno; 00266 00267 if ((nfdno = dup(fdno)) < 0) 00268 return NULL; 00269 if (fcntl(nfdno, F_SETFD, FD_CLOEXEC)) { 00270 (void) close(nfdno); 00271 return NULL; 00272 } 00273 fd = fdNew("open (fdDup)"); 00274 fdSetOpen(fd, "fdDup", nfdno, 0); /* XXX bogus */ 00275 fdSetFdno(fd, nfdno); 00276 DBGIO(fd, (stderr, "<-- fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd))); 00277 /*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/ 00278 } 00279 00280 static inline /*@unused@*/ 00281 int fdSeekNot(void * cookie, 00282 /*@unused@*/ _libio_pos_t pos, 00283 /*@unused@*/ int whence) 00284 /*@*/ 00285 { 00286 FD_t fd = c2f(cookie); 00287 FDSANE(fd); /* XXX keep gcc quiet */ 00288 return -2; 00289 } 00290 00291 /* =============================================================== */ 00292 00293 static void fdFini(void * _fd) 00294 /*@globals fileSystem @*/ 00295 /*@modifies _fd, fileSystem @*/ 00296 { 00297 FD_t fd = _fd; 00298 int i; 00299 00300 assert(fd != NULL); 00301 fd->opath = _free(fd->opath); 00302 fd->stats = _free(fd->stats); 00303 if (fd->ndigests > 0) 00304 for (i = fd->ndigests - 1; i >= 0; i--) { 00305 DIGEST_CTX ctx = fd->digests[i]; 00306 if (ctx == NULL) 00307 continue; 00308 (void) rpmDigestFinal(ctx, NULL, NULL, 0); 00309 fd->digests[i] = NULL; 00310 } 00311 fd->digests = _free(fd->digests); 00312 fd->ndigests = 0; 00313 fd->contentType = _free(fd->contentType); 00314 fd->contentDisposition = _free(fd->contentDisposition); 00315 /*@-onlytrans@*/ 00316 #ifdef WITH_XAR 00317 fd->xar = rpmxarFree(fd->xar, "fdFini"); 00318 #endif 00319 #ifdef WITH_NEON 00320 #ifndef NOTYET 00321 if (fd->req != NULL) 00322 fprintf(stderr, "*** %s: fd->req %p\n", __FUNCTION__, fd->req); 00323 fd->req = NULL; 00324 #else 00325 assert(fd->req == NULL); 00326 #endif 00327 #endif 00328 fd->dig = pgpDigFree(fd->dig); 00329 /*@=onlytrans@*/ 00330 } 00331 00332 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00333 rpmioPool _fdPool; 00334 00335 static FD_t fdGetPool(/*@null@*/ rpmioPool pool) 00336 /*@globals _fdPool, fileSystem @*/ 00337 /*@modifies pool, _fdPool, fileSystem @*/ 00338 { 00339 FD_t fd; 00340 00341 if (_fdPool == NULL) { 00342 _fdPool = rpmioNewPool("fd", sizeof(*fd), -1, _rpmio_debug, 00343 (char * (*)(void *))fdbg, NULL, fdFini); 00344 pool = _fdPool; 00345 } 00346 fd = (FD_t) rpmioGetPool(pool, sizeof(*fd)); 00347 memset(((char *)fd)+sizeof(fd->_item), 0, sizeof(*fd)-sizeof(fd->_item)); 00348 return fd; 00349 } 00350 00351 /*@-incondefs@*/ 00352 /*@null@*/ 00353 FD_t XfdNew(const char * msg, const char * fn, unsigned ln) 00354 { 00355 FD_t fd = fdGetPool(_fdPool); 00356 if (fd == NULL) /* XXX xmalloc never returns NULL */ 00357 return NULL; 00358 fd->flags = 0; 00359 fd->magic = FDMAGIC; 00360 00361 fd->nfps = 0; 00362 memset(fd->fps, 0, sizeof(fd->fps)); 00363 00364 fd->fps[0].io = ufdio; 00365 fd->fps[0].fp = NULL; 00366 fd->fps[0].fdno = -1; 00367 00368 fd->u = NULL; 00369 fd->req = NULL; 00370 fd->rd_timeoutsecs = 1; /* XXX default value used to be -1 */ 00371 fd->bytesRemain = -1; 00372 fd->contentLength = -1; 00373 fd->persist = 0; 00374 fd->wr_chunked = 0; 00375 00376 fd->syserrno = 0; 00377 fd->errcookie = NULL; 00378 00379 fd->opath = NULL; 00380 fd->oflags = 0; 00381 fd->omode = 0; 00382 00383 fd->xar = NULL; 00384 fd->dig = NULL; 00385 fd->stats = xcalloc(1, sizeof(*fd->stats)); 00386 fd->ndigests = 0; 00387 fd->digests = NULL; 00388 00389 fd->contentType = NULL; 00390 fd->contentDisposition = NULL; 00391 fd->lastModified = 0; 00392 fd->ftpFileDoneNeeded = 0; 00393 fd->fd_cpioPos = 0; 00394 00395 return (FD_t)rpmioLinkPoolItem((rpmioItem)fd, msg, fn, ln); 00396 } 00397 /*@=incondefs@*/ 00398 00399 static ssize_t fdRead(void * cookie, /*@out@*/ char * buf, size_t count) 00400 /*@globals errno, fileSystem, internalState @*/ 00401 /*@modifies buf, errno, fileSystem, internalState @*/ 00402 /*@requires maxSet(buf) >= (count - 1) @*/ 00403 { 00404 FD_t fd = c2f(cookie); 00405 ssize_t rc; 00406 00407 if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */ 00408 00409 fdstat_enter(fd, FDSTAT_READ); 00410 /* HACK: flimsy wiring for davRead */ 00411 if (fd->req != NULL) { 00412 #ifdef WITH_NEON 00413 if (fd->req != (void *)-1) 00414 rc = davRead(fd, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count)); 00415 else 00416 rc = -1; 00417 #else 00418 rc = -1; 00419 #endif 00420 /* XXX Chunked davRead EOF. */ 00421 if (rc == 0) 00422 fd->bytesRemain = 0; 00423 } else 00424 if (fd->xar != NULL) { 00425 #ifdef WITH_XAR 00426 rc = xarRead(fd, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count)); 00427 #else 00428 rc = -1; 00429 #endif 00430 } else 00431 rc = read(fdFileno(fd), buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count)); 00432 fdstat_exit(fd, FDSTAT_READ, rc); 00433 00434 if (fd->ndigests > 0 && rc > 0) fdUpdateDigests(fd, (void *)buf, rc); 00435 00436 DBGIO(fd, (stderr, "<--\tfdRead(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd))); 00437 00438 return rc; 00439 } 00440 00441 static ssize_t fdWrite(void * cookie, const char * buf, size_t count) 00442 /*@globals errno, fileSystem, internalState @*/ 00443 /*@modifies errno, fileSystem, internalState @*/ 00444 { 00445 FD_t fd = c2f(cookie); 00446 int fdno = fdFileno(fd); 00447 ssize_t rc; 00448 00449 if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */ 00450 00451 if (fd->ndigests > 0 && count > 0) fdUpdateDigests(fd, (void *)buf, count); 00452 00453 if (count == 0) return 0; 00454 00455 fdstat_enter(fd, FDSTAT_WRITE); 00456 /* HACK: flimsy wiring for davWrite */ 00457 if (fd->req != NULL) 00458 #ifdef WITH_NEON 00459 if (fd->req != (void *)-1) 00460 rc = davWrite(fd, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count)); 00461 else 00462 rc = -1; 00463 #else 00464 rc = -1; 00465 #endif 00466 else 00467 rc = write(fdno, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count)); 00468 fdstat_exit(fd, FDSTAT_WRITE, rc); 00469 00470 DBGIO(fd, (stderr, "<--\tfdWrite(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd))); 00471 00472 return rc; 00473 } 00474 00475 static int fdSeek(void * cookie, _libio_pos_t pos, int whence) 00476 /*@globals fileSystem, internalState @*/ 00477 /*@modifies fileSystem, internalState @*/ 00478 { 00479 #ifdef USE_COOKIE_SEEK_POINTER 00480 _IO_off64_t p = *pos; 00481 #else 00482 off_t p = pos; 00483 #endif 00484 FD_t fd = c2f(cookie); 00485 off_t rc; 00486 00487 assert(fd->bytesRemain == -1); /* XXX FIXME fadio only for now */ 00488 fdstat_enter(fd, FDSTAT_SEEK); 00489 rc = lseek(fdFileno(fd), p, whence); 00490 fdstat_exit(fd, FDSTAT_SEEK, rc); 00491 00492 DBGIO(fd, (stderr, "<--\tfdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd))); 00493 00494 return (int) rc; 00495 } 00496 00497 static int fdClose( /*@only@*/ void * cookie) 00498 /*@globals errno, fileSystem, systemState, internalState @*/ 00499 /*@modifies errno, fileSystem, systemState, internalState @*/ 00500 { 00501 FD_t fd; 00502 int fdno; 00503 int rc; 00504 00505 if (cookie == NULL) return -2; 00506 fd = c2f(cookie); 00507 fdno = fdFileno(fd); 00508 00509 fdSetFdno(fd, -1); 00510 00511 fdstat_enter(fd, FDSTAT_CLOSE); 00512 /* HACK: flimsy wiring for davClose */ 00513 if (fd->req != NULL) 00514 #ifdef WITH_NEON 00515 rc = davClose(fd); 00516 #else 00517 rc = -1; 00518 #endif 00519 else 00520 rc = ((fdno >= 0) ? close(fdno) : -2); 00521 fdstat_exit(fd, FDSTAT_CLOSE, rc); 00522 00523 DBGIO(fd, (stderr, "<--\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd))); 00524 00525 fd = fdFree(fd, "open (fdClose)"); 00526 return rc; 00527 } 00528 00529 static /*@null@*/ FD_t fdOpen(const char *path, int flags, mode_t mode) 00530 /*@globals errno, fileSystem, internalState @*/ 00531 /*@modifies errno, fileSystem, internalState @*/ 00532 { 00533 FD_t fd; 00534 int fdno; 00535 00536 fdno = open(path, flags, mode); 00537 if (fdno < 0) return NULL; 00538 if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) { 00539 (void) close(fdno); 00540 return NULL; 00541 } 00542 fd = fdNew("open (fdOpen)"); 00543 fdSetOpen(fd, path, flags, mode); 00544 fdSetFdno(fd, fdno); 00545 assert(fd != NULL); 00546 fd->flags = flags; 00547 DBGIO(fd, (stderr, "<--\tfdOpen(\"%s\",%x,0%o) %s\n", path, (unsigned)flags, (unsigned)mode, fdbg(fd))); 00548 /*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/ 00549 } 00550 00551 #ifdef NOTUSED 00552 FILE *fdFdopen(void * cookie, const char *fmode) 00553 { 00554 FD_t fd = c2f(cookie); 00555 int fdno; 00556 FILE * fp; 00557 00558 if (fmode == NULL) return NULL; 00559 fdno = fdFileno(fd); 00560 if (fdno < 0) return NULL; 00561 fp = fdopen(fdno, fmode); 00562 DBGIO(fd, (stderr, "<-- fdFdopen(%p,\"%s\") fdno %d -> fp %p fdno %d\n", cookie, fmode, fdno, fp, fileno(fp))); 00563 fd = fdFree(fd, "open (fdFdopen)"); 00564 return fp; 00565 } 00566 #endif 00567 00568 /*@-type@*/ /* LCL: function typedefs */ 00569 static struct FDIO_s fdio_s = { 00570 fdRead, fdWrite, fdSeek, fdClose, NULL, NULL, NULL, 00571 }; 00572 /*@=type@*/ 00573 00574 FDIO_t fdio = /*@-compmempass@*/ &fdio_s /*@=compmempass@*/ ; 00575 00576 int fdWritable(FD_t fd, int secs) 00577 { 00578 int fdno; 00579 int rc; 00580 #if defined(HAVE_POLL_H) 00581 int msecs = (secs >= 0 ? (1000 * secs) : -1); 00582 struct pollfd wrfds; 00583 #else 00584 struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL); 00585 fd_set wrfds; 00586 FD_ZERO(&wrfds); 00587 #endif 00588 00589 /* HACK: flimsy wiring for davWrite */ 00590 if (fd->req != NULL) 00591 return (fd->req == (void *)-1 ? -1 : 1); 00592 00593 if ((fdno = fdFileno(fd)) < 0) 00594 return -1; /* XXX W2DO? */ 00595 00596 do { 00597 #if defined(HAVE_POLL_H) 00598 wrfds.fd = fdno; 00599 wrfds.events = POLLOUT; 00600 wrfds.revents = 0; 00601 rc = poll(&wrfds, 1, msecs); 00602 #else 00603 if (tvp) { 00604 tvp->tv_sec = secs; 00605 tvp->tv_usec = 0; 00606 } 00607 FD_SET(fdno, &wrfds); 00608 /*@-compdef -nullpass@*/ 00609 rc = select(fdno + 1, NULL, &wrfds, NULL, tvp); 00610 /*@=compdef =nullpass@*/ 00611 #endif 00612 00613 /* HACK: EBADF on PUT chunked termination from ufdClose. */ 00614 if (_rpmio_debug && !(rc == 1 && errno == 0)) 00615 fprintf(stderr, "*** fdWritable fdno %d rc %d %s\n", fdno, rc, strerror(errno)); 00616 if (rc < 0) { 00617 switch (errno) { 00618 case EINTR: 00619 continue; 00620 /*@notreached@*/ /*@switchbreak@*/ break; 00621 default: 00622 return rc; 00623 /*@notreached@*/ /*@switchbreak@*/ break; 00624 } 00625 } 00626 return rc; 00627 } while (1); 00628 /*@notreached@*/ 00629 } 00630 00631 int fdReadable(FD_t fd, int secs) 00632 { 00633 int fdno; 00634 int rc; 00635 #if defined(HAVE_POLL_H) 00636 int msecs = (secs >= 0 ? (1000 * secs) : -1); 00637 struct pollfd rdfds; 00638 #else 00639 struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL); 00640 fd_set rdfds; 00641 FD_ZERO(&rdfds); 00642 #endif 00643 00644 /* HACK: flimsy wiring for davRead */ 00645 if (fd->req != NULL) 00646 return (fd->req == (void *)-1 ? -1 : 1); 00647 00648 if ((fdno = fdFileno(fd)) < 0) 00649 return -1; /* XXX W2DO? */ 00650 00651 do { 00652 #if defined(HAVE_POLL_H) 00653 rdfds.fd = fdno; 00654 rdfds.events = POLLIN; 00655 rdfds.revents = 0; 00656 rc = poll(&rdfds, 1, msecs); 00657 #else 00658 if (tvp) { 00659 tvp->tv_sec = secs; 00660 tvp->tv_usec = 0; 00661 } 00662 FD_SET(fdno, &rdfds); 00663 /*@-compdef -nullpass@*/ 00664 rc = select(fdno + 1, &rdfds, NULL, NULL, tvp); 00665 /*@=compdef =nullpass@*/ 00666 #endif 00667 00668 if (rc < 0) { 00669 switch (errno) { 00670 case EINTR: 00671 continue; 00672 /*@notreached@*/ /*@switchbreak@*/ break; 00673 default: 00674 return rc; 00675 /*@notreached@*/ /*@switchbreak@*/ break; 00676 } 00677 } 00678 return rc; 00679 } while (1); 00680 /*@notreached@*/ 00681 } 00682 00683 int fdFgets(FD_t fd, char * buf, size_t len) 00684 { 00685 int fdno; 00686 int secs = fd->rd_timeoutsecs; 00687 size_t nb = 0; 00688 int ec = 0; 00689 char lastchar = '\0'; 00690 00691 if ((fdno = fdFileno(fd)) < 0) 00692 return 0; /* XXX W2DO? */ 00693 00694 do { 00695 int rc; 00696 00697 /* Is there data to read? */ 00698 rc = fdReadable(fd, secs); 00699 00700 switch (rc) { 00701 case -1: /* error */ 00702 ec = -1; 00703 continue; 00704 /*@notreached@*/ /*@switchbreak@*/ break; 00705 case 0: /* timeout */ 00706 ec = -1; 00707 continue; 00708 /*@notreached@*/ /*@switchbreak@*/ break; 00709 default: /* data to read */ 00710 /*@switchbreak@*/ break; 00711 } 00712 00713 errno = 0; 00714 #ifdef NOISY 00715 rc = fdRead(fd, buf + nb, 1); 00716 #else 00717 rc = (int)read(fdFileno(fd), buf + nb, 1); 00718 #endif 00719 if (rc < 0) { 00720 fd->syserrno = errno; 00721 switch (errno) { 00722 case EWOULDBLOCK: 00723 continue; 00724 /*@notreached@*/ /*@switchbreak@*/ break; 00725 default: 00726 /*@switchbreak@*/ break; 00727 } 00728 if (_rpmio_debug) 00729 fprintf(stderr, "*** read: fd %p rc %d errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf); 00730 ec = -1; 00731 break; 00732 } else if (rc == 0) { 00733 if (_rpmio_debug) 00734 fprintf(stderr, "*** read: fd %p rc %d EOF errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf); 00735 break; 00736 } else { 00737 nb += rc; 00738 buf[nb] = '\0'; 00739 lastchar = buf[nb - 1]; 00740 } 00741 } while (ec == 0 && nb < len && lastchar != '\n'); 00742 00743 return (ec >= 0 ? (int)nb : ec); 00744 } 00745 00746 /* =============================================================== */ 00747 /* Support for FTP/HTTP I/O. 00748 */ 00749 const char * ftpStrerror(int errorNumber) 00750 { 00751 switch (errorNumber) { 00752 case 0: 00753 return _("Success"); 00754 00755 /* HACK error impediance match, coalesce and rename. */ 00756 case FTPERR_NE_ERROR: 00757 return ("NE_ERROR: Generic error."); 00758 case FTPERR_NE_LOOKUP: 00759 return ("NE_LOOKUP: Hostname lookup failed."); 00760 case FTPERR_NE_AUTH: 00761 return ("NE_AUTH: Server authentication failed."); 00762 case FTPERR_NE_PROXYAUTH: 00763 return ("NE_PROXYAUTH: Proxy authentication failed."); 00764 case FTPERR_NE_CONNECT: 00765 return ("NE_CONNECT: Could not connect to server."); 00766 case FTPERR_NE_TIMEOUT: 00767 return ("NE_TIMEOUT: Connection timed out."); 00768 case FTPERR_NE_FAILED: 00769 return ("NE_FAILED: The precondition failed."); 00770 case FTPERR_NE_RETRY: 00771 return ("NE_RETRY: Retry request."); 00772 case FTPERR_NE_REDIRECT: 00773 return ("NE_REDIRECT: Redirect received."); 00774 00775 case FTPERR_BAD_SERVER_RESPONSE: 00776 return _("Bad server response"); 00777 case FTPERR_SERVER_IO_ERROR: 00778 return _("Server I/O error"); 00779 case FTPERR_SERVER_TIMEOUT: 00780 return _("Server timeout"); 00781 case FTPERR_BAD_HOST_ADDR: 00782 return _("Unable to lookup server host address"); 00783 case FTPERR_BAD_HOSTNAME: 00784 return _("Unable to lookup server host name"); 00785 case FTPERR_FAILED_CONNECT: 00786 return _("Failed to connect to server"); 00787 case FTPERR_FAILED_DATA_CONNECT: 00788 return _("Failed to establish data connection to server"); 00789 case FTPERR_FILE_IO_ERROR: 00790 return _("I/O error to local file"); 00791 case FTPERR_PASSIVE_ERROR: 00792 return _("Error setting remote server to passive mode"); 00793 case FTPERR_FILE_NOT_FOUND: 00794 return _("File not found on server"); 00795 case FTPERR_NIC_ABORT_IN_PROGRESS: 00796 return _("Abort in progress"); 00797 00798 case FTPERR_UNKNOWN: 00799 default: 00800 return _("Unknown or unexpected error"); 00801 } 00802 } 00803 00804 const char *urlStrerror(const char *url) 00805 { 00806 const char *retstr; 00807 switch (urlIsURL(url)) { 00808 case URL_IS_HKP: 00809 case URL_IS_FTP: 00810 case URL_IS_HTTP: 00811 case URL_IS_HTTPS: 00812 { urlinfo u; 00813 /* XXX This only works for httpReq/ftpLogin/ftpReq failures */ 00814 if (urlSplit(url, &u) == 0) 00815 retstr = ftpStrerror(u->openError); 00816 else 00817 retstr = _("Malformed URL"); 00818 } break; 00819 case URL_IS_MONGO: /* XXX FIXME */ 00820 default: 00821 retstr = strerror(errno); 00822 break; 00823 } 00824 return retstr; 00825 } 00826 00827 #if !defined(HAVE_GETADDRINFO) 00828 #if !defined(USE_ALT_DNS) || !USE_ALT_DNS 00829 static int mygethostbyname(const char * host, 00830 /*@out@*/ struct in_addr * address) 00831 /*@globals h_errno @*/ 00832 /*@modifies *address @*/ 00833 { 00834 struct hostent * hostinfo; 00835 00836 /*@-multithreaded @*/ 00837 hostinfo = gethostbyname(host); 00838 /*@=multithreaded @*/ 00839 if (!hostinfo) return 1; 00840 00841 memcpy(address, hostinfo->h_addr_list[0], sizeof(*address)); 00842 return 0; 00843 } 00844 #endif 00845 00846 /*@-compdef@*/ /* FIX: address->s_addr undefined. */ 00847 static int getHostAddress(const char * host, /*@out@*/ struct in_addr * address) 00848 /*@globals errno, h_errno @*/ 00849 /*@modifies *address, errno @*/ 00850 { 00851 #if 0 /* XXX workaround nss_foo module hand-off using valgrind. */ 00852 if (!strcmp(host, "localhost")) { 00853 /*@-moduncon @*/ 00854 if (!inet_aton("127.0.0.1", address)) 00855 return FTPERR_BAD_HOST_ADDR; 00856 /*@=moduncon @*/ 00857 } else 00858 #endif 00859 if (xisdigit(host[0])) { 00860 /*@-moduncon @*/ 00861 if (!inet_aton(host, address)) 00862 return FTPERR_BAD_HOST_ADDR; 00863 /*@=moduncon @*/ 00864 } else { 00865 if (mygethostbyname(host, address)) { 00866 errno = h_errno; 00867 return FTPERR_BAD_HOSTNAME; 00868 } 00869 } 00870 00871 return 0; 00872 } 00873 /*@=compdef@*/ 00874 #endif /* HAVE_GETADDRINFO */ 00875 00876 static int tcpConnect(FD_t ctrl, const char * host, int port) 00877 /*@globals fileSystem, internalState @*/ 00878 /*@modifies ctrl, fileSystem, internalState @*/ 00879 { 00880 int fdno = -1; 00881 int rc; 00882 #ifdef HAVE_GETADDRINFO 00883 /*@-unrecog@*/ 00884 struct addrinfo hints, *res, *res0; 00885 #ifndef NI_MAXSERV 00886 #define NI_MAXSERV 32 00887 #endif 00888 char pbuf[NI_MAXSERV]; 00889 int xx; 00890 00891 memset(&hints, 0, sizeof(hints)); 00892 hints.ai_family = AF_UNSPEC; 00893 hints.ai_socktype = SOCK_STREAM; 00894 sprintf(pbuf, "%d", port); 00895 pbuf[sizeof(pbuf)-1] = '\0'; 00896 rc = FTPERR_FAILED_CONNECT; 00897 if (getaddrinfo(host, pbuf, &hints, &res0) == 0) { 00898 for (res = res0; res != NULL; res = res->ai_next) { 00899 if ((fdno = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) 00900 continue; 00901 if (connect(fdno, res->ai_addr, (int)res->ai_addrlen) < 0) { 00902 xx = close(fdno); 00903 continue; 00904 } 00905 /* success */ 00906 rc = 0; 00907 if (_ftp_debug) { 00908 char hbuf[NI_MAXHOST]; 00909 hbuf[0] = '\0'; 00910 xx = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 00911 NULL, 0, NI_NUMERICHOST); 00912 fprintf(stderr,"++ connect [%s]:%d on fdno %d\n", 00913 /*@-unrecog@*/ hbuf /*@=unrecog@*/, port, fdno); 00914 } 00915 break; 00916 } 00917 freeaddrinfo(res0); 00918 } 00919 if (rc < 0) 00920 goto errxit; 00921 /*@=unrecog@*/ 00922 #else /* HAVE_GETADDRINFO */ 00923 struct sockaddr_in sin; 00924 00925 memset(&sin, 0, sizeof(sin)); 00926 sin.sin_family = AF_INET; 00927 sin.sin_port = htons(port); 00928 sin.sin_addr.s_addr = INADDR_ANY; 00929 00930 do { 00931 if ((rc = getHostAddress(host, &sin.sin_addr)) < 0) 00932 break; 00933 00934 if ((fdno = socket(sin.sin_family, SOCK_STREAM, IPPROTO_IP)) < 0) { 00935 rc = FTPERR_FAILED_CONNECT; 00936 break; 00937 } 00938 00939 /*@-internalglobs@*/ 00940 if (connect(fdno, (struct sockaddr *) &sin, sizeof(sin))) { 00941 rc = FTPERR_FAILED_CONNECT; 00942 break; 00943 } 00944 /*@=internalglobs@*/ 00945 } while (0); 00946 00947 if (rc < 0) 00948 goto errxit; 00949 00950 if (_ftp_debug) 00951 fprintf(stderr,"++ connect %s:%d on fdno %d\n", 00952 /*@-unrecog -moduncon -evalorderuncon @*/ 00953 inet_ntoa(sin.sin_addr) 00954 /*@=unrecog =moduncon =evalorderuncon @*/ , 00955 (int)ntohs(sin.sin_port), fdno); 00956 #endif /* HAVE_GETADDRINFO */ 00957 00958 fdSetFdno(ctrl, (fdno >= 0 ? fdno : -1)); 00959 return 0; 00960 00961 errxit: 00962 /*@-observertrans@*/ 00963 fdSetSyserrno(ctrl, errno, ftpStrerror(rc)); 00964 /*@=observertrans@*/ 00965 if (fdno >= 0) 00966 (void) close(fdno); 00967 return rc; 00968 } 00969 00970 static int checkResponse(void * uu, FD_t ctrl, 00971 /*@out@*/ int *ecp, /*@out@*/ char ** str) 00972 /*@globals fileSystem @*/ 00973 /*@modifies ctrl, *ecp, *str, fileSystem @*/ 00974 { 00975 urlinfo u = uu; 00976 char *buf; 00977 size_t bufAlloced; 00978 int bufLength = 0; 00979 const char *s; 00980 char *se; 00981 int ec = 0; 00982 int moretodo = 1; 00983 char errorCode[4]; 00984 00985 URLSANE(u); 00986 if (u->bufAlloced == 0 || u->buf == NULL) { 00987 u->bufAlloced = _url_iobuf_size; 00988 u->buf = xcalloc(u->bufAlloced, sizeof(u->buf[0])); 00989 } 00990 buf = u->buf; 00991 bufAlloced = u->bufAlloced; 00992 *buf = '\0'; 00993 00994 errorCode[0] = '\0'; 00995 00996 do { 00997 int rc; 00998 00999 /* 01000 * Read next line from server. 01001 */ 01002 se = buf + bufLength; 01003 *se = '\0'; 01004 rc = fdFgets(ctrl, se, (bufAlloced - bufLength)); 01005 if (rc < 0) { 01006 ec = FTPERR_BAD_SERVER_RESPONSE; 01007 continue; 01008 } else if (rc == 0 || fdWritable(ctrl, 0) < 1) 01009 moretodo = 0; 01010 01011 /* 01012 * Process next line from server. 01013 */ 01014 for (s = se; *s != '\0'; s = se) { 01015 const char *e; 01016 01017 while (*se && *se != '\n') se++; 01018 01019 if (se > s && se[-1] == '\r') 01020 se[-1] = '\0'; 01021 if (*se == '\0') 01022 /*@innerbreak@*/ break; 01023 01024 if (_ftp_debug) 01025 fprintf(stderr, "<- %s\n", s); 01026 01027 /* HTTP: header termination on empty line */ 01028 if (*s == '\0') { 01029 moretodo = 0; 01030 /*@innerbreak@*/ break; 01031 } 01032 *se++ = '\0'; 01033 01034 /* HTTP: look for "HTTP/1.1 123 ..." */ 01035 if (!strncmp(s, "HTTP", sizeof("HTTP")-1)) { 01036 ctrl->contentLength = -1; 01037 if ((e = strchr(s, '.')) != NULL) { 01038 e++; 01039 u->httpVersion = (int)(*e - '0'); 01040 if (u->httpVersion < 1 || u->httpVersion > 2) 01041 ctrl->persist = u->httpVersion = 0; 01042 else 01043 ctrl->persist = 1; 01044 } 01045 if ((e = strchr(s, ' ')) != NULL) { 01046 e++; 01047 if (strchr("0123456789", *e)) 01048 strncpy(errorCode, e, 3); 01049 errorCode[3] = '\0'; 01050 } 01051 /*@innercontinue@*/ continue; 01052 } 01053 01054 /* HTTP: look for "token: ..." */ 01055 for (e = s; *e && !(*e == ' ' || *e == ':'); e++) 01056 {}; 01057 if (e > s && *e++ == ':') { 01058 size_t ne = (e - s); 01059 while (*e && *e == ' ') e++; 01060 #if 0 01061 if (!strncmp(s, "Date:", ne)) { 01062 } else 01063 if (!strncmp(s, "Server:", ne)) { 01064 } else 01065 if (!strncmp(s, "Last-Modified:", ne)) { 01066 } else 01067 if (!strncmp(s, "ETag:", ne)) { 01068 } else 01069 #endif 01070 if (!strncmp(s, "Accept-Ranges:", ne)) { 01071 if (!strcmp(e, "bytes")) 01072 u->allow |= RPMURL_SERVER_HASRANGE; 01073 if (!strcmp(e, "none")) 01074 u->allow &= ~RPMURL_SERVER_HASRANGE; 01075 } else 01076 if (!strncmp(s, "Content-Length:", ne)) { 01077 if (strchr("0123456789", *e)) 01078 ctrl->contentLength = atol(e); 01079 } else 01080 if (!strncmp(s, "Connection:", ne)) { 01081 if (!strcmp(e, "close")) 01082 ctrl->persist = 0; 01083 } 01084 #if 0 01085 else 01086 if (!strncmp(s, "Content-Type:", ne)) { 01087 } else 01088 if (!strncmp(s, "Transfer-Encoding:", ne)) { 01089 if (!strcmp(e, "chunked")) 01090 ctrl->wr_chunked = 1; 01091 else 01092 ctrl->wr_chunked = 0; 01093 } else 01094 if (!strncmp(s, "Allow:", ne)) { 01095 } 01096 #endif 01097 /*@innercontinue@*/ continue; 01098 } 01099 01100 /* HTTP: look for "<TITLE>501 ... </TITLE>" */ 01101 if (!strncmp(s, "<TITLE>", sizeof("<TITLE>")-1)) 01102 s += sizeof("<TITLE>") - 1; 01103 01104 /* FTP: look for "123-" and/or "123 " */ 01105 if (strchr("0123456789", *s)) { 01106 if (errorCode[0] != '\0') { 01107 if (!strncmp(s, errorCode, sizeof("123")-1) && s[3] == ' ') 01108 moretodo = 0; 01109 } else { 01110 strncpy(errorCode, s, sizeof("123")-1); 01111 errorCode[3] = '\0'; 01112 if (s[3] != '-') 01113 moretodo = 0; 01114 } 01115 } 01116 } 01117 01118 if (moretodo && se > s) { 01119 bufLength = se - s - 1; 01120 if (s != buf) 01121 memmove(buf, s, bufLength); 01122 } else { 01123 bufLength = 0; 01124 } 01125 } while (moretodo && ec == 0); 01126 01127 if (str) *str = buf; 01128 if (ecp) *ecp = atoi(errorCode); 01129 01130 return ec; 01131 } 01132 01133 static int ftpCheckResponse(urlinfo u, /*@out@*/ char ** str) 01134 /*@globals fileSystem @*/ 01135 /*@modifies u, *str, fileSystem @*/ 01136 { 01137 int ec = 0; 01138 int rc; 01139 01140 URLSANE(u); 01141 rc = checkResponse(u, u->ctrl, &ec, str); 01142 01143 switch (ec) { 01144 case 550: 01145 return FTPERR_FILE_NOT_FOUND; 01146 /*@notreached@*/ break; 01147 case 552: 01148 return FTPERR_NIC_ABORT_IN_PROGRESS; 01149 /*@notreached@*/ break; 01150 default: 01151 if (ec >= 400 && ec <= 599) { 01152 return FTPERR_BAD_SERVER_RESPONSE; 01153 } 01154 break; 01155 } 01156 return rc; 01157 } 01158 01159 static int ftpCommand(urlinfo u, char ** str, ...) 01160 /*@globals fileSystem, internalState @*/ 01161 /*@modifies u, *str, fileSystem, internalState @*/ 01162 { 01163 va_list ap; 01164 int len = 0; 01165 const char * s, * t; 01166 char * te; 01167 int rc; 01168 01169 URLSANE(u); 01170 va_start(ap, str); 01171 while ((s = va_arg(ap, const char *)) != NULL) { 01172 if (len) len++; 01173 len += strlen(s); 01174 } 01175 len += sizeof("\r\n")-1; 01176 va_end(ap); 01177 01178 t = te = alloca(len + 1); 01179 01180 va_start(ap, str); 01181 while ((s = va_arg(ap, const char *)) != NULL) { 01182 if (te > t) *te++ = ' '; 01183 te = stpcpy(te, s); 01184 } 01185 te = stpcpy(te, "\r\n"); 01186 va_end(ap); 01187 01188 if (_ftp_debug) 01189 fprintf(stderr, "-> %s", t); 01190 if (fdWrite(u->ctrl, t, (te-t)) != (te-t)) 01191 return FTPERR_SERVER_IO_ERROR; 01192 01193 rc = ftpCheckResponse(u, str); 01194 return rc; 01195 } 01196 01197 static int ftpLogin(urlinfo u) 01198 /*@globals fileSystem, internalState @*/ 01199 /*@modifies u, fileSystem, internalState @*/ 01200 { 01201 const char * host; 01202 const char * user; 01203 const char * password; 01204 int port; 01205 int rc; 01206 01207 URLSANE(u); 01208 u->ctrl = fdLink(u->ctrl, "open ctrl"); 01209 01210 if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) { 01211 rc = FTPERR_BAD_HOSTNAME; 01212 goto errxit; 01213 } 01214 01215 if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = IPPORT_FTP; 01216 01217 if ((user = (u->proxyu ? u->proxyu : u->user)) == NULL) 01218 user = "anonymous"; 01219 01220 if ((password = u->password) == NULL) { 01221 uid_t uid = getuid(); 01222 struct passwd * pw; 01223 if (uid && (pw = getpwuid(uid)) != NULL) { 01224 char *myp = alloca(strlen(pw->pw_name) + sizeof("@")); 01225 strcpy(myp, pw->pw_name); 01226 strcat(myp, "@"); 01227 password = myp; 01228 } else { 01229 password = "root@"; 01230 } 01231 } 01232 01233 if (fdFileno(u->ctrl) >= 0 && fdWritable(u->ctrl, 0) < 1) 01234 /*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/ 01235 01236 /*@-usereleased@*/ 01237 if (fdFileno(u->ctrl) < 0) { 01238 rc = tcpConnect(u->ctrl, host, port); 01239 if (rc < 0) 01240 goto errxit2; 01241 } 01242 01243 if ((rc = ftpCheckResponse(u, NULL))) 01244 goto errxit; 01245 01246 if ((rc = ftpCommand(u, NULL, "USER", user, NULL))) 01247 goto errxit; 01248 01249 if ((rc = ftpCommand(u, NULL, "PASS", password, NULL))) 01250 goto errxit; 01251 01252 if ((rc = ftpCommand(u, NULL, "TYPE", "I", NULL))) 01253 goto errxit; 01254 01255 /*@-compdef@*/ 01256 return 0; 01257 /*@=compdef@*/ 01258 01259 errxit: 01260 /*@-observertrans@*/ 01261 fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc)); 01262 /*@=observertrans@*/ 01263 errxit2: 01264 if (fdFileno(u->ctrl) >= 0) 01265 /*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/ 01266 /*@-compdef@*/ 01267 return rc; 01268 /*@=compdef@*/ 01269 /*@=usereleased@*/ 01270 } 01271 01272 int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg) 01273 { 01274 urlinfo u = data->u; 01275 #if !defined(HAVE_GETADDRINFO) 01276 struct sockaddr_in dataAddress; 01277 #endif /* HAVE_GETADDRINFO */ 01278 char remoteIP[NI_MAXHOST]; 01279 char * cmd; 01280 size_t cmdlen; 01281 char * passReply; 01282 char * chptr; 01283 int rc; 01284 int epsv; 01285 int port; 01286 01287 remoteIP[0] = '\0'; 01288 URLSANE(u); 01289 if (ftpCmd == NULL) 01290 return FTPERR_UNKNOWN; /* XXX W2DO? */ 01291 01292 cmdlen = strlen(ftpCmd) + (ftpArg ? 1+strlen(ftpArg) : 0) + sizeof("\r\n"); 01293 chptr = cmd = alloca(cmdlen); 01294 chptr = stpcpy(chptr, ftpCmd); 01295 if (ftpArg) { 01296 *chptr++ = ' '; 01297 chptr = stpcpy(chptr, ftpArg); 01298 } 01299 chptr = stpcpy(chptr, "\r\n"); 01300 cmdlen = chptr - cmd; 01301 01302 /* 01303 * Get the ftp version of the Content-Length. 01304 */ 01305 if (!strncmp(cmd, "RETR", 4)) { 01306 unsigned cl; 01307 01308 passReply = NULL; 01309 rc = ftpCommand(u, &passReply, "SIZE", ftpArg, NULL); 01310 if (rc) 01311 goto errxit; 01312 if (sscanf(passReply, "%d %u", &rc, &cl) != 2) { 01313 rc = FTPERR_BAD_SERVER_RESPONSE; 01314 goto errxit; 01315 } 01316 rc = 0; 01317 data->contentLength = cl; 01318 } 01319 01320 epsv = 0; 01321 passReply = NULL; 01322 #ifdef HAVE_GETNAMEINFO 01323 rc = ftpCommand(u, &passReply, "EPSV", NULL); 01324 if (rc == 0) { 01325 #ifdef HAVE_GETADDRINFO 01326 struct sockaddr_storage ss; 01327 #else /* HAVE_GETADDRINFO */ 01328 struct sockaddr_in ss; 01329 #endif /* HAVE_GETADDRINFO */ 01330 socklen_t sslen = sizeof(ss); 01331 01332 /* we need to know IP of remote host */ 01333 if ((getpeername(fdFileno(c2f(u->ctrl)), (struct sockaddr *)&ss, &sslen) == 0) 01334 && (getnameinfo((struct sockaddr *)&ss, sslen, 01335 remoteIP, sizeof(remoteIP), 01336 NULL, 0, NI_NUMERICHOST) == 0)) 01337 { 01338 epsv++; 01339 } else { 01340 /* abort EPSV and fall back to PASV */ 01341 rc = ftpCommand(u, &passReply, "ABOR", NULL); 01342 if (rc) { 01343 rc = FTPERR_PASSIVE_ERROR; 01344 goto errxit; 01345 } 01346 } 01347 } 01348 if (epsv == 0) 01349 #endif /* HAVE_GETNAMEINFO */ 01350 rc = ftpCommand(u, &passReply, "PASV", NULL); 01351 if (rc) { 01352 rc = FTPERR_PASSIVE_ERROR; 01353 goto errxit; 01354 } 01355 01356 chptr = passReply; 01357 assert(chptr != NULL); 01358 while (*chptr && *chptr != '(') chptr++; 01359 if (*chptr != '(') return FTPERR_PASSIVE_ERROR; 01360 chptr++; 01361 passReply = chptr; 01362 while (*chptr && *chptr != ')') chptr++; 01363 if (*chptr != ')') return FTPERR_PASSIVE_ERROR; 01364 *chptr-- = '\0'; 01365 01366 if (epsv) { 01367 int i; 01368 if(sscanf(passReply,"%*c%*c%*c%d%*c",&i) != 1) { 01369 rc = FTPERR_PASSIVE_ERROR; 01370 goto errxit; 01371 } 01372 port = i; 01373 } else { 01374 01375 while (*chptr && *chptr != ',') chptr--; 01376 if (*chptr != ',') return FTPERR_PASSIVE_ERROR; 01377 chptr--; 01378 while (*chptr && *chptr != ',') chptr--; 01379 if (*chptr != ',') return FTPERR_PASSIVE_ERROR; 01380 *chptr++ = '\0'; 01381 01382 /* now passReply points to the IP portion, and chptr points to the 01383 port number portion */ 01384 01385 { int i, j; 01386 if (sscanf(chptr, "%d,%d", &i, &j) != 2) { 01387 rc = FTPERR_PASSIVE_ERROR; 01388 goto errxit; 01389 } 01390 port = (((unsigned)i) << 8) + j; 01391 } 01392 01393 chptr = passReply; 01394 while (*chptr++ != '\0') { 01395 if (*chptr == ',') *chptr = '.'; 01396 } 01397 sprintf(remoteIP, "%s", passReply); 01398 } /* if (epsv) */ 01399 01400 #ifdef HAVE_GETADDRINFO 01401 /*@-unrecog@*/ 01402 { 01403 struct addrinfo hints, *res, *res0; 01404 char pbuf[NI_MAXSERV]; 01405 int xx; 01406 01407 memset(&hints, 0, sizeof(hints)); 01408 hints.ai_family = AF_UNSPEC; 01409 hints.ai_socktype = SOCK_STREAM; 01410 hints.ai_flags = AI_NUMERICHOST; 01411 #if defined(AI_IDN) 01412 hints.ai_flags |= AI_IDN; 01413 #endif 01414 sprintf(pbuf, "%d", port); 01415 pbuf[sizeof(pbuf)-1] = '\0'; 01416 if (getaddrinfo(remoteIP, pbuf, &hints, &res0)) { 01417 rc = FTPERR_PASSIVE_ERROR; 01418 goto errxit; 01419 } 01420 01421 for (res = res0; res != NULL; res = res->ai_next) { 01422 rc = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 01423 fdSetFdno(data, (rc >= 0 ? rc : -1)); 01424 if (rc < 0) { 01425 if (res->ai_next) 01426 continue; 01427 else { 01428 rc = FTPERR_FAILED_CONNECT; 01429 freeaddrinfo(res0); 01430 goto errxit; 01431 } 01432 } 01433 data = fdLink(data, "open data (ftpReq)"); 01434 01435 /* XXX setsockopt SO_LINGER */ 01436 /* XXX setsockopt SO_KEEPALIVE */ 01437 /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */ 01438 01439 { 01440 int criterr = 0; 01441 while (connect(fdFileno(data), res->ai_addr, (int)res->ai_addrlen) < 0) { 01442 if (errno == EINTR) 01443 /*@innercontinue@*/ continue; 01444 criterr++; 01445 } 01446 if (criterr) { 01447 if (res->ai_addr) { 01448 /*@-refcounttrans@*/ 01449 xx = fdClose(data); 01450 /*@=refcounttrans@*/ 01451 continue; 01452 } else { 01453 rc = FTPERR_PASSIVE_ERROR; 01454 freeaddrinfo(res0); 01455 goto errxit; 01456 } 01457 } 01458 } 01459 /* success */ 01460 rc = 0; 01461 break; 01462 } 01463 freeaddrinfo(res0); 01464 } 01465 /*@=unrecog@*/ 01466 #else /* HAVE_GETADDRINFO */ 01467 memset(&dataAddress, 0, sizeof(dataAddress)); 01468 dataAddress.sin_family = AF_INET; 01469 dataAddress.sin_port = htons(port); 01470 01471 /*@-moduncon@*/ 01472 if (!inet_aton(remoteIP, &dataAddress.sin_addr)) { 01473 rc = FTPERR_PASSIVE_ERROR; 01474 goto errxit; 01475 } 01476 /*@=moduncon@*/ 01477 01478 rc = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 01479 fdSetFdno(data, (rc >= 0 ? rc : -1)); 01480 if (rc < 0) { 01481 rc = FTPERR_FAILED_CONNECT; 01482 goto errxit; 01483 } 01484 data = fdLink(data, "open data (ftpReq)"); 01485 01486 /* XXX setsockopt SO_LINGER */ 01487 /* XXX setsockopt SO_KEEPALIVE */ 01488 /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */ 01489 01490 /*@-internalglobs@*/ 01491 while (connect(fdFileno(data), (struct sockaddr *) &dataAddress, 01492 sizeof(dataAddress)) < 0) 01493 { 01494 if (errno == EINTR) 01495 continue; 01496 rc = FTPERR_FAILED_DATA_CONNECT; 01497 goto errxit; 01498 } 01499 /*@=internalglobs@*/ 01500 #endif /* HAVE_GETADDRINFO */ 01501 01502 if (_ftp_debug) 01503 fprintf(stderr, "-> %s", cmd); 01504 if ((size_t)fdWrite(u->ctrl, cmd, cmdlen) != cmdlen) { 01505 rc = FTPERR_SERVER_IO_ERROR; 01506 goto errxit; 01507 } 01508 01509 if ((rc = ftpCheckResponse(u, NULL))) { 01510 goto errxit; 01511 } 01512 01513 data->ftpFileDoneNeeded = 1; 01514 u->ctrl = fdLink(u->ctrl, "grab data (ftpReq)"); 01515 u->ctrl = fdLink(u->ctrl, "open data (ftpReq)"); 01516 return 0; 01517 01518 errxit: 01519 /*@-observertrans@*/ 01520 fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc)); 01521 /*@=observertrans@*/ 01522 if (fdFileno(data) >= 0) 01523 /*@-refcounttrans@*/ (void) fdClose(data); /*@=refcounttrans@*/ 01524 return rc; 01525 } 01526 01527 #ifdef DYING 01528 /*@unchecked@*/ /*@null@*/ 01529 static rpmCallbackFunction _urlNotify = NULL; 01530 01531 /*@unchecked@*/ /*@null@*/ 01532 static void * _urlNotifyData = NULL; 01533 01534 /*@unchecked@*/ 01535 static int _urlNotifyCount = -1; 01536 01537 static void urlSetCallback(rpmCallbackFunction notify, void *notifyData, int notifyCount) { 01538 _urlNotify = notify; 01539 _urlNotifyData = notifyData; 01540 _urlNotifyCount = (notifyCount >= 0) ? notifyCount : 4096; 01541 } 01542 #endif 01543 01544 int ufdCopy(FD_t sfd, FD_t tfd) 01545 { 01546 char buf[BUFSIZ]; 01547 int itemsRead; 01548 int itemsCopied = 0; 01549 int rc = 0; 01550 #ifdef DYING 01551 int notifier = -1; 01552 01553 if (_urlNotify) { 01554 /*@-noeffectuncon @*/ /* FIX: check rc */ 01555 (void)(*_urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE, 01556 0, 0, NULL, _urlNotifyData); 01557 /*@=noeffectuncon @*/ 01558 } 01559 #endif 01560 01561 while (1) { 01562 rc = (int) Fread(buf, sizeof(buf[0]), sizeof(buf), sfd); 01563 if (rc < 0) /* XXX never happens Fread returns size_t */ 01564 break; 01565 else if (rc == 0) { 01566 rc = itemsCopied; 01567 break; 01568 } 01569 itemsRead = rc; 01570 rc = (int) Fwrite(buf, sizeof(buf[0]), itemsRead, tfd); 01571 if (rc < 0) /* XXX never happens Fwrite returns size_t */ 01572 break; 01573 if (rc != itemsRead) { 01574 rc = FTPERR_FILE_IO_ERROR; 01575 break; 01576 } 01577 01578 itemsCopied += itemsRead; 01579 #ifdef DYING 01580 if (_urlNotify && _urlNotifyCount > 0) { 01581 int n = itemsCopied/_urlNotifyCount; 01582 if (n != notifier) { 01583 /*@-noeffectuncon @*/ /* FIX: check rc */ 01584 (void)(*_urlNotify) (NULL, RPMCALLBACK_INST_PROGRESS, 01585 itemsCopied, 0, NULL, _urlNotifyData); 01586 /*@=noeffectuncon @*/ 01587 notifier = n; 01588 } 01589 } 01590 #endif 01591 } 01592 01593 DBGIO(sfd, (stderr, "++ copied %d bytes: %s\n", itemsCopied, 01594 ftpStrerror(rc))); 01595 01596 #ifdef DYING 01597 if (_urlNotify) { 01598 /*@-noeffectuncon @*/ /* FIX: check rc */ 01599 (void)(*_urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE, 01600 itemsCopied, itemsCopied, NULL, _urlNotifyData); 01601 /*@=noeffectuncon @*/ 01602 } 01603 #endif 01604 01605 return rc; 01606 } 01607 01608 static int urlConnect(const char * url, /*@out@*/ urlinfo * uret) 01609 /*@globals h_errno, fileSystem, internalState @*/ 01610 /*@modifies *uret, fileSystem, internalState @*/ 01611 { 01612 urlinfo u; 01613 int rc = 0; 01614 01615 if (urlSplit(url, &u) < 0) 01616 return -1; 01617 01618 if (urlType(u) == URL_IS_FTP) { 01619 FD_t fd; 01620 01621 if ((fd = u->ctrl) == NULL) { 01622 fd = u->ctrl = fdNew("persist ctrl (urlConnect FTP)"); 01623 /*@-usereleased@*/ 01624 fdSetOpen(u->ctrl, url, 0, 0); 01625 fdSetIo(u->ctrl, ufdio); 01626 /*@=usereleased@*/ 01627 } 01628 01629 assert(fd != NULL); 01630 fd->rd_timeoutsecs = ftpTimeoutSecs; 01631 fd->contentLength = fd->bytesRemain = -1; 01632 fd->u = NULL; /* XXX FTP ctrl has not */ 01633 fd->ftpFileDoneNeeded = 0; 01634 fd = fdLink(fd, "grab ctrl (urlConnect FTP)"); 01635 01636 if (fdFileno(u->ctrl) < 0) { 01637 rpmlog(RPMLOG_DEBUG, D_("logging into %s as %s, pw %s\n"), 01638 u->host ? u->host : "???", 01639 u->user ? u->user : "ftp", 01640 u->password ? u->password : "(username)"); 01641 01642 if ((rc = ftpLogin(u)) < 0) { /* XXX save ftpLogin error */ 01643 u->ctrl = fdFree(fd, "grab ctrl (urlConnect FTP)"); 01644 u->openError = rc; 01645 } 01646 } 01647 } 01648 01649 if (uret != NULL) 01650 *uret = urlLink(u, "urlConnect"); 01651 u = urlFree(u, "urlSplit (urlConnect)"); 01652 01653 return rc; 01654 } 01655 01656 int ufdGetFile(FD_t sfd, FD_t tfd) 01657 { 01658 int rc; 01659 01660 FDSANE(sfd); 01661 FDSANE(tfd); 01662 rc = ufdCopy(sfd, tfd); 01663 (void) Fclose(sfd); 01664 if (rc > 0) /* XXX ufdCopy now returns no. bytes copied */ 01665 rc = 0; 01666 return rc; 01667 } 01668 01669 int ftpCmd(const char * cmd, const char * url, const char * arg2) 01670 { 01671 urlinfo u; 01672 int rc; 01673 const char * path; 01674 01675 if (urlConnect(url, &u) < 0) 01676 return -1; 01677 01678 (void) urlPath(url, &path); 01679 01680 rc = ftpCommand(u, NULL, cmd, path, arg2, NULL); 01681 u->ctrl = fdFree(u->ctrl, "grab ctrl (ftpCmd)"); 01682 return rc; 01683 } 01684 01685 /* XXX these aren't worth the pain of including correctly */ 01686 #if !defined(IAC) 01687 #define IAC ((unsigned char)255) /* interpret as command: */ 01688 #endif 01689 #if !defined(IP) 01690 #define IP ((unsigned char)244) /* interrupt process--permanently */ 01691 #endif 01692 #if !defined(DM) 01693 #define DM ((unsigned char)242) /* data mark--for connect. cleaning */ 01694 #endif 01695 #if !defined(SHUT_RDWR) 01696 #define SHUT_RDWR 1+1 01697 #endif 01698 01699 static int ftpAbort(urlinfo u, FD_t data) 01700 /*@globals fileSystem, internalState @*/ 01701 /*@modifies u, data, fileSystem, internalState @*/ 01702 { 01703 static unsigned char ipbuf[3] = { IAC, IP, IAC }; 01704 FD_t ctrl; 01705 int rc; 01706 int tosecs; 01707 01708 URLSANE(u); 01709 01710 if (data != NULL) { 01711 data->ftpFileDoneNeeded = 0; 01712 if (fdFileno(data) >= 0) 01713 u->ctrl = fdFree(u->ctrl, "open data (ftpAbort)"); 01714 u->ctrl = fdFree(u->ctrl, "grab data (ftpAbort)"); 01715 } 01716 ctrl = u->ctrl; 01717 01718 DBGIO(0, (stderr, "-> ABOR\n")); 01719 01720 /*@-usereleased -compdef@*/ 01721 if (send(fdFileno(ctrl), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) { 01722 /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/ 01723 return FTPERR_SERVER_IO_ERROR; 01724 } 01725 01726 sprintf(u->buf, "%cABOR\r\n",(char) DM); 01727 if (fdWrite(ctrl, u->buf, 7) != 7) { 01728 /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/ 01729 return FTPERR_SERVER_IO_ERROR; 01730 } 01731 01732 if (data && fdFileno(data) >= 0) { 01733 /* XXX shorten data drain time wait */ 01734 tosecs = data->rd_timeoutsecs; 01735 data->rd_timeoutsecs = 10; 01736 if (fdReadable(data, data->rd_timeoutsecs) > 0) { 01737 /*@-infloopsuncon@*/ 01738 while ((ufdio->read)(data, u->buf, u->bufAlloced) > 0) 01739 u->buf[0] = '\0'; 01740 /*@=infloopsuncon@*/ 01741 } 01742 data->rd_timeoutsecs = tosecs; 01743 /* XXX ftp abort needs to close the data channel to receive status */ 01744 (void) shutdown(fdFileno(data), SHUT_RDWR); 01745 (void) close(fdFileno(data)); 01746 data->fps[0].fdno = -1; /* XXX WRONG but expedient */ 01747 } 01748 01749 /* XXX shorten ctrl drain time wait */ 01750 assert(u->ctrl != NULL); 01751 tosecs = u->ctrl->rd_timeoutsecs; 01752 u->ctrl->rd_timeoutsecs = 10; 01753 if ((rc = ftpCheckResponse(u, NULL)) == FTPERR_NIC_ABORT_IN_PROGRESS) { 01754 rc = ftpCheckResponse(u, NULL); 01755 } 01756 rc = ftpCheckResponse(u, NULL); 01757 u->ctrl->rd_timeoutsecs = tosecs; 01758 01759 return rc; 01760 /*@=usereleased =compdef@*/ 01761 } 01762 01763 static int ftpFileDone(urlinfo u, FD_t data) 01764 /*@globals fileSystem @*/ 01765 /*@modifies u, data, fileSystem @*/ 01766 { 01767 int rc = 0; 01768 01769 URLSANE(u); 01770 assert(data->ftpFileDoneNeeded); 01771 01772 if (data->ftpFileDoneNeeded) { 01773 data->ftpFileDoneNeeded = 0; 01774 u->ctrl = fdFree(u->ctrl, "open data (ftpFileDone)"); 01775 u->ctrl = fdFree(u->ctrl, "grab data (ftpFileDone)"); 01776 rc = ftpCheckResponse(u, NULL); 01777 } 01778 return rc; 01779 } 01780 01781 #ifndef WITH_NEON 01782 static int httpResp(urlinfo u, FD_t ctrl, /*@out@*/ char ** str) 01783 /*@globals fileSystem @*/ 01784 /*@modifies ctrl, *str, fileSystem @*/ 01785 { 01786 int ec = 0; 01787 int rc; 01788 01789 URLSANE(u); 01790 rc = checkResponse(u, ctrl, &ec, str); 01791 01792 if (_ftp_debug && !(rc == 0 && (ec == 200 || ec == 201))) 01793 fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec); 01794 01795 switch (ec) { 01796 case 200: 01797 case 201: /* 201 Created. */ 01798 break; 01799 case 204: /* HACK: if overwriting, 204 No Content. */ 01800 case 403: /* 403 Forbidden. */ 01801 ctrl->syserrno = EACCES; /* HACK */ 01802 rc = FTPERR_UNKNOWN; 01803 break; 01804 default: 01805 rc = FTPERR_FILE_NOT_FOUND; 01806 break; 01807 } 01808 return rc; 01809 } 01810 01811 static int httpReq(FD_t ctrl, const char * httpCmd, const char * httpArg) 01812 /*@globals h_errno, fileSystem, internalState @*/ 01813 /*@modifies ctrl, fileSystem, internalState @*/ 01814 { 01815 urlinfo u; 01816 const char * host; 01817 const char * path; 01818 char hthost[NI_MAXHOST]; 01819 int port; 01820 int rc; 01821 char * req; 01822 size_t len; 01823 int retrying = 0; 01824 01825 assert(ctrl != NULL); 01826 u = ctrl->u; 01827 URLSANE(u); 01828 01829 if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) 01830 return FTPERR_BAD_HOSTNAME; 01831 if (strchr(host, ':')) 01832 sprintf(hthost, "[%s]", host); 01833 else 01834 strcpy(hthost, host); 01835 01836 if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80; 01837 path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg; 01838 if (path == NULL) path = ""; 01839 01840 reopen: 01841 if (fdFileno(ctrl) >= 0 && (rc = fdWritable(ctrl, 0)) < 1) { 01842 /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/ 01843 } 01844 01845 /*@-usereleased@*/ 01846 if (fdFileno(ctrl) < 0) { 01847 rc = tcpConnect(ctrl, host, port); 01848 if (rc < 0) 01849 goto errxit2; 01850 ctrl = fdLink(ctrl, "open ctrl (httpReq)"); 01851 } 01852 01853 len = sizeof("\ 01854 req x HTTP/1.0\r\n\ 01855 User-Agent: rpm/3.0.4\r\n\ 01856 Host: y:z\r\n\ 01857 Accept: text/plain\r\n\ 01858 Transfer-Encoding: chunked\r\n\ 01859 \r\n\ 01860 ") + strlen(httpCmd) + strlen(path) + sizeof(VERSION) + strlen(hthost) + 20; 01861 01862 req = alloca(len); 01863 *req = '\0'; 01864 01865 if (!strcmp(httpCmd, "PUT")) { 01866 sprintf(req, "\ 01867 %s %s HTTP/1.%d\r\n\ 01868 User-Agent: rpm/%s\r\n\ 01869 Host: %s:%d\r\n\ 01870 Accept: text/plain\r\n\ 01871 Transfer-Encoding: chunked\r\n\ 01872 \r\n\ 01873 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, hthost, port); 01874 } else { 01875 sprintf(req, "\ 01876 %s %s HTTP/1.%d\r\n\ 01877 User-Agent: rpm/%s\r\n\ 01878 Host: %s:%d\r\n\ 01879 Accept: text/plain\r\n\ 01880 \r\n\ 01881 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, hthost, port); 01882 } 01883 01884 if (_ftp_debug) 01885 fprintf(stderr, "-> %s", req); 01886 01887 len = strlen(req); 01888 if (fdWrite(ctrl, req, len) != (ssize_t)len) { 01889 rc = FTPERR_SERVER_IO_ERROR; 01890 goto errxit; 01891 } 01892 01893 if (!strcmp(httpCmd, "PUT")) { 01894 ctrl->wr_chunked = 1; 01895 } else { 01896 01897 rc = httpResp(u, ctrl, NULL); 01898 01899 if (rc) { 01900 if (!retrying) { /* not HTTP_OK */ 01901 retrying = 1; 01902 /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/ 01903 goto reopen; 01904 } 01905 goto errxit; 01906 } 01907 } 01908 01909 ctrl = fdLink(ctrl, "open data (httpReq)"); 01910 return 0; 01911 01912 errxit: 01913 /*@-observertrans@*/ 01914 fdSetSyserrno(ctrl, errno, ftpStrerror(rc)); 01915 /*@=observertrans@*/ 01916 errxit2: 01917 if (fdFileno(ctrl) >= 0) 01918 /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/ 01919 return rc; 01920 /*@=usereleased@*/ 01921 } 01922 #endif /* WITH_NEON */ 01923 01924 /* XXX DYING: unused */ 01925 void * ufdGetUrlinfo(FD_t fd) 01926 { 01927 FDSANE(fd); 01928 if (fd->u == NULL) 01929 return NULL; 01930 /*@-retexpose@*/ 01931 return urlLink(fd->u, "ufdGetUrlinfo"); 01932 /*@=retexpose@*/ 01933 } 01934 01935 /* =============================================================== */ 01936 static ssize_t ufdRead(void * cookie, /*@out@*/ char * buf, size_t count) 01937 /*@globals fileSystem, internalState @*/ 01938 /*@modifies buf, fileSystem, internalState @*/ 01939 /*@requires maxSet(buf) >= (count - 1) @*/ 01940 { 01941 FD_t fd = c2f(cookie); 01942 size_t bytesRead; 01943 size_t total; 01944 01945 if (fdGetIo(fd) == fdio) { 01946 struct stat sb; 01947 int fdno = fdFileno(fd); 01948 (void) fstat(fdno, &sb); 01949 if (S_ISREG(sb.st_mode)) 01950 return fdRead(fd, buf, count); 01951 } 01952 01953 UFDONLY(fd); 01954 assert(fd->rd_timeoutsecs >= 0); 01955 01956 for (total = 0; total < count; total += bytesRead) { 01957 01958 int rc; 01959 01960 bytesRead = 0; 01961 01962 /* Is there data to read? */ 01963 if (fd->bytesRemain == 0) return (ssize_t) total; /* XXX simulate EOF */ 01964 rc = fdReadable(fd, fd->rd_timeoutsecs); 01965 01966 switch (rc) { 01967 case -1: /* error */ 01968 case 0: /* timeout */ 01969 return (ssize_t) total; 01970 /*@notreached@*/ /*@switchbreak@*/ break; 01971 default: /* data to read */ 01972 /*@switchbreak@*/ break; 01973 } 01974 01975 rc = (int) fdRead(fd, buf + total, count - total); 01976 01977 if (rc < 0) { 01978 switch (errno) { 01979 case EWOULDBLOCK: 01980 continue; 01981 /*@notreached@*/ /*@switchbreak@*/ break; 01982 default: 01983 /*@switchbreak@*/ break; 01984 } 01985 if (_rpmio_debug) 01986 fprintf(stderr, "*** read: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf); 01987 return rc; 01988 /*@notreached@*/ break; 01989 } else if (rc == 0) { 01990 return (ssize_t) total; 01991 /*@notreached@*/ break; 01992 } 01993 bytesRead = (size_t) rc; 01994 } 01995 01996 return (ssize_t) count; 01997 } 01998 01999 static ssize_t ufdWrite(void * cookie, const char * buf, size_t count) 02000 /*@globals fileSystem, internalState @*/ 02001 /*@modifies fileSystem, internalState @*/ 02002 { 02003 FD_t fd = c2f(cookie); 02004 size_t bytesWritten; 02005 size_t total = 0; 02006 02007 #ifdef NOTYET 02008 if (fdGetIo(fd) == fdio) { 02009 struct stat sb; 02010 (void) fstat(fdGetFdno(fd), &sb); 02011 if (S_ISREG(sb.st_mode)) 02012 return fdWrite(fd, buf, count); 02013 } 02014 #endif 02015 02016 UFDONLY(fd); 02017 02018 for (total = 0; total < count; total += bytesWritten) { 02019 02020 int rc; 02021 02022 bytesWritten = 0; 02023 02024 /* Is there room to write data? */ 02025 if (fd->bytesRemain == 0) { 02026 fprintf(stderr, "*** ufdWrite fd %p WRITE PAST END OF CONTENT\n", fd); 02027 return (ssize_t) total; /* XXX simulate EOF */ 02028 } 02029 rc = fdWritable(fd, 2); /* XXX configurable? */ 02030 02031 switch (rc) { 02032 case -1: /* error */ 02033 case 0: /* timeout */ 02034 return (ssize_t) total; 02035 /*@notreached@*/ /*@switchbreak@*/ break; 02036 default: /* data to write */ 02037 /*@switchbreak@*/ break; 02038 } 02039 02040 rc = (int) fdWrite(fd, buf + total, count - total); 02041 02042 if (rc < 0) { 02043 switch (errno) { 02044 case EWOULDBLOCK: 02045 continue; 02046 /*@notreached@*/ /*@switchbreak@*/ break; 02047 default: 02048 /*@switchbreak@*/ break; 02049 } 02050 if (_rpmio_debug) 02051 fprintf(stderr, "*** write: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf); 02052 return rc; 02053 /*@notreached@*/ break; 02054 } else if (rc == 0) { 02055 return (ssize_t) total; 02056 /*@notreached@*/ break; 02057 } 02058 bytesWritten = (size_t) rc; 02059 } 02060 02061 return (ssize_t) count; 02062 } 02063 02064 static int ufdSeek(void * cookie, _libio_pos_t pos, int whence) 02065 /*@globals fileSystem, internalState @*/ 02066 /*@modifies fileSystem, internalState @*/ 02067 { 02068 FD_t fd = c2f(cookie); 02069 02070 switch (urlType(fd->u)) { 02071 case URL_IS_UNKNOWN: 02072 case URL_IS_PATH: 02073 break; 02074 case URL_IS_DASH: 02075 case URL_IS_HKP: 02076 case URL_IS_FTP: 02077 case URL_IS_HTTP: 02078 case URL_IS_HTTPS: 02079 case URL_IS_MONGO: /* XXX FIXME */ 02080 default: 02081 return -2; 02082 /*@notreached@*/ break; 02083 } 02084 return fdSeek(cookie, pos, whence); 02085 } 02086 02087 /*@-usereleased@*/ /* LCL: fd handling is tricky here. */ 02088 int ufdClose( /*@only@*/ void * cookie) 02089 { 02090 FD_t fd = c2f(cookie); 02091 02092 UFDONLY(fd); 02093 02094 if (fd->u) { 02095 urlinfo u = fd->u; 02096 02097 /*@-evalorder @*/ 02098 if (fd == u->data) 02099 fd = u->data = fdFree(fd, "grab data (ufdClose persist)"); 02100 else 02101 fd = fdFree(fd, "grab data (ufdClose)"); 02102 assert(fd != NULL); 02103 (void) urlFree(fd->u, "url (ufdClose)"); 02104 fd->u = NULL; 02105 u->ctrl = fdFree(u->ctrl, "grab ctrl (ufdClose)"); 02106 /*@=evalorder @*/ 02107 02108 if (urlType(u) == URL_IS_FTP) { 02109 02110 /* XXX if not using libio, lose the fp from fpio */ 02111 { FILE * fp; 02112 /*@+voidabstract -nullpass@*/ 02113 fp = fdGetFILE(fd); 02114 if (noLibio && fp) 02115 fdSetFp(fd, NULL); 02116 /*@=voidabstract =nullpass@*/ 02117 } 02118 02119 /* 02120 * Non-error FTP has 4 refs on the data fd: 02121 * "persist data (ufdOpen FTP)" rpmio.c:888 02122 * "grab data (ufdOpen FTP)" rpmio.c:892 02123 * "open data (ftpReq)" ftp.c:633 02124 * "fopencookie" rpmio.c:1507 02125 * 02126 * Non-error FTP has 5 refs on the ctrl fd: 02127 * "persist ctrl" url.c:176 02128 * "grab ctrl (urlConnect FTP)" rpmio.c:404 02129 * "open ctrl" ftp.c:504 02130 * "grab data (ftpReq)" ftp.c:661 02131 * "open data (ftpReq)" ftp.c:662 02132 */ 02133 if (fd->bytesRemain > 0) { 02134 if (fd->ftpFileDoneNeeded) { 02135 if (fdReadable(u->ctrl, 0) > 0) 02136 (void) ftpFileDone(u, fd); 02137 else 02138 (void) ftpAbort(u, fd); 02139 } 02140 } else { 02141 int rc; 02142 /* XXX STOR et al require close before ftpFileDone */ 02143 /*@-refcounttrans@*/ 02144 rc = fdClose(fd); 02145 /*@=refcounttrans@*/ 02146 #if 0 /* XXX error exit from ufdOpen does not have this set */ 02147 assert(fd->ftpFileDoneNeeded != 0); 02148 #endif 02149 /*@-compdef@*/ /* FIX: u->data undefined */ 02150 if (fd->ftpFileDoneNeeded) 02151 (void) ftpFileDone(u, fd); 02152 /*@=compdef@*/ 02153 return rc; 02154 } 02155 } 02156 02157 /* XXX Why not (u->urltype == URL_IS_HTTP) ??? */ 02158 /* XXX Why not (u->urltype == URL_IS_HTTPS) ??? */ 02159 /* XXX Why not (u->urltype == URL_IS_HKP) ??? */ 02160 if (u->scheme != NULL 02161 && (!strncmp(u->scheme, "http", sizeof("http")-1) || !strncmp(u->scheme, "hkp", sizeof("hkp")-1))) 02162 { 02163 /* 02164 * HTTP has 4 (or 5 if persistent malloc) refs on the fd: 02165 * "persist ctrl" url.c:177 02166 * "grab ctrl (ufdOpen HTTP)" rpmio.c:924 02167 * "grab data (ufdOpen HTTP)" rpmio.c:928 02168 * "open ctrl (httpReq)" ftp.c:382 02169 * "open data (httpReq)" ftp.c:435 02170 */ 02171 02172 /*@-evalorder @*/ 02173 if (fd == u->ctrl) 02174 fd = u->ctrl = fdFree(fd, "open data (ufdClose HTTP persist ctrl)"); 02175 else if (fd == u->data) 02176 fd = u->data = fdFree(fd, "open data (ufdClose HTTP persist data)"); 02177 else 02178 fd = fdFree(fd, "open data (ufdClose HTTP)"); 02179 /*@=evalorder @*/ 02180 02181 /* XXX if not using libio, lose the fp from fpio */ 02182 { FILE * fp; 02183 /*@+voidabstract -nullpass@*/ 02184 fp = fdGetFILE(fd); 02185 if (noLibio && fp) 02186 fdSetFp(fd, NULL); 02187 /*@=voidabstract =nullpass@*/ 02188 } 02189 02190 /* If content remains, then don't persist. */ 02191 assert(fd != NULL); 02192 if (fd->bytesRemain > 0) { 02193 fd->persist = 0; 02194 } 02195 fd->contentLength = fd->bytesRemain = -1; 02196 02197 /* If persisting, then Fclose will juggle refcounts. */ 02198 if (fd->persist && (fd == u->ctrl || fd == u->data)) 02199 return 0; 02200 } 02201 } 02202 return fdClose(fd); 02203 } 02204 /*@=usereleased@*/ 02205 02206 /*@-nullstate@*/ /* FIX: u->{ctrl,data}->u undef after XurlLink. */ 02207 /*@null@*/ FD_t ftpOpen(const char *url, /*@unused@*/ int flags, 02208 /*@unused@*/ mode_t mode, /*@out@*/ urlinfo *uret) 02209 /*@modifies *uret @*/ 02210 { 02211 urlinfo u = NULL; 02212 FD_t fd = NULL; 02213 02214 #if 0 /* XXX makeTempFile() heartburn */ 02215 assert(!(flags & O_RDWR)); 02216 #endif 02217 if (urlConnect(url, &u) < 0) 02218 goto exit; 02219 02220 if (u->data == NULL) 02221 u->data = fdNew("persist data (ftpOpen)"); 02222 02223 assert(u->data != NULL); 02224 /*@-unqualifiedtrans@*/ 02225 if (u->data->u == NULL) 02226 fd = u->data = fdLink(u->data, "grab data (ftpOpen persist data)"); 02227 else 02228 fd = fdNew("grab data (ftpOpen)"); 02229 /*@=unqualifiedtrans@*/ 02230 02231 if (fd != NULL) { 02232 fdSetOpen(fd, url, flags, mode); 02233 fdSetIo(fd, ufdio); 02234 fd->ftpFileDoneNeeded = 0; 02235 fd->rd_timeoutsecs = ftpTimeoutSecs; 02236 fd->contentLength = fd->bytesRemain = -1; 02237 /*@-usereleased@*/ 02238 fd->u = urlLink(u, "url (ufdOpen FTP)"); 02239 /*@=usereleased@*/ 02240 } 02241 02242 exit: 02243 if (uret) 02244 *uret = u; 02245 /*@-refcounttrans@*/ 02246 return fd; 02247 /*@=refcounttrans@*/ 02248 } 02249 /*@=nullstate@*/ 02250 02251 static /*@null@*/ FD_t ufdOpen(const char * url, int flags, mode_t mode) 02252 /*@globals h_errno, fileSystem, internalState @*/ 02253 /*@modifies fileSystem, internalState @*/ 02254 { 02255 FD_t fd = NULL; 02256 const char * cmd; 02257 urlinfo u; 02258 const char * path; 02259 urltype ut = urlPath(url, &path); 02260 02261 if (_rpmio_debug) 02262 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode); 02263 02264 /*@-usereleased@*/ 02265 switch (ut) { 02266 case URL_IS_FTP: 02267 fd = ftpOpen(url, flags, mode, &u); 02268 if (fd == NULL || u == NULL) 02269 break; 02270 02271 /* XXX W2DO? use STOU rather than STOR to prevent clobbering */ 02272 cmd = ((flags & O_WRONLY) 02273 ? ((flags & O_APPEND) ? "APPE" : 02274 ((flags & O_CREAT) ? "STOR" : "STOR")) 02275 : ((flags & O_CREAT) ? "STOR" : "RETR")); 02276 u->openError = ftpReq(fd, cmd, path); 02277 if (u->openError < 0) { 02278 /* XXX make sure that we can exit through ufdClose */ 02279 fd = fdLink(fd, "error data (ufdOpen FTP)"); 02280 } else { 02281 fd->bytesRemain = ((!strcmp(cmd, "RETR")) 02282 ? fd->contentLength : -1); 02283 fd->wr_chunked = 0; 02284 } 02285 break; 02286 case URL_IS_HKP: 02287 case URL_IS_HTTP: 02288 case URL_IS_HTTPS: 02289 #ifdef WITH_NEON 02290 fd = davOpen(url, flags, mode, &u); 02291 #else 02292 fd = httpOpen(url, flags, mode, &u); 02293 #endif 02294 if (fd == NULL || u == NULL) 02295 break; 02296 02297 cmd = ((flags & O_WRONLY) 02298 ? ((flags & O_APPEND) ? "PUT" : 02299 ((flags & O_CREAT) ? "PUT" : "PUT")) 02300 : "GET"); 02301 #ifdef WITH_NEON 02302 u->openError = davReq(fd, cmd, path); 02303 #else 02304 u->openError = httpReq(fd, cmd, path); 02305 #endif 02306 if (u->openError < 0) { 02307 /* XXX make sure that we can exit through ufdClose */ 02308 fd = fdLink(fd, "error ctrl (ufdOpen HTTP)"); 02309 fd = fdLink(fd, "error data (ufdOpen HTTP)"); 02310 } else { 02311 fd->bytesRemain = ((!strcmp(cmd, "GET")) 02312 ? fd->contentLength : -1); 02313 fd->wr_chunked = ((!strcmp(cmd, "PUT")) 02314 ? fd->wr_chunked : 0); 02315 } 02316 break; 02317 case URL_IS_MONGO: /* XXX FIXME */ 02318 break; 02319 case URL_IS_DASH: 02320 assert(!(flags & O_RDWR)); 02321 fd = fdDup( ((flags & O_WRONLY) ? STDOUT_FILENO : STDIN_FILENO) ); 02322 if (fd) { 02323 fdSetOpen(fd, url, flags, mode); 02324 fdSetIo(fd, ufdio); 02325 fd->rd_timeoutsecs = 600; /* XXX W2DO? 10 mins? */ 02326 fd->contentLength = fd->bytesRemain = -1; 02327 } 02328 break; 02329 case URL_IS_PATH: 02330 case URL_IS_UNKNOWN: 02331 default: 02332 fd = fdOpen(path, flags, mode); 02333 if (fd) { 02334 fdSetIo(fd, ufdio); 02335 fd->rd_timeoutsecs = 1; 02336 fd->contentLength = fd->bytesRemain = -1; 02337 } 02338 break; 02339 } 02340 02341 if (fd == NULL) return NULL; 02342 if (Fileno(fd) < 0) { 02343 (void) ufdClose(fd); 02344 return NULL; 02345 } 02346 /*@=usereleased@*/ 02347 DBGIO(fd, (stderr, "<--\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd))); 02348 return fd; 02349 } 02350 02351 /*@-type@*/ /* LCL: function typedefs */ 02352 static struct FDIO_s ufdio_s = { 02353 ufdRead, ufdWrite, ufdSeek, ufdClose, NULL, NULL, NULL, 02354 }; 02355 /*@=type@*/ 02356 02357 FDIO_t ufdio = /*@-compmempass@*/ &ufdio_s /*@=compmempass@*/ ; 02358 02359 /* =============================================================== */ 02360 /*@observer@*/ 02361 static const char * getFdErrstr (FD_t fd) 02362 /*@*/ 02363 { 02364 const char *errstr = NULL; 02365 02366 #if defined(WITH_ZLIB) 02367 if (fdGetIo(fd) == gzdio) { 02368 errstr = fd->errcookie; 02369 } else 02370 #endif /* WITH_ZLIB */ 02371 02372 #if defined(WITH_BZIP2) 02373 if (fdGetIo(fd) == bzdio) { 02374 errstr = fd->errcookie; 02375 } else 02376 #endif 02377 02378 #if defined(WITH_XZ) 02379 if (fdGetIo(fd) == lzdio) { 02380 errstr = fd->errcookie; 02381 } else 02382 if (fdGetIo(fd) == xzdio) { 02383 errstr = fd->errcookie; 02384 } else 02385 #endif 02386 02387 { 02388 errstr = (fd->syserrno ? strerror(fd->syserrno) : ""); 02389 } 02390 02391 return errstr; 02392 } 02393 02394 /* =============================================================== */ 02395 02396 const char *Fstrerror(FD_t fd) 02397 { 02398 if (fd == NULL) 02399 return (errno ? strerror(errno) : ""); 02400 FDSANE(fd); 02401 return getFdErrstr(fd); 02402 } 02403 02404 #define FDIOVEC(_fd, _vec) \ 02405 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL) 02406 02407 size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) { 02408 fdio_read_function_t _read; 02409 int rc; 02410 02411 FDSANE(fd); 02412 DBGIO(fd, (stderr, "==> Fread(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd))); 02413 02414 if (fdGetIo(fd) == fpio) { 02415 /*@+voidabstract -nullpass@*/ 02416 rc = (int) fread(buf, size, nmemb, fdGetFILE(fd)); 02417 /*@=voidabstract =nullpass@*/ 02418 return (size_t) rc; 02419 } 02420 02421 /*@-nullderef@*/ 02422 _read = FDIOVEC(fd, read); 02423 /*@=nullderef@*/ 02424 02425 rc = (int) (_read ? (*_read) (fd, buf, size * nmemb) : -2); 02426 return (size_t) rc; 02427 } 02428 02429 size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd) 02430 { 02431 fdio_write_function_t _write; 02432 int rc; 02433 02434 FDSANE(fd); 02435 DBGIO(fd, (stderr, "==> Fwrite(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd))); 02436 02437 if (fdGetIo(fd) == fpio) { 02438 /*@+voidabstract -nullpass@*/ 02439 rc = (int) fwrite(buf, size, nmemb, fdGetFILE(fd)); 02440 /*@=voidabstract =nullpass@*/ 02441 return (size_t) rc; 02442 } 02443 02444 /*@-nullderef@*/ 02445 _write = FDIOVEC(fd, write); 02446 /*@=nullderef@*/ 02447 02448 rc = (int) (_write ? _write(fd, buf, size * nmemb) : -2); 02449 return (size_t) rc; 02450 } 02451 02452 int Fseek(FD_t fd, _libio_off_t offset, int whence) 02453 { 02454 fdio_seek_function_t _seek; 02455 #ifdef USE_COOKIE_SEEK_POINTER 02456 _IO_off64_t o64 = offset; 02457 _libio_pos_t pos = &o64; 02458 #else 02459 _libio_pos_t pos = offset; 02460 #endif 02461 02462 long int rc; 02463 02464 FDSANE(fd); 02465 DBGIO(fd, (stderr, "==> Fseek(%p,%ld,%d) %s\n", fd, (long)offset, whence, fdbg(fd))); 02466 02467 if (fdGetIo(fd) == fpio) 02468 return fseek(fdGetFILE(fd), (long)offset, whence); 02469 02470 /*@-nullderef@*/ 02471 _seek = FDIOVEC(fd, seek); 02472 /*@=nullderef@*/ 02473 02474 rc = (_seek ? _seek(fd, pos, whence) : -2); 02475 return rc; 02476 } 02477 02478 long Ftell(FD_t fd) 02479 { 02480 long int rc = -2; 02481 02482 FDSANE(fd); 02483 02484 if (fdGetIo(fd) == fpio) 02485 rc = ftell(fdGetFILE(fd)); 02486 else 02487 errno = EBADF; 02488 DBGIO(fd, (stderr, "<== Ftell(%p) rc %ld %s\n", fd, rc, fdbg(fd))); 02489 return rc; 02490 } 02491 02492 void Rewind(FD_t fd) 02493 { 02494 FDSANE(fd); 02495 DBGIO(fd, (stderr, "==> Rewind(%p) %s\n", fd, fdbg(fd))); 02496 02497 if (fdGetIo(fd) == fpio) 02498 rewind(fdGetFILE(fd)); 02499 } 02500 02501 int Fgetpos(FD_t fd, fpos_t *pos) 02502 { 02503 int rc = -2; 02504 02505 FDSANE(fd); 02506 02507 if (fdGetIo(fd) == fpio) 02508 rc = fgetpos(fdGetFILE(fd), pos); 02509 else 02510 errno = EBADF; 02511 DBGIO(fd, (stderr, "<== Fgetpos(%p,%p) rc %d %s\n", fd, pos, rc, fdbg(fd))); 02512 return rc; 02513 } 02514 02515 int Fsetpos(FD_t fd, fpos_t *pos) 02516 { 02517 int rc = -2; 02518 02519 FDSANE(fd); 02520 02521 if (fdGetIo(fd) == fpio) 02522 return fgetpos(fdGetFILE(fd), pos); 02523 02524 errno = EBADF; 02525 DBGIO(fd, (stderr, "<== Fsetpos(%p,%p) rc %d %s\n", fd, pos, rc, fdbg(fd))); 02526 return rc; 02527 } 02528 02529 int Fclose(FD_t fd) 02530 { 02531 int rc = 0, ec = 0; 02532 02533 FDSANE(fd); 02534 DBGIO(fd, (stderr, "==> Fclose(%p) %s\n", (fd ? fd : NULL), fdbg(fd))); 02535 02536 /*@-usereleased@*/ 02537 fd = fdLink(fd, "Fclose"); 02538 if (fd != NULL) 02539 while (fd->nfps >= 0) { 02540 FDSTACK_t * fps = &fd->fps[fd->nfps]; 02541 02542 if (fps->io == fpio) { 02543 FILE *fp; 02544 int fpno; 02545 02546 /*@+voidabstract -nullpass@*/ 02547 fp = fdGetFILE(fd); 02548 fpno = fileno(fp); 02549 /*@=voidabstract =nullpass@*/ 02550 /* XXX persistent HTTP/1.1 returns the previously opened fp */ 02551 if (fd->nfps > 0 && fpno == -1 && 02552 fd->fps[fd->nfps-1].io == ufdio && 02553 fd->fps[fd->nfps-1].fp == fp && 02554 (fd->fps[fd->nfps-1].fdno >= 0 || fd->req != NULL)) 02555 { 02556 int hadreqpersist = (fd->req != NULL); 02557 02558 if (fp) 02559 rc = fflush(fp); 02560 fd->nfps--; 02561 /*@-refcounttrans@*/ 02562 rc = ufdClose(fd); 02563 /*@=refcounttrans@*/ 02564 if (fdGetFdno(fd) >= 0) 02565 break; 02566 if (!fd->persist) 02567 hadreqpersist = 0; 02568 fdSetFp(fd, NULL); 02569 fd->nfps++; 02570 if (fp) { 02571 /* HACK: flimsy Keepalive wiring. */ 02572 if (hadreqpersist) { 02573 #ifdef NOTYET /* XXX not quite right yet. */ 02574 (void) davDisconnect(fd); 02575 fd->req = NULL; 02576 #endif 02577 fd->nfps--; 02578 /*@-exposetrans@*/ 02579 fdSetFp(fd, fp); 02580 /*@=exposetrans@*/ 02581 /*@-refcounttrans@*/ 02582 (void) fdClose(fd); 02583 /*@=refcounttrans@*/ 02584 fdSetFp(fd, NULL); 02585 fd->nfps++; 02586 /*@-refcounttrans@*/ 02587 (void) fdClose(fd); 02588 /*@=refcounttrans@*/ 02589 } else 02590 rc = fclose(fp); 02591 } 02592 fdPop(fd); 02593 if (noLibio) 02594 fdSetFp(fd, NULL); 02595 } else { 02596 if (fp) 02597 rc = fclose(fp); 02598 if (fpno == -1) { 02599 fd = fdFree(fd, "fopencookie (Fclose)"); 02600 fdPop(fd); 02601 } 02602 } 02603 } else { 02604 /*@-nullderef@*/ 02605 fdio_close_function_t _close = FDIOVEC(fd, close); 02606 /*@=nullderef@*/ 02607 rc = _close(fd); 02608 } 02609 if (fd == NULL || fd->nfps == 0) /* XXX fd != NULL ever */ 02610 break; 02611 if (ec == 0 && rc) 02612 ec = rc; 02613 fdPop(fd); 02614 } 02615 fd = fdFree(fd, "Fclose"); 02616 return ec; 02617 /*@=usereleased@*/ 02618 } 02619 02637 static inline void cvtfmode (const char *m, 02638 /*@out@*/ char *stdio, size_t nstdio, 02639 /*@out@*/ char *other, size_t nother, 02640 /*@out@*/ const char **end, /*@out@*/ int * f) 02641 /*@modifies *stdio, *other, *end, *f @*/ 02642 { 02643 int flags = 0; 02644 char c; 02645 02646 switch (*m) { 02647 case 'a': 02648 flags |= O_WRONLY | O_CREAT | O_APPEND; 02649 if (--nstdio > 0) *stdio++ = *m; 02650 break; 02651 case 'w': 02652 flags |= O_WRONLY | O_CREAT | O_TRUNC; 02653 if (--nstdio > 0) *stdio++ = *m; 02654 break; 02655 case 'r': 02656 flags |= O_RDONLY; 02657 if (--nstdio > 0) *stdio++ = *m; 02658 break; 02659 default: 02660 *stdio = '\0'; 02661 return; 02662 /*@notreached@*/ break; 02663 } 02664 m++; 02665 02666 while ((c = *m++) != '\0') { 02667 switch (c) { 02668 case '.': 02669 /*@switchbreak@*/ break; 02670 case '+': 02671 flags &= ~(O_RDONLY|O_WRONLY); 02672 flags |= O_RDWR; 02673 if (--nstdio > 0) *stdio++ = c; 02674 continue; 02675 /*@notreached@*/ /*@switchbreak@*/ break; 02676 case 'x': /* glibc: open file exclusively. */ 02677 flags |= O_EXCL; 02678 /*@fallthrough@*/ 02679 case 'm': /* glibc: mmap'd reads */ 02680 case 'c': /* glibc: no cancel */ 02681 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3 02682 if (--nstdio > 0) *stdio++ = c; 02683 #endif 02684 continue; 02685 /*@notreached@*/ /*@switchbreak@*/ break; 02686 case 'b': 02687 if (--nstdio > 0) *stdio++ = c; 02688 continue; 02689 /*@notreached@*/ /*@switchbreak@*/ break; 02690 default: 02691 if (--nother > 0) *other++ = c; 02692 continue; 02693 /*@notreached@*/ /*@switchbreak@*/ break; 02694 } 02695 break; 02696 } 02697 if (c == '\0') m--; /* one too far */ 02698 02699 *stdio = *other = '\0'; 02700 if (end != NULL) 02701 *end = (*m != '\0' ? m : NULL); 02702 if (f != NULL) 02703 *f = flags; 02704 } 02705 02706 #if _USE_LIBIO 02707 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0 02708 /* XXX retrofit glibc-2.1.x typedef on glibc-2.0.x systems */ 02709 typedef _IO_cookie_io_functions_t cookie_io_functions_t; 02710 #endif 02711 #endif 02712 02713 FD_t Fdopen(FD_t ofd, const char *fmode) 02714 { 02715 char stdio[20], other[20], zstdio[40+1]; 02716 const char *end = NULL; 02717 FDIO_t iof = NULL; 02718 FD_t fd = ofd; 02719 02720 if (_rpmio_debug) 02721 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd)); 02722 FDSANE(fd); 02723 02724 if (fmode == NULL) 02725 return NULL; 02726 02727 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL); 02728 if (stdio[0] == '\0') 02729 return NULL; 02730 zstdio[0] = '\0'; 02731 (void) stpcpy( stpcpy(zstdio, stdio), other); 02732 02733 if (end == NULL && other[0] == '\0') 02734 /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/ 02735 02736 if (end && *end) { 02737 if (!strcmp(end, "fdio")) { 02738 iof = fdio; 02739 #if defined(WITH_ZLIB) 02740 } else if (!strcmp(end, "gzdio")) { 02741 iof = gzdio; 02742 /*@-internalglobs@*/ 02743 fd = iof->_fdopen(fd, zstdio); 02744 /*@=internalglobs@*/ 02745 #endif 02746 #if defined(WITH_BZIP2) 02747 } else if (!strcmp(end, "bzdio")) { 02748 iof = bzdio; 02749 /*@-internalglobs@*/ 02750 fd = iof->_fdopen(fd, zstdio); 02751 /*@=internalglobs@*/ 02752 #endif 02753 #if defined(WITH_XZ) 02754 } else if (!strcmp(end, "lzdio")) { 02755 iof = lzdio; 02756 fd = iof->_fdopen(fd, zstdio); 02757 } else if (!strcmp(end, "xzdio")) { 02758 iof = xzdio; 02759 fd = iof->_fdopen(fd, zstdio); 02760 #endif 02761 } else if (!strcmp(end, "ufdio")) { 02762 iof = ufdio; 02763 } else if (!strcmp(end, "fpio")) { 02764 iof = fpio; 02765 if (noLibio) { 02766 int fdno = Fileno(fd); 02767 FILE * fp = fdopen(fdno, stdio); 02768 /*@+voidabstract -nullpass@*/ 02769 if (_rpmio_debug) 02770 fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp); 02771 /*@=voidabstract =nullpass@*/ 02772 if (fp == NULL) 02773 return NULL; 02774 /* XXX gzdio/bzdio use fp for private data */ 02775 /*@+voidabstract@*/ 02776 if (fdGetFp(fd) == NULL) 02777 fdSetFp(fd, fp); 02778 fdPush(fd, fpio, fp, fdno); /* Push fpio onto stack */ 02779 /*@=voidabstract@*/ 02780 } 02781 } 02782 } else if (other[0] != '\0') { 02783 for (end = other; *end && strchr("0123456789fh", *end); end++) 02784 {}; 02785 if (*end == '\0') { 02786 #if defined(WITH_ZLIB) 02787 iof = gzdio; 02788 /*@-internalglobs@*/ 02789 fd = iof->_fdopen(fd, zstdio); 02790 /*@=internalglobs@*/ 02791 #endif 02792 } 02793 } 02794 if (iof == NULL) 02795 /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/ 02796 02797 if (!noLibio) { 02798 FILE * fp = NULL; 02799 02800 #if _USE_LIBIO 02801 { cookie_io_functions_t ciof; 02802 ciof.read = iof->read; 02803 ciof.write = iof->write; 02804 ciof.seek = iof->seek; 02805 ciof.close = iof->close; 02806 fp = fopencookie(fd, stdio, ciof); 02807 DBGIO(fd, (stderr, "<-- fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp)); 02808 } 02809 #endif 02810 02811 if (fp) { 02812 /* XXX gzdio/bzdio use fp for private data */ 02813 /*@+voidabstract -nullpass@*/ 02814 if (fdGetFp(fd) == NULL) 02815 fdSetFp(fd, fp); 02816 fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */ 02817 /*@=voidabstract =nullpass@*/ 02818 fd = fdLink(fd, "fopencookie"); 02819 } 02820 } 02821 02822 /*@-refcounttrans -retalias -usereleased @*/ 02823 DBGIO(fd, (stderr, "<== Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd))); 02824 return fd; 02825 /*@=refcounttrans =retalias =usereleased @*/ 02826 } 02827 02828 FD_t Fopen(const char *path, const char *_fmode) 02829 { 02830 const char * fmode = NULL; 02831 char stdio[20], other[20]; 02832 const char *end = NULL; 02833 mode_t perms = 0666; 02834 int flags = 0; 02835 FD_t fd = NULL; 02836 02837 if (path == NULL || _fmode == NULL) 02838 goto exit; 02839 /*@-globs -mods@*/ 02840 fmode = rpmExpand(_fmode, NULL); 02841 /*@=globs =mods@*/ 02842 02843 if (_rpmio_debug) 02844 fprintf(stderr, "==> Fopen(%s, %s)\n", path, fmode); 02845 02846 stdio[0] = '\0'; 02847 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags); 02848 if (stdio[0] == '\0') 02849 goto exit; 02850 02851 if (end == NULL || !strcmp(end, "fdio")) { 02852 fd = fdOpen(path, flags, perms); 02853 if (fdFileno(fd) < 0) { 02854 if (fd) (void) fdClose(fd); 02855 fd = NULL; 02856 goto exit; 02857 } 02858 } else { 02859 FILE *fp; 02860 int fdno; 02861 int isHTTP = 0; 02862 02863 /* XXX gzdio/bzdio/lzdio through here too */ 02864 02865 switch (urlIsURL(path)) { 02866 case URL_IS_HKP: 02867 case URL_IS_HTTP: 02868 case URL_IS_HTTPS: 02869 isHTTP = 1; 02870 /*@fallthrough@*/ 02871 case URL_IS_PATH: 02872 case URL_IS_DASH: 02873 case URL_IS_FTP: 02874 case URL_IS_UNKNOWN: 02875 fd = ufdOpen(path, flags, perms); 02876 if (fd == NULL || !(fdFileno(fd) >= 0 || fd->req != NULL)) { 02877 if (fd) (void) fdClose(fd); 02878 fd = NULL; 02879 goto exit; 02880 } 02881 break; 02882 case URL_IS_MONGO: /* XXX FIXME */ 02883 default: 02884 if (fd) (void) fdClose(fd); 02885 fd = NULL; 02886 goto exit; 02887 /*@notreached@*/ break; 02888 } 02889 02890 /* XXX persistent HTTP/1.1 returns the previously opened fp */ 02891 if (isHTTP && ((fp = fdGetFp(fd)) != NULL) && ((fdno = fdGetFdno(fd)) >= 0 || fd->req != NULL)) 02892 { 02893 /*@+voidabstract@*/ 02894 fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */ 02895 /*@=voidabstract@*/ 02896 goto exit; 02897 } 02898 } 02899 02900 if (fd) 02901 fd = Fdopen(fd, fmode); 02902 exit: 02903 02904 if (_rpmio_debug) 02905 fprintf(stderr, "<== Fopen(%s, %s) fd %p\n", path, fmode, fd); 02906 fmode = _free(fmode); 02907 return fd; 02908 } 02909 02910 int Fflush(FD_t fd) 02911 { 02912 void * vh; 02913 if (fd == NULL) return -1; 02914 if (fdGetIo(fd) == fpio) 02915 /*@+voidabstract -nullpass@*/ 02916 return fflush(fdGetFILE(fd)); 02917 /*@=voidabstract =nullpass@*/ 02918 02919 vh = fdGetFp(fd); 02920 #if defined(WITH_ZLIB) 02921 if (vh && fdGetIo(fd) == gzdio && gzdio->_flush != NULL) 02922 return (*gzdio->_flush) ((void *)fd); 02923 #endif 02924 #if defined(WITH_BZIP2) 02925 if (vh && fdGetIo(fd) == bzdio && bzdio->_flush != NULL) 02926 return (*bzdio->_flush) ((void *)fd); 02927 #endif 02928 #if defined(WITH_XZ) 02929 if (vh && fdGetIo(fd) == lzdio && lzdio->_flush != NULL) 02930 return (*lzdio->_flush) ((void *)fd); 02931 if (vh && fdGetIo(fd) == xzdio && xzdio->_flush != NULL) 02932 return (*xzdio->_flush) ((void *)fd); 02933 #endif 02934 02935 return 0; 02936 } 02937 02938 int Ferror(FD_t fd) 02939 { 02940 int i, rc = 0; 02941 02942 if (fd == NULL) return -1; 02943 if (fd->req != NULL) { 02944 /* HACK: flimsy wiring for neon errors. */ 02945 rc = (fd->req == (void *)-1 || fd->syserrno || fd->errcookie != NULL) ? -1 : 0; 02946 } else 02947 for (i = fd->nfps; rc == 0 && i >= 0; i--) { 02948 FDSTACK_t * fps = &fd->fps[i]; 02949 int ec; 02950 02951 if (fps->io == fpio) { 02952 /*@+voidabstract -nullpass@*/ 02953 ec = ferror(fdGetFILE(fd)); 02954 /*@=voidabstract =nullpass@*/ 02955 #if defined(WITH_ZLIB) 02956 } else if (fps->io == gzdio) { 02957 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0; 02958 i--; /* XXX fdio under gzdio always has fdno == -1 */ 02959 #endif 02960 #if defined(WITH_BZIP2) 02961 } else if (fps->io == bzdio) { 02962 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0; 02963 i--; /* XXX fdio under bzdio always has fdno == -1 */ 02964 #endif 02965 #if defined(WITH_XZ) 02966 } else if (fps->io == lzdio) { 02967 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0; 02968 i--; /* XXX fdio under lzdio always has fdno == -1 */ 02969 } else if (fps->io == xzdio) { 02970 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0; 02971 i--; /* XXX fdio under xzdio always has fdno == -1 */ 02972 #endif 02973 } else { 02974 /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */ 02975 ec = (fdFileno(fd) < 0 ? -1 : 0); 02976 } 02977 02978 if (rc == 0 && ec) 02979 rc = ec; 02980 } 02981 DBGIO(fd, (stderr, "<== Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd))); 02982 return rc; 02983 } 02984 02985 int Fileno(FD_t fd) 02986 { 02987 int i, rc = -1; 02988 02989 if (fd == NULL) 02990 return -1; 02991 if (fd->req != NULL) 02992 rc = 123456789; /* HACK: https has no steenkin fileno. */ 02993 else 02994 for (i = fd->nfps ; rc == -1 && i >= 0; i--) { 02995 rc = fd->fps[i].fdno; 02996 } 02997 02998 DBGIO(fd, (stderr, "<== Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd))); 02999 return rc; 03000 } 03001 03002 /* XXX this is naive */ 03003 int Fcntl(FD_t fd, int op, void *lip) 03004 { 03005 return fcntl(Fileno(fd), op, lip); 03006 } 03007 03008 /* =============================================================== */ 03009 /* Helper routines that may be generally useful. 03010 */ 03011 int rpmioMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid) 03012 { 03013 char * d, * de; 03014 int created = 0; 03015 int rc; 03016 03017 if (path == NULL || *path == '\0') 03018 return -1; 03019 d = alloca(strlen(path)+2); 03020 de = stpcpy(d, path); 03021 de[1] = '\0'; 03022 for (de = d; *de != '\0'; de++) { 03023 struct stat st; 03024 char savec; 03025 03026 while (*de && *de != '/') de++; 03027 savec = de[1]; 03028 de[1] = '\0'; 03029 03030 rc = Stat(d, &st); 03031 if (rc) { 03032 switch(errno) { 03033 default: 03034 return errno; 03035 /*@notreached@*/ /*@switchbreak@*/ break; 03036 case ENOENT: 03037 /*@switchbreak@*/ break; 03038 } 03039 rc = Mkdir(d, mode); 03040 if (rc) 03041 return errno; 03042 created = 1; 03043 if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) { 03044 rc = Chown(d, uid, gid); 03045 if (rc) 03046 return errno; 03047 } 03048 } else if (!S_ISDIR(st.st_mode)) { 03049 return ENOTDIR; 03050 } 03051 de[1] = savec; 03052 } 03053 rc = 0; 03054 if (created) 03055 rpmlog(RPMLOG_DEBUG, D_("created directory(s) %s mode 0%o\n"), 03056 path, (unsigned)mode); 03057 return rc; 03058 } 03059 03060 #define _PATH "/bin:/usr/bin:/sbin:/usr/sbin" 03061 /*@unchecked@*/ /*@observer@*/ 03062 static const char *_path = _PATH; 03063 03064 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) 03065 03066 int rpmioAccess(const char * FN, const char * path, int mode) 03067 { 03068 char fn[4096]; 03069 char * bn; 03070 char * r, * re; 03071 char * t, * te; 03072 int negate = 0; 03073 int rc = 0; 03074 03075 /* Empty paths are always accessible. */ 03076 if (FN == NULL || *FN == '\0') 03077 return 0; 03078 03079 if (mode == 0) 03080 mode = X_OK; 03081 03082 /* Strip filename out of its name space wrapper. */ 03083 bn = alloca_strdup(FN); 03084 for (t = bn; t && *t; t++) { 03085 if (*t != '(') 03086 continue; 03087 *t++ = '\0'; 03088 03089 /* Permit negation on name space tests. */ 03090 if (*bn == '!') { 03091 negate = 1; 03092 bn++; 03093 } 03094 03095 /* Set access flags from name space marker. */ 03096 if (strlen(bn) == 3 03097 && strchr("Rr_", bn[0]) != NULL 03098 && strchr("Ww_", bn[1]) != NULL 03099 && strchr("Xx_", bn[2]) != NULL) { 03100 mode = 0; 03101 if (strchr("Rr", bn[0]) != NULL) 03102 mode |= R_OK; 03103 if (strchr("Ww", bn[1]) != NULL) 03104 mode |= W_OK; 03105 if (strchr("Xx", bn[2]) != NULL) 03106 mode |= X_OK; 03107 if (mode == 0) 03108 mode = F_OK; 03109 } else if (!strcmp(bn, "exists")) 03110 mode = F_OK; 03111 else if (!strcmp(bn, "executable")) 03112 mode = X_OK; 03113 else if (!strcmp(bn, "readable")) 03114 mode = R_OK; 03115 else if (!strcmp(bn, "writable")) 03116 mode = W_OK; 03117 03118 bn = t; 03119 te = bn + strlen(t) - 1; 03120 if (*te != ')') /* XXX syntax error, never exists */ 03121 return 1; 03122 *te = '\0'; 03123 break; 03124 } 03125 03126 /* Empty paths are always accessible. */ 03127 if (*bn == '\0') 03128 goto exit; 03129 03130 /* Check absolute path for access. */ 03131 if (*bn == '/') { 03132 rc = (Access(bn, mode) != 0 ? 1 : 0); 03133 if (_rpmio_debug) 03134 fprintf(stderr, "*** rpmioAccess(\"%s\", 0x%x) rc %d\n", bn, mode, rc); 03135 goto exit; 03136 } 03137 03138 /* Find path to search. */ 03139 if (path == NULL) 03140 path = getenv("PATH"); 03141 if (path == NULL) 03142 path = _path; 03143 if (path == NULL) { 03144 rc = 1; 03145 goto exit; 03146 } 03147 03148 /* Look for relative basename on PATH. */ 03149 for (r = alloca_strdup(path); r != NULL && *r != '\0'; r = re) { 03150 03151 /* Find next element, terminate current element. */ 03152 for (re = r; (re = strchr(re, ':')) != NULL; re++) { 03153 if (!(re[1] == '/' && re[2] == '/')) 03154 /*@innerbreak@*/ break; 03155 } 03156 if (re && *re == ':') 03157 *re++ = '\0'; 03158 else 03159 re = r + strlen(r); 03160 03161 /* Expand ~/ to $HOME/ */ 03162 fn[0] = '\0'; 03163 t = fn; 03164 *t = '\0'; /* XXX redundant. */ 03165 if (r[0] == '~' && r[1] == '/') { 03166 const char * home = getenv("HOME"); 03167 if (home == NULL) /* XXX No HOME? */ 03168 continue; 03169 if (strlen(home) > (sizeof(fn) - strlen(r))) /* XXX too big */ 03170 continue; 03171 t = stpcpy(t, home); 03172 r++; /* skip ~ */ 03173 } 03174 t = stpcpy(t, r); 03175 if (t[-1] != '/' && *bn != '/') 03176 *t++ = '/'; 03177 t = stpcpy(t, bn); 03178 t = rpmCleanPath(fn); 03179 if (t == NULL) /* XXX can't happen */ 03180 continue; 03181 03182 /* Check absolute path for access. */ 03183 rc = (Access(t, mode) != 0 ? 1 : 0); 03184 if (_rpmio_debug) 03185 fprintf(stderr, "*** rpmioAccess(\"%s\", 0x%x) rc %d\n", t, mode, rc); 03186 if (rc == 0) 03187 goto exit; 03188 } 03189 03190 rc = 1; 03191 03192 exit: 03193 if (negate) 03194 rc ^= 1; 03195 return rc; 03196 } 03197 03198 #if defined(WITH_NSS) && !defined(__LCLINT__) /* XXX TODO: add nssDestroy */ 03199 /*@-exportheader@*/ 03200 extern void NSS_Shutdown(void); 03201 /*@=exportheader@*/ 03202 03203 /*@unchecked@*/ 03204 int _rpmnss_init = 0; 03205 #endif 03206 03207 void rpmioClean(void) 03208 { 03209 /*@-nestedextern@*/ 03210 extern rpmioPool _avxPool; 03211 extern rpmioPool _urlPool; 03212 extern rpmioPool _xarPool; 03213 extern rpmioPool _digPool; 03214 extern rpmioPool _rpmiobPool; 03215 extern rpmioPool _rpmvcPool; 03216 extern rpmioPool _rpmvtPool; 03217 /*@-shadow@*/ 03218 extern rpmioPool _mirePool; 03219 extern rpmioPool _rpmbfPool; 03220 extern rpmioPool _rpmhkpPool; 03221 extern rpmioPool _htmlPool; 03222 extern rpmioPool _htPool; 03223 extern rpmioPool _ctxPool; 03224 extern rpmioPool _rpmsmPool; 03225 extern rpmioPool _rpmspPool; 03226 extern rpmioPool _rpmsxPool; 03227 extern rpmioPool _rpmsyckPool; 03228 /*@=shadow@*/ 03229 03230 extern rpmioPool _rpmasnPool; 03231 extern rpmioPool _rpmbagPool; 03232 extern rpmioPool _rpmcvsPool; 03233 extern rpmioPool _rpmsvnPool; 03234 extern rpmioPool _rpmtpmPool; 03235 03236 extern rpmioPool _rpmaugPool; 03237 extern rpmioPool _rpmcudfPool; 03238 extern rpmioPool _rpmficlPool; 03239 extern rpmioPool _rpmjsPool; 03240 extern rpmioPool _rpmluavPool; 03241 extern rpmioPool _rpmluaPool; 03242 extern rpmioPool _rpmmgPool; 03243 extern rpmioPool _rpmmgoPool; 03244 #ifdef NOTYET 03245 extern rpmioPool _rpmnixPool; 03246 #endif 03247 extern rpmioPool _rpmperlPool; 03248 extern rpmioPool _rpmpythonPool; 03249 extern rpmioPool _rpmrubyPool; 03250 extern rpmioPool _rpmsqlPool; 03251 extern rpmioPool _rpmsquirrelPool; 03252 extern rpmioPool _rpmtclPool; 03253 /*@=nestedextern@*/ 03254 03255 #if defined(WITH_LUA) 03256 (void) rpmluaFree(NULL); 03257 #endif 03258 #if defined(WITH_NEON) 03259 davDestroy(); 03260 #endif 03261 #if defined(WITH_NSS) && !defined(__LCLINT__) 03262 if (_rpmnss_init) { 03263 (void) NSS_Shutdown(); 03264 _rpmnss_init = 0; 03265 } 03266 #endif 03267 urlFreeCache(); 03268 03269 _rpmtclI = rpmtclFree(_rpmtclI); 03270 _rpmtclPool = rpmioFreePool(_rpmtclPool); 03271 _rpmsquirrelI = rpmsquirrelFree(_rpmsquirrelI); 03272 _rpmsquirrelPool = rpmioFreePool(_rpmsquirrelPool); 03273 _rpmsqlI = rpmsqlFree(_rpmsqlI); 03274 _rpmsqlPool = rpmioFreePool(_rpmsqlPool); 03275 _rpmrubyI = rpmrubyFree(_rpmrubyI); 03276 _rpmrubyPool = rpmioFreePool(_rpmrubyPool); 03277 _rpmpythonI = rpmpythonFree(_rpmpythonI); 03278 _rpmpythonPool = rpmioFreePool(_rpmpythonPool); 03279 _rpmperlI = rpmperlFree(_rpmperlI); 03280 _rpmperlPool = rpmioFreePool(_rpmperlPool); 03281 _rpmjsI = rpmjsFree(_rpmjsI); 03282 _rpmjsPool = rpmioFreePool(_rpmjsPool); 03283 _rpmficlI = rpmficlFree(_rpmficlI); 03284 _rpmficlPool = rpmioFreePool(_rpmficlPool); 03285 03286 _rpmaugI = rpmaugFree(_rpmaugI); 03287 _rpmaugPool = rpmioFreePool(_rpmaugPool); 03288 _rpmmgoI = rpmmgoFree(_rpmmgoI); 03289 _rpmmgoPool = rpmioFreePool(_rpmmgoPool); 03290 03291 _rpmasnPool = rpmioFreePool(_rpmasnPool); 03292 _rpmbagPool = rpmioFreePool(_rpmbagPool); 03293 _rpmcvsPool = rpmioFreePool(_rpmcvsPool); 03294 _rpmsvnPool = rpmioFreePool(_rpmsvnPool); 03295 _rpmtpmPool = rpmioFreePool(_rpmtpmPool); 03296 03297 #ifdef NOTYET /* XXX FIXME: dig out the recursion deadlock. */ 03298 _rpmnixI = rpmnixFree(_rpmnixI); 03299 _rpmnixPool = rpmioFreePool(_rpmnixPool); 03300 #endif 03301 03302 _rpmcudfPool = rpmioFreePool(_rpmcudfPool); 03303 _rpmluavPool = rpmioFreePool(_rpmluavPool); 03304 _rpmluaPool = rpmioFreePool(_rpmluaPool); 03305 03306 _rpmhkpI = rpmhkpFree(_rpmhkpI); 03307 _rpmhkpPool = rpmioFreePool(_rpmhkpPool); 03308 _rpmhkp_awol.bf = rpmbfFree(_rpmhkp_awol.bf); 03309 _rpmhkp_crl.bf = rpmbfFree(_rpmhkp_crl.bf); 03310 03311 _rpmvcPool = rpmioFreePool(_rpmvcPool); 03312 _rpmvtPool = rpmioFreePool(_rpmvtPool); 03313 03314 _rpmsmI = rpmsmFree(_rpmsmI); 03315 _rpmsmPool = rpmioFreePool(_rpmsmPool); 03316 _rpmspPool = rpmioFreePool(_rpmspPool); 03317 _rpmsxI = rpmsxFree(_rpmsxI); 03318 _rpmsxPool = rpmioFreePool(_rpmsxPool); 03319 03320 _htmlPool = rpmioFreePool(_htmlPool); 03321 _mirePool = rpmioFreePool(_mirePool); 03322 _rpmmgPool = rpmioFreePool(_rpmmgPool); 03323 _rpmbfPool = rpmioFreePool(_rpmbfPool); 03324 _htPool = rpmioFreePool(_htPool); 03325 _ctxPool = rpmioFreePool(_ctxPool); 03326 _rpmsyckPool = rpmioFreePool(_rpmsyckPool); 03327 _rpmiobPool = rpmioFreePool(_rpmiobPool); 03328 _digPool = rpmioFreePool(_digPool); 03329 _xarPool = rpmioFreePool(_xarPool); 03330 _avxPool = rpmioFreePool(_avxPool); 03331 _urlPool = rpmioFreePool(_urlPool); 03332 _fdPool = rpmioFreePool(_fdPool); 03333 03334 rpmlogClose(); 03335 } 03336 03337 /*@-type@*/ /* LCL: function typedefs */ 03338 static struct FDIO_s fpio_s = { 03339 ufdRead, ufdWrite, fdSeek, ufdClose, NULL, NULL, NULL, 03340 }; 03341 /*@=type@*/ 03342 03343 FDIO_t fpio = /*@-compmempass@*/ &fpio_s /*@=compmempass@*/ ;
1.7.5.1