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