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