rpm  5.4.15
rpmio.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 #include <stdarg.h>
7 
8 #if defined(HAVE_MACHINE_TYPES_H)
9 # include <machine/types.h>
10 #endif
11 
12 #if defined(HAVE_SYS_SOCKET_H)
13 # include <sys/socket.h>
14 #endif
15 
16 #ifndef NI_MAXHOST
17 #define NI_MAXHOST 1025
18 #endif
19 
20 #if defined(__LCLINT__)
21 struct addrinfo
22 {
23  int ai_flags; /* Input flags. */
24  int ai_family; /* Protocol family for socket. */
25  int ai_socktype; /* Socket type. */
26  int ai_protocol; /* Protocol for socket. */
27  socklen_t ai_addrlen; /* Length of socket address. */
28  struct sockaddr *ai_addr; /* Socket address for socket. */
29  char *ai_canonname; /* Canonical name for service location. */
30  struct addrinfo *ai_next; /* Pointer to next in list. */
31 };
32 
33 /*@-exportheader -incondefs @*/
34 extern int getaddrinfo (__const char *__restrict __name,
35  __const char *__restrict __service,
36  __const struct addrinfo *__restrict __req,
37  /*@out@*/ struct addrinfo **__restrict __pai)
38  /*@modifies *__pai @*/;
39 
40 extern int getnameinfo (__const struct sockaddr *__restrict __sa,
41  socklen_t __salen, /*@out@*/ char *__restrict __host,
42  socklen_t __hostlen, /*@out@*/ char *__restrict __serv,
43  socklen_t __servlen, unsigned int __flags)
44  /*@modifies __host, __serv @*/;
45 
46 extern void freeaddrinfo (/*@only@*/ struct addrinfo *__ai)
47  /*@modifies __ai @*/;
48 /*@=exportheader =incondefs @*/
49 #else
50 #include <netdb.h> /* XXX getaddrinfo et al */
51 #endif
52 
53 #include <netinet/in.h>
54 #include <arpa/inet.h> /* XXX for inet_aton and HP-UX */
55 
56 #if defined(HAVE_NETINET_IN_SYSTM_H)
57 # include <sys/types.h>
58 # include <netinet/in_systm.h>
59 #endif
60 
61 #if defined(WITH_XZ)
62 #include <lzma.h>
63 #endif
64 
65 #include <rpmiotypes.h>
66 #include <rpmmacro.h> /* XXX rpmioAccess needs rpmCleanPath() */
67 
68 #include <mongo.h>
69 
70 #include <rpmaug.h>
71 #include <rpmficl.h>
72 #include <rpmgit.h>
73 #include <rpmjni.h>
74 #include <rpmjs.h>
75 #include <rpmlua.h> /* XXX rpmioClean() calls rpmluaFree() */
76 #include <rpmmrb.h>
77 #include <rpmnix.h>
78 #include <rpmodbc.h>
79 #include <rpmperl.h>
80 #include <rpmpython.h>
81 #include <rpmruby.h>
82 #include <rpmsql.h>
83 #include <rpmsquirrel.h>
84 #include <rpmtcl.h>
85 
86 #define _RPMHKP_INTERNAL /* XXX awol/crl bloom filters */
87 #include <rpmhkp.h>
88 
89 #include <rpmsm.h>
90 #include <rpmsp.h>
91 #include <rpmsx.h>
92 
93 #if defined(HAVE_LIBIO_H) && defined(_G_IO_IO_FILE_VERSION)
94 #define _USE_LIBIO 1
95 #endif
96 
97 /* XXX HP-UX w/o -D_XOPEN_SOURCE needs */
98 #if !defined(HAVE_HERRNO) && (defined(hpux) || defined(__hpux) || defined(__LCLINT__))
99 /*@unchecked@*/
100 extern int h_errno;
101 #endif
102 
103 #ifndef IPPORT_FTP
104 #define IPPORT_FTP 21
105 #endif
106 #ifndef IPPORT_HTTP
107 #define IPPORT_HTTP 80
108 #endif
109 
110 #if !defined(HAVE_INET_ATON)
111 #define inet_aton(cp,inp) rpm_inet_aton(cp,inp)
112 static int rpm_inet_aton(const char *cp, struct in_addr *inp)
113  /*@modifies *inp @*/
114 {
115  long addr;
116 
117  addr = inet_addr(cp);
118  if (addr == ((long) -1)) return 0;
119 
120  memcpy(inp, &addr, sizeof(addr));
121  return 1;
122 }
123 #endif
124 
125 #if defined(USE_ALT_DNS) && USE_ALT_DNS
126 #include "dns.h"
127 #endif
128 
129 #include <rpmio_internal.h>
130 #undef fdFileno
131 #undef fdOpen
132 #define fdOpen __fdOpen
133 #undef fdRead
134 #define fdRead __fdRead
135 #undef fdWrite
136 #define fdWrite __fdWrite
137 #undef fdClose
138 #define fdClose __fdClose
139 
140 #include <ugid.h>
141 #include <rpmcb.h>
142 #include <rpmdav.h>
143 
144 #include "debug.h"
145 
146 /*@access FILE @*/ /* XXX to permit comparison/conversion with void *. */
147 /*@access urlinfo @*/
148 /*@access FDSTAT_t @*/
149 /*@access rpmxar @*/
150 /*@access pgpDig @*/
151 
152 #define FDTO(fd) (fd ? ((FD_t)fd)->rd_timeoutsecs : -99)
153 #define FDCPIOPOS(fd) (fd ? ((FD_t)fd)->fd_cpioPos : -99)
154 
155 #define FDONLY(fd) assert(fdGetIo(fd) == fdio)
156 
157 #define UFDONLY(fd) /* assert(fdGetIo(fd) == ufdio) */
158 
159 #define fdGetFILE(_fd) ((FILE *)fdGetFp(_fd))
160 
163 /*@unchecked@*/
164 #if _USE_LIBIO
165 int noLibio = 0;
166 #else
167 int noLibio = 1;
168 #endif
169 
170 #define TIMEOUT_SECS 60
171 
174 /*@unchecked@*/
176 
179 /*@unchecked@*/
180 int _rpmio_debug = 0;
181 
184 /*@unchecked@*/
185 int _av_debug = 0;
186 
189 /*@unchecked@*/
190 int _ftp_debug = 0;
191 
194 /*@unchecked@*/
195 int _dav_debug = 0;
196 
197 /* =============================================================== */
198 
199 const char * fdbg(FD_t fd)
200 {
201  static char buf[BUFSIZ];
202  char *be = buf;
203  int i;
204 
205  buf[0] = '\0';
206  if (fd == NULL)
207  return buf;
208 
209 #ifdef DYING
210  sprintf(be, "fd %p", fd); be += strlen(be);
211  if (fd->rd_timeoutsecs >= 0) {
212  sprintf(be, " secs %d", fd->rd_timeoutsecs);
213  be += strlen(be);
214  }
215 #endif
216  if (fd->bytesRemain != -1) {
217  sprintf(be, " clen %d", (int)fd->bytesRemain);
218  be += strlen(be);
219  }
220  if (fd->wr_chunked) {
221  strcpy(be, " chunked");
222  be += strlen(be);
223  }
224  *be++ = '\t';
225  for (i = fd->nfps; i >= 0; i--) {
226  FDSTACK_t * fps = &fd->fps[i];
227  if (i != fd->nfps)
228  *be++ = ' ';
229  *be++ = '|';
230  *be++ = ' ';
231  if (fps->io == fdio) {
232  sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
233  } else if (fps->io == ufdio) {
234  sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
235 #if defined(WITH_ZLIB)
236  } else if (fps->io == gzdio) {
237  sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
238 #endif
239 #if defined(WITH_BZIP2)
240  } else if (fps->io == bzdio) {
241  sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
242 #endif
243 #if defined(WITH_XZ)
244  } else if (fps->io == lzdio) {
245  sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
246  } else if (fps->io == xzdio) {
247  sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno);
248 #endif
249  } else if (fps->io == fpio) {
250  /*@+voidabstract@*/
251  sprintf(be, "%s %p(%d) fdno %d",
252  (fps->fdno < 0 ? "LIBIO" : "FP"),
253  fps->fp, fileno(((FILE *)fps->fp)), fps->fdno);
254  /*@=voidabstract@*/
255  } else {
256  sprintf(be, "??? io %p fp %p fdno %d ???",
257  fps->io, fps->fp, fps->fdno);
258  }
259  be += strlen(be);
260  *be = '\0';
261  }
262  return buf;
263 }
264 
265 /* =============================================================== */
266 FD_t fdDup(int fdno)
267 {
268  FD_t fd;
269  int nfdno;
270 
271  if ((nfdno = dup(fdno)) < 0)
272  return NULL;
273  if (fcntl(nfdno, F_SETFD, FD_CLOEXEC)) {
274  (void) close(nfdno);
275  return NULL;
276  }
277  fd = fdNew("open (fdDup)");
278  fdSetOpen(fd, "fdDup", nfdno, 0); /* XXX bogus */
279  fdSetFdno(fd, nfdno);
280 DBGIO(fd, (stderr, "<-- fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
281  /*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/
282 }
283 
284 static inline /*@unused@*/
285 int fdSeekNot(void * cookie,
286  /*@unused@*/ _libio_pos_t pos,
287  /*@unused@*/ int whence)
288  /*@*/
289 {
290  FD_t fd = c2f(cookie);
291  FDSANE(fd); /* XXX keep gcc quiet */
292  return -2;
293 }
294 
295 /* =============================================================== */
296 
297 static void fdFini(void * _fd)
298  /*@globals fileSystem @*/
299  /*@modifies _fd, fileSystem @*/
300 {
301  FD_t fd = (FD_t) _fd;
302  int i;
303 
304 assert(fd != NULL);
305  fd->opath = _free(fd->opath);
306  if (fd->stats) free(fd->stats); fd->stats = NULL;
307  if (fd->ndigests > 0)
308  for (i = fd->ndigests - 1; i >= 0; i--) {
309  DIGEST_CTX ctx = fd->digests[i];
310  if (ctx == NULL)
311  continue;
312  (void) rpmDigestFinal(ctx, NULL, NULL, 0);
313  fd->digests[i] = NULL;
314  }
315  fd->digests = _free(fd->digests);
316  fd->ndigests = 0;
317  fd->contentType = _free(fd->contentType);
319 /*@-onlytrans@*/
320 #ifdef WITH_XAR
321  fd->xar = rpmxarFree(fd->xar, "fdFini");
322 #endif
323 #ifdef WITH_NEON
324 #ifndef NOTYET
325 if (fd->req != NULL)
326 fprintf(stderr, "*** %s: fd->req %p\n", __FUNCTION__, fd->req);
327 fd->req = NULL;
328 #else
329 assert(fd->req == NULL);
330 #endif
331 #endif
332  fd->dig = pgpDigFree(fd->dig);
333 /*@=onlytrans@*/
334 }
335 
336 /*@unchecked@*/ /*@only@*/ /*@null@*/
338 
339 static FD_t fdGetPool(/*@null@*/ rpmioPool pool)
340  /*@globals _fdPool, fileSystem @*/
341  /*@modifies pool, _fdPool, fileSystem @*/
342 {
343  FD_t fd;
344 
345  if (_fdPool == NULL) {
346  _fdPool = rpmioNewPool("fd", sizeof(*fd), -1, _rpmio_debug,
347  (char * (*)(void *))fdbg, NULL, fdFini);
348  pool = _fdPool;
349  }
350  fd = (FD_t) rpmioGetPool(pool, sizeof(*fd));
351  memset(((char *)fd)+sizeof(fd->_item), 0, sizeof(*fd)-sizeof(fd->_item));
352  return fd;
353 }
354 
355 /*@-incondefs@*/
356 /*@null@*/
357 FD_t XfdNew(const char * msg, const char * fn, unsigned ln)
358 {
359  FD_t fd = fdGetPool(_fdPool);
360  if (fd == NULL) /* XXX xmalloc never returns NULL */
361  return NULL;
362  fd->flags = 0;
363  fd->magic = FDMAGIC;
364 
365  fd->nfps = 0;
366  memset(fd->fps, 0, sizeof(fd->fps));
367 
368  fd->fps[0].io = ufdio;
369  fd->fps[0].fp = NULL;
370  fd->fps[0].fdno = -1;
371 
372  fd->u = NULL;
373  fd->req = NULL;
374  fd->rd_timeoutsecs = 1; /* XXX default value used to be -1 */
375  fd->bytesRemain = -1;
376  fd->contentLength = -1;
377  fd->persist = 0;
378  fd->wr_chunked = 0;
379 
380  fd->syserrno = 0;
381  fd->errcookie = NULL;
382 
383  fd->opath = NULL;
384  fd->oflags = 0;
385  fd->omode = 0;
386 
387  fd->xar = NULL;
388  fd->dig = NULL;
389  fd->stats = (FDSTAT_t) xcalloc(1, sizeof(*fd->stats));
390  fd->ndigests = 0;
391  fd->digests = NULL;
392 
393  fd->contentType = NULL;
394  fd->contentDisposition = NULL;
395  fd->lastModified = 0;
396  fd->ftpFileDoneNeeded = 0;
397  fd->fd_cpioPos = 0;
398 
399  return (FD_t)rpmioLinkPoolItem((rpmioItem)fd, msg, fn, ln);
400 }
401 /*@=incondefs@*/
402 
403 static ssize_t fdRead(void * cookie, /*@out@*/ char * buf, size_t count)
404  /*@globals errno, fileSystem, internalState @*/
405  /*@modifies buf, errno, fileSystem, internalState @*/
406  /*@requires maxSet(buf) >= (count - 1) @*/
407 {
408  FD_t fd = c2f(cookie);
409  ssize_t rc;
410 
411  if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
412 
414  /* HACK: flimsy wiring for davRead */
415  if (fd->req != NULL) {
416 #ifdef WITH_NEON
417  if (fd->req != (void *)-1)
418  rc = davRead(fd, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count));
419  else
420  rc = -1;
421 #else
422  rc = -1;
423 #endif
424  /* XXX Chunked davRead EOF. */
425  if (rc == 0)
426  fd->bytesRemain = 0;
427  } else
428  if (fd->xar != NULL) {
429 #ifdef WITH_XAR
430  rc = xarRead(fd, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count));
431 #else
432  rc = -1;
433 #endif
434  } else
435  rc = read(fdFileno(fd), buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count));
436  fdstat_exit(fd, FDSTAT_READ, rc);
437 
438  if (fd->ndigests > 0 && rc > 0) fdUpdateDigests(fd, (const unsigned char *)buf, rc);
439 
440 DBGIO(fd, (stderr, "<--\tfdRead(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
441 
442  return rc;
443 }
444 
445 static ssize_t fdWrite(void * cookie, const char * buf, size_t count)
446  /*@globals errno, fileSystem, internalState @*/
447  /*@modifies errno, fileSystem, internalState @*/
448 {
449  FD_t fd = c2f(cookie);
450  int fdno = fdFileno(fd);
451  ssize_t rc;
452 
453  if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
454 
455  if (fd->ndigests > 0 && count > 0) fdUpdateDigests(fd, (const unsigned char *)buf, count);
456 
457  if (count == 0) return 0;
458 
460  /* HACK: flimsy wiring for davWrite */
461  if (fd->req != NULL)
462 #ifdef WITH_NEON
463  if (fd->req != (void *)-1)
464  rc = davWrite(fd, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count));
465  else
466  rc = -1;
467 #else
468  rc = -1;
469 #endif
470  else
471  rc = write(fdno, buf, (count > (size_t)fd->bytesRemain ? (size_t)fd->bytesRemain : count));
472  fdstat_exit(fd, FDSTAT_WRITE, rc);
473 
474 DBGIO(fd, (stderr, "<--\tfdWrite(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
475 
476  return rc;
477 }
478 
479 static int fdSeek(void * cookie, _libio_pos_t pos, int whence)
480  /*@globals fileSystem, internalState @*/
481  /*@modifies fileSystem, internalState @*/
482 {
483 #ifdef USE_COOKIE_SEEK_POINTER
484  _IO_off64_t p = *pos;
485 #else
486  off_t p = pos;
487 #endif
488  FD_t fd = c2f(cookie);
489  off_t rc;
490 
491  assert(fd->bytesRemain == -1); /* XXX FIXME fadio only for now */
493  rc = lseek(fdFileno(fd), p, whence);
494  fdstat_exit(fd, FDSTAT_SEEK, rc);
495 
496 DBGIO(fd, (stderr, "<--\tfdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
497 
498  return (int) rc;
499 }
500 
501 static int fdClose( /*@only@*/ void * cookie)
502  /*@globals errno, fileSystem, systemState, internalState @*/
503  /*@modifies errno, fileSystem, systemState, internalState @*/
504 {
505  FD_t fd;
506  int fdno;
507  int rc;
508 
509  if (cookie == NULL) return -2;
510  fd = c2f(cookie);
511  fdno = fdFileno(fd);
512 
513  fdSetFdno(fd, -1);
514 
516  /* HACK: flimsy wiring for davClose */
517  if (fd->req != NULL)
518 #ifdef WITH_NEON
519  rc = davClose(fd);
520 #else
521  rc = -1;
522 #endif
523  else
524  rc = ((fdno >= 0) ? close(fdno) : -2);
525  fdstat_exit(fd, FDSTAT_CLOSE, rc);
526 
527 DBGIO(fd, (stderr, "<--\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
528 
529  fd = fdFree(fd, "open (fdClose)");
530  return rc;
531 }
532 
533 static /*@null@*/ FD_t fdOpen(const char *path, int flags, mode_t mode)
534  /*@globals errno, fileSystem, internalState @*/
535  /*@modifies errno, fileSystem, internalState @*/
536 {
537  FD_t fd;
538  int fdno;
539 
540  fdno = open(path, flags, mode);
541  if (fdno < 0) return NULL;
542  if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
543  (void) close(fdno);
544  return NULL;
545  }
546  fd = fdNew("open (fdOpen)");
547  fdSetOpen(fd, path, flags, mode);
548  fdSetFdno(fd, fdno);
549 assert(fd != NULL);
550  fd->flags = flags;
551 DBGIO(fd, (stderr, "<--\tfdOpen(\"%s\",%x,0%o) %s\n", path, (unsigned)flags, (unsigned)mode, fdbg(fd)));
552  /*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/
553 }
554 
555 #ifdef NOTUSED
556 FILE *fdFdopen(void * cookie, const char *fmode)
557 {
558  FD_t fd = c2f(cookie);
559  int fdno;
560  FILE * fp;
561 
562  if (fmode == NULL) return NULL;
563  fdno = fdFileno(fd);
564  if (fdno < 0) return NULL;
565  fp = fdopen(fdno, fmode);
566 DBGIO(fd, (stderr, "<-- fdFdopen(%p,\"%s\") fdno %d -> fp %p fdno %d\n", cookie, fmode, fdno, fp, fileno(fp)));
567  fd = fdFree(fd, "open (fdFdopen)");
568  return fp;
569 }
570 #endif
571 
572 /*@-type@*/ /* LCL: function typedefs */
573 static struct FDIO_s fdio_s = {
574  fdRead, fdWrite, fdSeek, fdClose, NULL, NULL, NULL,
575 };
576 /*@=type@*/
577 
578 FDIO_t fdio = /*@-compmempass@*/ &fdio_s /*@=compmempass@*/ ;
579 
580 int fdWritable(FD_t fd, int secs)
581 {
582  int fdno;
583  int rc;
584 #if defined(HAVE_POLL_H)
585  int msecs = (secs >= 0 ? (1000 * secs) : -1);
586  struct pollfd wrfds;
587 #else
588  struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
589  fd_set wrfds;
590  FD_ZERO(&wrfds);
591 #endif
592 
593  /* HACK: flimsy wiring for davWrite */
594  if (fd->req != NULL)
595  return (fd->req == (void *)-1 ? -1 : 1);
596 
597  if ((fdno = fdFileno(fd)) < 0)
598  return -1; /* XXX W2DO? */
599 
600  do {
601 #if defined(HAVE_POLL_H)
602  wrfds.fd = fdno;
603  wrfds.events = POLLOUT;
604  wrfds.revents = 0;
605  rc = poll(&wrfds, 1, msecs);
606 #else
607  if (tvp) {
608  tvp->tv_sec = secs;
609  tvp->tv_usec = 0;
610  }
611  FD_SET(fdno, &wrfds);
612 /*@-compdef -nullpass@*/
613  rc = select(fdno + 1, NULL, &wrfds, NULL, tvp);
614 /*@=compdef =nullpass@*/
615 #endif
616 
617  /* HACK: EBADF on PUT chunked termination from ufdClose. */
618 if (_rpmio_debug && !(rc == 1 && errno == 0))
619 fprintf(stderr, "*** fdWritable fdno %d rc %d %s\n", fdno, rc, strerror(errno));
620  if (rc < 0) {
621  switch (errno) {
622  case EINTR:
623  continue;
624  /*@notreached@*/ /*@switchbreak@*/ break;
625  default:
626  return rc;
627  /*@notreached@*/ /*@switchbreak@*/ break;
628  }
629  }
630  return rc;
631  } while (1);
632  /*@notreached@*/
633 }
634 
635 int fdReadable(FD_t fd, int secs)
636 {
637  int fdno;
638  int rc;
639 #if defined(HAVE_POLL_H)
640  int msecs = (secs >= 0 ? (1000 * secs) : -1);
641  struct pollfd rdfds;
642 #else
643  struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
644  fd_set rdfds;
645  FD_ZERO(&rdfds);
646 #endif
647 
648  /* HACK: flimsy wiring for davRead */
649  if (fd->req != NULL)
650  return (fd->req == (void *)-1 ? -1 : 1);
651 
652  if ((fdno = fdFileno(fd)) < 0)
653  return -1; /* XXX W2DO? */
654 
655  do {
656 #if defined(HAVE_POLL_H)
657  rdfds.fd = fdno;
658  rdfds.events = POLLIN;
659  rdfds.revents = 0;
660  rc = poll(&rdfds, 1, msecs);
661 #else
662  if (tvp) {
663  tvp->tv_sec = secs;
664  tvp->tv_usec = 0;
665  }
666  FD_SET(fdno, &rdfds);
667  /*@-compdef -nullpass@*/
668  rc = select(fdno + 1, &rdfds, NULL, NULL, tvp);
669  /*@=compdef =nullpass@*/
670 #endif
671 
672  if (rc < 0) {
673  switch (errno) {
674  case EINTR:
675  continue;
676  /*@notreached@*/ /*@switchbreak@*/ break;
677  default:
678  return rc;
679  /*@notreached@*/ /*@switchbreak@*/ break;
680  }
681  }
682  return rc;
683  } while (1);
684  /*@notreached@*/
685 }
686 
687 int fdFgets(FD_t fd, char * buf, size_t len)
688 {
689  int fdno;
690  int secs = fd->rd_timeoutsecs;
691  size_t nb = 0;
692  int ec = 0;
693  char lastchar = '\0';
694 
695  if ((fdno = fdFileno(fd)) < 0)
696  return 0; /* XXX W2DO? */
697 
698  do {
699  int rc;
700 
701  /* Is there data to read? */
702  rc = fdReadable(fd, secs);
703 
704  switch (rc) {
705  case -1: /* error */
706  ec = -1;
707  continue;
708  /*@notreached@*/ /*@switchbreak@*/ break;
709  case 0: /* timeout */
710  ec = -1;
711  continue;
712  /*@notreached@*/ /*@switchbreak@*/ break;
713  default: /* data to read */
714  /*@switchbreak@*/ break;
715  }
716 
717  errno = 0;
718 #ifdef NOISY
719  rc = fdRead(fd, buf + nb, 1);
720 #else
721  rc = (int)read(fdFileno(fd), buf + nb, 1);
722 #endif
723  if (rc < 0) {
724  fd->syserrno = errno;
725  switch (errno) {
726  case EWOULDBLOCK:
727  continue;
728  /*@notreached@*/ /*@switchbreak@*/ break;
729  default:
730  /*@switchbreak@*/ break;
731  }
732 if (_rpmio_debug)
733 fprintf(stderr, "*** read: fd %p rc %d errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
734  ec = -1;
735  break;
736  } else if (rc == 0) {
737 if (_rpmio_debug)
738 fprintf(stderr, "*** read: fd %p rc %d EOF errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
739  break;
740  } else {
741  nb += rc;
742  buf[nb] = '\0';
743  lastchar = buf[nb - 1];
744  }
745  } while (ec == 0 && nb < len && lastchar != '\n');
746 
747  return (ec >= 0 ? (int)nb : ec);
748 }
749 
750 /* =============================================================== */
751 /* Support for FTP/HTTP I/O.
752  */
753 const char * ftpStrerror(int errorNumber)
754 {
755  switch (errorNumber) {
756  case 0:
757  return _("Success");
758 
759  /* HACK error impediance match, coalesce and rename. */
760  case FTPERR_NE_ERROR:
761  return ("NE_ERROR: Generic error.");
762  case FTPERR_NE_LOOKUP:
763  return ("NE_LOOKUP: Hostname lookup failed.");
764  case FTPERR_NE_AUTH:
765  return ("NE_AUTH: Server authentication failed.");
766  case FTPERR_NE_PROXYAUTH:
767  return ("NE_PROXYAUTH: Proxy authentication failed.");
768  case FTPERR_NE_CONNECT:
769  return ("NE_CONNECT: Could not connect to server.");
770  case FTPERR_NE_TIMEOUT:
771  return ("NE_TIMEOUT: Connection timed out.");
772  case FTPERR_NE_FAILED:
773  return ("NE_FAILED: The precondition failed.");
774  case FTPERR_NE_RETRY:
775  return ("NE_RETRY: Retry request.");
776  case FTPERR_NE_REDIRECT:
777  return ("NE_REDIRECT: Redirect received.");
778 
780  return _("Bad server response");
782  return _("Server I/O error");
784  return _("Server timeout");
786  return _("Unable to lookup server host address");
787  case FTPERR_BAD_HOSTNAME:
788  return _("Unable to lookup server host name");
790  return _("Failed to connect to server");
792  return _("Failed to establish data connection to server");
794  return _("I/O error to local file");
796  return _("Error setting remote server to passive mode");
798  return _("File not found on server");
800  return _("Abort in progress");
801 
802  case FTPERR_UNKNOWN:
803  default:
804  return _("Unknown or unexpected error");
805  }
806 }
807 
808 const char *urlStrerror(const char *url)
809 {
810  const char *retstr;
811  switch (urlIsURL(url)) {
812  case URL_IS_HKP:
813  case URL_IS_FTP:
814  case URL_IS_HTTP:
815  case URL_IS_HTTPS:
816  { urlinfo u;
817 /* XXX This only works for httpReq/ftpLogin/ftpReq failures */
818  if (urlSplit(url, &u) == 0)
819  retstr = ftpStrerror(u->openError);
820  else
821  retstr = _("Malformed URL");
822  } break;
823  case URL_IS_MONGO: /* XXX FIXME */
824  default:
825  retstr = strerror(errno);
826  break;
827  }
828  return retstr;
829 }
830 
831 #if !defined(HAVE_GETADDRINFO)
832 #if !defined(USE_ALT_DNS) || !USE_ALT_DNS
833 static int mygethostbyname(const char * host,
834  /*@out@*/ struct in_addr * address)
835  /*@globals h_errno @*/
836  /*@modifies *address @*/
837 {
838  struct hostent * hostinfo;
839 
840  /*@-multithreaded @*/
841  hostinfo = gethostbyname(host);
842  /*@=multithreaded @*/
843  if (!hostinfo) return 1;
844 
845  memcpy(address, hostinfo->h_addr_list[0], sizeof(*address));
846  return 0;
847 }
848 #endif
849 
850 /*@-compdef@*/ /* FIX: address->s_addr undefined. */
851 static int getHostAddress(const char * host, /*@out@*/ struct in_addr * address)
852  /*@globals errno, h_errno @*/
853  /*@modifies *address, errno @*/
854 {
855 #if 0 /* XXX workaround nss_foo module hand-off using valgrind. */
856  if (!strcmp(host, "localhost")) {
857  /*@-moduncon @*/
858  if (!inet_aton("127.0.0.1", address))
859  return FTPERR_BAD_HOST_ADDR;
860  /*@=moduncon @*/
861  } else
862 #endif
863  if (xisdigit(host[0])) {
864  /*@-moduncon @*/
865  if (!inet_aton(host, address))
866  return FTPERR_BAD_HOST_ADDR;
867  /*@=moduncon @*/
868  } else {
869  if (mygethostbyname(host, address)) {
870  errno = h_errno;
871  return FTPERR_BAD_HOSTNAME;
872  }
873  }
874 
875  return 0;
876 }
877 /*@=compdef@*/
878 #endif /* HAVE_GETADDRINFO */
879 
880 static int tcpConnect(FD_t ctrl, const char * host, int port)
881  /*@globals fileSystem, internalState @*/
882  /*@modifies ctrl, fileSystem, internalState @*/
883 {
884  int fdno = -1;
885  int rc;
886 #ifdef HAVE_GETADDRINFO
887 /*@-unrecog@*/
888  struct addrinfo hints, *res, *res0;
889 #ifndef NI_MAXSERV
890 #define NI_MAXSERV 32
891 #endif
892  char pbuf[NI_MAXSERV];
893  int xx;
894 
895  memset(&hints, 0, sizeof(hints));
896  hints.ai_family = AF_UNSPEC;
897  hints.ai_socktype = SOCK_STREAM;
898  sprintf(pbuf, "%d", port);
899  pbuf[sizeof(pbuf)-1] = '\0';
901  if (getaddrinfo(host, pbuf, &hints, &res0) == 0) {
902  for (res = res0; res != NULL; res = res->ai_next) {
903  if ((fdno = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
904  continue;
905  if (connect(fdno, res->ai_addr, (int)res->ai_addrlen) < 0) {
906  xx = close(fdno);
907  fdno = -1; /* XXX coverity #1036724 */
908  continue;
909  }
910  /* success */
911  rc = 0;
912  if (_ftp_debug) {
913  char hbuf[NI_MAXHOST];
914  hbuf[0] = '\0';
915  xx = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
916  NULL, 0, NI_NUMERICHOST);
917  fprintf(stderr,"++ connect [%s]:%d on fdno %d\n",
918  /*@-unrecog@*/ hbuf /*@=unrecog@*/, port, fdno);
919  }
920  break;
921  }
922  freeaddrinfo(res0);
923  }
924  if (rc < 0)
925  goto errxit;
926 /*@=unrecog@*/
927 #else /* HAVE_GETADDRINFO */
928  struct sockaddr_in sin;
929 
930  memset(&sin, 0, sizeof(sin));
931  sin.sin_family = AF_INET;
932  sin.sin_port = htons(port);
933  sin.sin_addr.s_addr = INADDR_ANY;
934 
935  do {
936  if ((rc = getHostAddress(host, &sin.sin_addr)) < 0)
937  break;
938 
939  if ((fdno = socket(sin.sin_family, SOCK_STREAM, IPPROTO_IP)) < 0) {
941  break;
942  }
943 
944  /*@-internalglobs@*/
945  if (connect(fdno, (struct sockaddr *) &sin, sizeof(sin))) {
947  break;
948  }
949  /*@=internalglobs@*/
950  } while (0);
951 
952  if (rc < 0)
953  goto errxit;
954 
955 if (_ftp_debug)
956 fprintf(stderr,"++ connect %s:%d on fdno %d\n",
957 /*@-unrecog -moduncon -evalorderuncon @*/
958 inet_ntoa(sin.sin_addr)
959 /*@=unrecog =moduncon =evalorderuncon @*/ ,
960 (int)ntohs(sin.sin_port), fdno);
961 #endif /* HAVE_GETADDRINFO */
962 
963  fdSetFdno(ctrl, (fdno >= 0 ? fdno : -1));
964  return 0;
965 
966 errxit:
967  /*@-observertrans@*/
968  fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
969  /*@=observertrans@*/
970  if (fdno >= 0)
971  (void) close(fdno);
972  return rc;
973 }
974 
975 static int checkResponse(void * _u, FD_t ctrl,
976  /*@out@*/ int *ecp, /*@out@*/ char ** str)
977  /*@globals fileSystem @*/
978  /*@modifies ctrl, *ecp, *str, fileSystem @*/
979 {
980  urlinfo u = (urlinfo) _u;
981  char *buf;
982  size_t bufAlloced;
983  int bufLength = 0;
984  const char *s;
985  char *se;
986  int ec = 0;
987  int moretodo = 1;
988  char errorCode[4];
989 
990  URLSANE(u);
991  if (u->bufAlloced == 0 || u->buf == NULL) {
993  u->buf = (char *) xcalloc(u->bufAlloced, sizeof(u->buf[0]));
994  }
995  buf = u->buf;
996  bufAlloced = u->bufAlloced;
997  *buf = '\0';
998 
999  errorCode[0] = '\0';
1000 
1001  do {
1002  int rc;
1003 
1004  /*
1005  * Read next line from server.
1006  */
1007  se = buf + bufLength;
1008  *se = '\0';
1009  rc = fdFgets(ctrl, se, (bufAlloced - bufLength));
1010  if (rc < 0) {
1012  continue;
1013  } else if (rc == 0 || fdWritable(ctrl, 0) < 1)
1014  moretodo = 0;
1015 
1016  /*
1017  * Process next line from server.
1018  */
1019  for (s = se; *s != '\0'; s = se) {
1020  const char *e;
1021 
1022  while (*se && *se != '\n') se++;
1023 
1024  if (se > s && se[-1] == '\r')
1025  se[-1] = '\0';
1026  if (*se == '\0')
1027  /*@innerbreak@*/ break;
1028 
1029 if (_ftp_debug)
1030 fprintf(stderr, "<- %s\n", s);
1031 
1032  /* HTTP: header termination on empty line */
1033  if (*s == '\0') {
1034  moretodo = 0;
1035  /*@innerbreak@*/ break;
1036  }
1037  *se++ = '\0';
1038 
1039  /* HTTP: look for "HTTP/1.1 123 ..." */
1040  if (!strncmp(s, "HTTP", sizeof("HTTP")-1)) {
1041  ctrl->contentLength = -1;
1042  if ((e = strchr(s, '.')) != NULL) {
1043  e++;
1044  u->httpVersion = (int)(*e - '0');
1045  if (u->httpVersion < 1 || u->httpVersion > 2)
1046  ctrl->persist = u->httpVersion = 0;
1047  else
1048  ctrl->persist = 1;
1049  }
1050  if ((e = strchr(s, ' ')) != NULL) {
1051  e++;
1052  if (strchr("0123456789", *e))
1053  strncpy(errorCode, e, 3);
1054  errorCode[3] = '\0';
1055  }
1056  /*@innercontinue@*/ continue;
1057  }
1058 
1059  /* HTTP: look for "token: ..." */
1060  for (e = s; *e && !(*e == ' ' || *e == ':'); e++)
1061  {};
1062  if (e > s && *e++ == ':') {
1063  size_t ne = (e - s);
1064  while (*e && *e == ' ') e++;
1065 #if 0
1066  if (!strncmp(s, "Date:", ne)) {
1067  } else
1068  if (!strncmp(s, "Server:", ne)) {
1069  } else
1070  if (!strncmp(s, "Last-Modified:", ne)) {
1071  } else
1072  if (!strncmp(s, "ETag:", ne)) {
1073  } else
1074 #endif
1075  if (!strncmp(s, "Accept-Ranges:", ne)) {
1076  if (!strcmp(e, "bytes"))
1078  if (!strcmp(e, "none"))
1080  } else
1081  if (!strncmp(s, "Content-Length:", ne)) {
1082  if (strchr("0123456789", *e))
1083  ctrl->contentLength = atol(e);
1084  } else
1085  if (!strncmp(s, "Connection:", ne)) {
1086  if (!strcmp(e, "close"))
1087  ctrl->persist = 0;
1088  }
1089 #if 0
1090  else
1091  if (!strncmp(s, "Content-Type:", ne)) {
1092  } else
1093  if (!strncmp(s, "Transfer-Encoding:", ne)) {
1094  if (!strcmp(e, "chunked"))
1095  ctrl->wr_chunked = 1;
1096  else
1097  ctrl->wr_chunked = 0;
1098  } else
1099  if (!strncmp(s, "Allow:", ne)) {
1100  }
1101 #endif
1102  /*@innercontinue@*/ continue;
1103  }
1104 
1105  /* HTTP: look for "<TITLE>501 ... </TITLE>" */
1106  if (!strncmp(s, "<TITLE>", sizeof("<TITLE>")-1))
1107  s += sizeof("<TITLE>") - 1;
1108 
1109  /* FTP: look for "123-" and/or "123 " */
1110  if (strchr("0123456789", *s)) {
1111  if (errorCode[0] != '\0') {
1112  if (!strncmp(s, errorCode, sizeof("123")-1) && s[3] == ' ')
1113  moretodo = 0;
1114  } else {
1115  strncpy(errorCode, s, sizeof("123")-1);
1116  errorCode[3] = '\0';
1117  if (s[3] != '-')
1118  moretodo = 0;
1119  }
1120  }
1121  }
1122 
1123  if (moretodo && se > s) {
1124  bufLength = se - s - 1;
1125  if (s != buf)
1126  memmove(buf, s, bufLength);
1127  } else {
1128  bufLength = 0;
1129  }
1130  } while (moretodo && ec == 0);
1131 
1132  if (str) *str = buf;
1133  if (ecp) *ecp = atoi(errorCode);
1134 
1135  return ec;
1136 }
1137 
1138 static int ftpCheckResponse(urlinfo u, /*@out@*/ char ** str)
1139  /*@globals fileSystem @*/
1140  /*@modifies u, *str, fileSystem @*/
1141 {
1142  int ec = 0;
1143  int rc;
1144 
1145  URLSANE(u);
1146  rc = checkResponse(u, u->ctrl, &ec, str);
1147 
1148  switch (ec) {
1149  case 550:
1150  return FTPERR_FILE_NOT_FOUND;
1151  /*@notreached@*/ break;
1152  case 552:
1154  /*@notreached@*/ break;
1155  default:
1156  if (ec >= 400 && ec <= 599) {
1158  }
1159  break;
1160  }
1161  return rc;
1162 }
1163 
1164 static int ftpCommand(urlinfo u, char ** str, ...)
1165  /*@globals fileSystem, internalState @*/
1166  /*@modifies u, *str, fileSystem, internalState @*/
1167 {
1168  va_list ap;
1169  int len = 0;
1170  const char * s, * t;
1171  char * te;
1172  int rc;
1173 
1174  URLSANE(u);
1175  va_start(ap, str);
1176  while ((s = va_arg(ap, const char *)) != NULL) {
1177  if (len) len++;
1178  len += strlen(s);
1179  }
1180  len += sizeof("\r\n")-1;
1181  va_end(ap);
1182 
1183  t = te = (char *) alloca(len + 1);
1184 
1185  va_start(ap, str);
1186  while ((s = va_arg(ap, const char *)) != NULL) {
1187  if (te > t) *te++ = ' ';
1188  te = stpcpy(te, s);
1189  }
1190  te = stpcpy(te, "\r\n");
1191  va_end(ap);
1192 
1193 if (_ftp_debug)
1194 fprintf(stderr, "-> %s", t);
1195  if (fdWrite(u->ctrl, t, (te-t)) != (te-t))
1196  return FTPERR_SERVER_IO_ERROR;
1197 
1198  rc = ftpCheckResponse(u, str);
1199  return rc;
1200 }
1201 
1202 static int ftpLogin(urlinfo u)
1203  /*@globals fileSystem, internalState @*/
1204  /*@modifies u, fileSystem, internalState @*/
1205 {
1206  const char * host;
1207  const char * user;
1208  const char * password;
1209  int port;
1210  int rc;
1211 
1212  URLSANE(u);
1213  u->ctrl = fdLink(u->ctrl, "open ctrl");
1214 
1215  if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) {
1216  rc = FTPERR_BAD_HOSTNAME;
1217  goto errxit;
1218  }
1219 
1220  if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = IPPORT_FTP;
1221 
1222  if ((user = (u->proxyu ? u->proxyu : u->user)) == NULL)
1223  user = "anonymous";
1224 
1225  if ((password = u->password) == NULL) {
1226  uid_t uid = getuid();
1227  struct passwd * pw;
1228  if (uid && (pw = getpwuid(uid)) != NULL) {
1229  char *myp = (char *) alloca(strlen(pw->pw_name) + sizeof("@"));
1230  strcpy(myp, pw->pw_name);
1231  strcat(myp, "@");
1232  password = myp;
1233  } else {
1234  password = "root@";
1235  }
1236  }
1237 
1238  if (fdFileno(u->ctrl) >= 0 && fdWritable(u->ctrl, 0) < 1)
1239  /*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/
1240 
1241 /*@-usereleased@*/
1242  if (fdFileno(u->ctrl) < 0) {
1243  rc = tcpConnect(u->ctrl, host, port);
1244  if (rc < 0)
1245  goto errxit2;
1246  }
1247 
1248  if ((rc = ftpCheckResponse(u, NULL)))
1249  goto errxit;
1250 
1251  if ((rc = ftpCommand(u, NULL, "USER", user, NULL)))
1252  goto errxit;
1253 
1254  if ((rc = ftpCommand(u, NULL, "PASS", password, NULL)))
1255  goto errxit;
1256 
1257  if ((rc = ftpCommand(u, NULL, "TYPE", "I", NULL)))
1258  goto errxit;
1259 
1260  /*@-compdef@*/
1261  return 0;
1262  /*@=compdef@*/
1263 
1264 errxit:
1265  /*@-observertrans@*/
1266  fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
1267  /*@=observertrans@*/
1268 errxit2:
1269  if (fdFileno(u->ctrl) >= 0)
1270  /*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/
1271  /*@-compdef@*/
1272  return rc;
1273  /*@=compdef@*/
1274 /*@=usereleased@*/
1275 }
1276 
1277 int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg)
1278 {
1279  urlinfo u = (urlinfo) data->u;
1280 #if !defined(HAVE_GETADDRINFO)
1281  struct sockaddr_in dataAddress;
1282 #endif /* HAVE_GETADDRINFO */
1283  char remoteIP[NI_MAXHOST];
1284  char * cmd;
1285  size_t cmdlen;
1286  char * passReply;
1287  char * chptr;
1288  int rc;
1289  int epsv;
1290  int port;
1291 
1292  remoteIP[0] = '\0';
1293  URLSANE(u);
1294  if (ftpCmd == NULL)
1295  return FTPERR_UNKNOWN; /* XXX W2DO? */
1296 
1297  cmdlen = strlen(ftpCmd) + (ftpArg ? 1+strlen(ftpArg) : 0) + sizeof("\r\n");
1298  cmd = (char *) alloca(cmdlen); /* XXX coverity #1035968 */
1299  chptr = stpcpy(cmd, ftpCmd);
1300  if (ftpArg) {
1301  *chptr++ = ' ';
1302  chptr = stpcpy(chptr, ftpArg);
1303  }
1304  chptr = stpcpy(chptr, "\r\n");
1305  cmdlen = chptr - cmd;
1306 
1307 /*
1308  * Get the ftp version of the Content-Length.
1309  */
1310  if (!strncmp(cmd, "RETR", 4)) {
1311  unsigned cl;
1312 
1313  passReply = NULL;
1314  rc = ftpCommand(u, &passReply, "SIZE", ftpArg, NULL);
1315  if (rc)
1316  goto errxit;
1317  if (sscanf(passReply, "%d %u", &rc, &cl) != 2) {
1319  goto errxit;
1320  }
1321  rc = 0;
1322  data->contentLength = cl;
1323  }
1324 
1325  epsv = 0;
1326  passReply = NULL;
1327 #ifdef HAVE_GETNAMEINFO
1328  rc = ftpCommand(u, &passReply, "EPSV", NULL);
1329  if (rc == 0) {
1330 #ifdef HAVE_GETADDRINFO
1331  struct sockaddr_storage ss;
1332 #else /* HAVE_GETADDRINFO */
1333  struct sockaddr_in ss;
1334 #endif /* HAVE_GETADDRINFO */
1335  socklen_t sslen = sizeof(ss);
1336 
1337  /* we need to know IP of remote host */
1338  if ((getpeername(fdFileno(c2f(u->ctrl)), (struct sockaddr *)&ss, &sslen) == 0)
1339  && (getnameinfo((struct sockaddr *)&ss, sslen,
1340  remoteIP, sizeof(remoteIP),
1341  NULL, 0, NI_NUMERICHOST) == 0))
1342  {
1343  epsv++;
1344  } else {
1345  /* abort EPSV and fall back to PASV */
1346  rc = ftpCommand(u, &passReply, "ABOR", NULL);
1347  if (rc) {
1348  rc = FTPERR_PASSIVE_ERROR;
1349  goto errxit;
1350  }
1351  }
1352  }
1353  if (epsv == 0)
1354 #endif /* HAVE_GETNAMEINFO */
1355  rc = ftpCommand(u, &passReply, "PASV", NULL);
1356  if (rc) {
1357  rc = FTPERR_PASSIVE_ERROR;
1358  goto errxit;
1359  }
1360 
1361  chptr = passReply;
1362 assert(chptr != NULL);
1363  while (*chptr && *chptr != '(') chptr++;
1364  if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
1365  chptr++;
1366  passReply = chptr;
1367  while (*chptr && *chptr != ')') chptr++;
1368  if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
1369  *chptr-- = '\0';
1370 
1371  if (epsv) {
1372  int i;
1373  if(sscanf(passReply,"%*c%*c%*c%d%*c",&i) != 1) {
1374  rc = FTPERR_PASSIVE_ERROR;
1375  goto errxit;
1376  }
1377  port = i;
1378  } else {
1379 
1380  while (*chptr && *chptr != ',') chptr--;
1381  if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
1382  chptr--;
1383  while (*chptr && *chptr != ',') chptr--;
1384  if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
1385  *chptr++ = '\0';
1386 
1387  /* now passReply points to the IP portion, and chptr points to the
1388  port number portion */
1389 
1390  { int i, j;
1391  if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
1392  rc = FTPERR_PASSIVE_ERROR;
1393  goto errxit;
1394  }
1395  port = (((unsigned)i) << 8) + j;
1396  }
1397 
1398  chptr = passReply;
1399  while (*chptr++ != '\0') {
1400  if (*chptr == ',') *chptr = '.';
1401  }
1402  sprintf(remoteIP, "%s", passReply);
1403  } /* if (epsv) */
1404 
1405 #ifdef HAVE_GETADDRINFO
1406 /*@-unrecog@*/
1407  {
1408  struct addrinfo hints, *res, *res0;
1409  char pbuf[NI_MAXSERV];
1410  int xx;
1411 
1412  memset(&hints, 0, sizeof(hints));
1413  hints.ai_family = AF_UNSPEC;
1414  hints.ai_socktype = SOCK_STREAM;
1415  hints.ai_flags = AI_NUMERICHOST;
1416 #if defined(AI_IDN)
1417  hints.ai_flags |= AI_IDN;
1418 #endif
1419  sprintf(pbuf, "%d", port);
1420  pbuf[sizeof(pbuf)-1] = '\0';
1421  if (getaddrinfo(remoteIP, pbuf, &hints, &res0)) {
1422  rc = FTPERR_PASSIVE_ERROR;
1423  goto errxit;
1424  }
1425 
1426  for (res = res0; res != NULL; res = res->ai_next) {
1427  rc = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1428  fdSetFdno(data, (rc >= 0 ? rc : -1));
1429  if (rc < 0) {
1430  if (res->ai_next)
1431  continue;
1432  else {
1433  rc = FTPERR_FAILED_CONNECT;
1434  freeaddrinfo(res0);
1435  goto errxit;
1436  }
1437  }
1438  data = fdLink(data, "open data (ftpReq)");
1439 
1440  /* XXX setsockopt SO_LINGER */
1441  /* XXX setsockopt SO_KEEPALIVE */
1442  /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */
1443 
1444  {
1445  int criterr = 0;
1446  while (connect(fdFileno(data), res->ai_addr, (int)res->ai_addrlen) < 0) {
1447  if (errno == EINTR)
1448  /*@innercontinue@*/ continue;
1449  criterr++;
1450  }
1451  if (criterr) {
1452  if (res->ai_addr) {
1453 /*@-refcounttrans@*/
1454  xx = fdClose(data);
1455 /*@=refcounttrans@*/
1456  continue;
1457  } else {
1458  rc = FTPERR_PASSIVE_ERROR;
1459  freeaddrinfo(res0);
1460  goto errxit;
1461  }
1462  }
1463  }
1464  /* success */
1465  rc = 0;
1466  break;
1467  }
1468  freeaddrinfo(res0);
1469  }
1470 /*@=unrecog@*/
1471 #else /* HAVE_GETADDRINFO */
1472  memset(&dataAddress, 0, sizeof(dataAddress));
1473  dataAddress.sin_family = AF_INET;
1474  dataAddress.sin_port = htons(port);
1475 
1476  /*@-moduncon@*/
1477  if (!inet_aton(remoteIP, &dataAddress.sin_addr)) {
1478  rc = FTPERR_PASSIVE_ERROR;
1479  goto errxit;
1480  }
1481  /*@=moduncon@*/
1482 
1483  rc = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
1484  fdSetFdno(data, (rc >= 0 ? rc : -1));
1485  if (rc < 0) {
1486  rc = FTPERR_FAILED_CONNECT;
1487  goto errxit;
1488  }
1489  data = fdLink(data, "open data (ftpReq)");
1490 
1491  /* XXX setsockopt SO_LINGER */
1492  /* XXX setsockopt SO_KEEPALIVE */
1493  /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */
1494 
1495  /*@-internalglobs@*/
1496  while (connect(fdFileno(data), (struct sockaddr *) &dataAddress,
1497  sizeof(dataAddress)) < 0)
1498  {
1499  if (errno == EINTR)
1500  continue;
1502  goto errxit;
1503  }
1504  /*@=internalglobs@*/
1505 #endif /* HAVE_GETADDRINFO */
1506 
1507 if (_ftp_debug)
1508 fprintf(stderr, "-> %s", cmd);
1509  if ((size_t)fdWrite(u->ctrl, cmd, cmdlen) != cmdlen) {
1511  goto errxit;
1512  }
1513 
1514  if ((rc = ftpCheckResponse(u, NULL))) {
1515  goto errxit;
1516  }
1517 
1518  data->ftpFileDoneNeeded = 1;
1519  u->ctrl = fdLink(u->ctrl, "grab data (ftpReq)");
1520  u->ctrl = fdLink(u->ctrl, "open data (ftpReq)");
1521  return 0;
1522 
1523 errxit:
1524  /*@-observertrans@*/
1525  fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
1526  /*@=observertrans@*/
1527  if (fdFileno(data) >= 0)
1528  /*@-refcounttrans@*/ (void) fdClose(data); /*@=refcounttrans@*/
1529  return rc;
1530 }
1531 
1532 #ifdef DYING
1533 /*@unchecked@*/ /*@null@*/
1534 static rpmCallbackFunction _urlNotify = NULL;
1535 
1536 /*@unchecked@*/ /*@null@*/
1537 static void * _urlNotifyData = NULL;
1538 
1539 /*@unchecked@*/
1540 static int _urlNotifyCount = -1;
1541 
1542 static void urlSetCallback(rpmCallbackFunction notify, void *notifyData, int notifyCount) {
1543  _urlNotify = notify;
1544  _urlNotifyData = notifyData;
1545  _urlNotifyCount = (notifyCount >= 0) ? notifyCount : 4096;
1546 }
1547 #endif
1548 
1549 int ufdCopy(FD_t sfd, FD_t tfd)
1550 {
1551  char buf[BUFSIZ];
1552  int itemsRead;
1553  int itemsCopied = 0;
1554  int rc = 0;
1555 #ifdef DYING
1556  int notifier = -1;
1557 
1558  if (_urlNotify) {
1559  /*@-noeffectuncon @*/ /* FIX: check rc */
1560  (void)(*_urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
1561  0, 0, NULL, _urlNotifyData);
1562  /*@=noeffectuncon @*/
1563  }
1564 #endif
1565 
1566  while (1) {
1567  rc = (int) Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
1568  if (rc < 0) /* XXX never happens Fread returns size_t */
1569  break;
1570  else if (rc == 0) {
1571  rc = itemsCopied;
1572  break;
1573  }
1574  itemsRead = rc;
1575  rc = (int) Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
1576  if (rc < 0) /* XXX never happens Fwrite returns size_t */
1577  break;
1578  if (rc != itemsRead) {
1579  rc = FTPERR_FILE_IO_ERROR;
1580  break;
1581  }
1582 
1583  itemsCopied += itemsRead;
1584 #ifdef DYING
1585  if (_urlNotify && _urlNotifyCount > 0) {
1586  int n = itemsCopied/_urlNotifyCount;
1587  if (n != notifier) {
1588  /*@-noeffectuncon @*/ /* FIX: check rc */
1589  (void)(*_urlNotify) (NULL, RPMCALLBACK_INST_PROGRESS,
1590  itemsCopied, 0, NULL, _urlNotifyData);
1591  /*@=noeffectuncon @*/
1592  notifier = n;
1593  }
1594  }
1595 #endif
1596  }
1597 
1598  DBGIO(sfd, (stderr, "++ copied %d bytes: %s\n", itemsCopied,
1599  ftpStrerror(rc)));
1600 
1601 #ifdef DYING
1602  if (_urlNotify) {
1603  /*@-noeffectuncon @*/ /* FIX: check rc */
1604  (void)(*_urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
1605  itemsCopied, itemsCopied, NULL, _urlNotifyData);
1606  /*@=noeffectuncon @*/
1607  }
1608 #endif
1609 
1610  return rc;
1611 }
1612 
1613 static int urlConnect(const char * url, /*@out@*/ urlinfo * uret)
1614  /*@globals h_errno, fileSystem, internalState @*/
1615  /*@modifies *uret, fileSystem, internalState @*/
1616 {
1617  urlinfo u;
1618  int rc = 0;
1619 
1620  if (urlSplit(url, &u) < 0)
1621  return -1;
1622 
1623  if (urlType(u) == URL_IS_FTP) {
1624  FD_t fd;
1625 
1626  if ((fd = u->ctrl) == NULL) {
1627  fd = u->ctrl = fdNew("persist ctrl (urlConnect FTP)");
1628 /*@-usereleased@*/
1629  fdSetOpen(u->ctrl, url, 0, 0);
1630  fdSetIo(u->ctrl, ufdio);
1631 /*@=usereleased@*/
1632  }
1633 
1634 assert(fd != NULL);
1636  fd->contentLength = fd->bytesRemain = -1;
1637  fd->u = NULL; /* XXX FTP ctrl has not */
1638  fd->ftpFileDoneNeeded = 0;
1639  fd = fdLink(fd, "grab ctrl (urlConnect FTP)");
1640 
1641  if (fdFileno(u->ctrl) < 0) {
1642  rpmlog(RPMLOG_DEBUG, D_("logging into %s as %s, pw %s\n"),
1643  u->host ? u->host : "???",
1644  u->user ? u->user : "ftp",
1645  u->password ? u->password : "(username)");
1646 
1647  if ((rc = ftpLogin(u)) < 0) { /* XXX save ftpLogin error */
1648  u->ctrl = fdFree(fd, "grab ctrl (urlConnect FTP)");
1649  u->openError = rc;
1650  }
1651  }
1652  }
1653 
1654  if (uret != NULL)
1655  *uret = urlLink(u, "urlConnect");
1656  u = urlFree(u, "urlSplit (urlConnect)");
1657 
1658  return rc;
1659 }
1660 
1661 int ufdGetFile(FD_t sfd, FD_t tfd)
1662 {
1663  int rc;
1664 
1665  FDSANE(sfd);
1666  FDSANE(tfd);
1667  rc = ufdCopy(sfd, tfd);
1668  (void) Fclose(sfd);
1669  if (rc > 0) /* XXX ufdCopy now returns no. bytes copied */
1670  rc = 0;
1671  return rc;
1672 }
1673 
1674 int ftpCmd(const char * cmd, const char * url, const char * arg2)
1675 {
1676  urlinfo u;
1677  int rc;
1678  const char * path;
1679 
1680  if (urlConnect(url, &u) < 0)
1681  return -1;
1682 
1683  (void) urlPath(url, &path);
1684 
1685  rc = ftpCommand(u, NULL, cmd, path, arg2, NULL);
1686  u->ctrl = fdFree(u->ctrl, "grab ctrl (ftpCmd)");
1687  return rc;
1688 }
1689 
1690 /* XXX these aren't worth the pain of including correctly */
1691 #if !defined(IAC)
1692 #define IAC ((unsigned char)255) /* interpret as command: */
1693 #endif
1694 #if !defined(IP)
1695 #define IP ((unsigned char)244) /* interrupt process--permanently */
1696 #endif
1697 #if !defined(DM)
1698 #define DM ((unsigned char)242) /* data mark--for connect. cleaning */
1699 #endif
1700 #if !defined(SHUT_RDWR)
1701 #define SHUT_RDWR 1+1
1702 #endif
1703 
1704 static int ftpAbort(urlinfo u, FD_t data)
1705  /*@globals fileSystem, internalState @*/
1706  /*@modifies u, data, fileSystem, internalState @*/
1707 {
1708  static unsigned char ipbuf[3] = { IAC, IP, IAC };
1709  FD_t ctrl;
1710  int rc;
1711  int tosecs;
1712 
1713  URLSANE(u);
1714 
1715  if (data != NULL) {
1716  data->ftpFileDoneNeeded = 0;
1717  if (fdFileno(data) >= 0)
1718  u->ctrl = fdFree(u->ctrl, "open data (ftpAbort)");
1719  u->ctrl = fdFree(u->ctrl, "grab data (ftpAbort)");
1720  }
1721  ctrl = u->ctrl;
1722 
1723  DBGIO(0, (stderr, "-> ABOR\n"));
1724 
1725 /*@-usereleased -compdef@*/
1726  if (send(fdFileno(ctrl), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
1727  /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1728  return FTPERR_SERVER_IO_ERROR;
1729  }
1730 
1731  sprintf(u->buf, "%cABOR\r\n",(char) DM);
1732  if (fdWrite(ctrl, u->buf, 7) != 7) {
1733  /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1734  return FTPERR_SERVER_IO_ERROR;
1735  }
1736 
1737  if (data && fdFileno(data) >= 0) {
1738  /* XXX shorten data drain time wait */
1739  tosecs = data->rd_timeoutsecs;
1740  data->rd_timeoutsecs = 10;
1741  if (fdReadable(data, data->rd_timeoutsecs) > 0) {
1742 /*@-infloopsuncon@*/
1743  while ((ufdio->read)(data, u->buf, u->bufAlloced) > 0)
1744  u->buf[0] = '\0';
1745 /*@=infloopsuncon@*/
1746  }
1747  data->rd_timeoutsecs = tosecs;
1748  /* XXX ftp abort needs to close the data channel to receive status */
1749  (void) shutdown(fdFileno(data), SHUT_RDWR);
1750  (void) close(fdFileno(data));
1751  data->fps[0].fdno = -1; /* XXX WRONG but expedient */
1752  }
1753 
1754  /* XXX shorten ctrl drain time wait */
1755 assert(u->ctrl != NULL);
1756  tosecs = u->ctrl->rd_timeoutsecs;
1757  u->ctrl->rd_timeoutsecs = 10;
1758  if ((rc = ftpCheckResponse(u, NULL)) == FTPERR_NIC_ABORT_IN_PROGRESS) {
1759  rc = ftpCheckResponse(u, NULL);
1760  }
1761  rc = ftpCheckResponse(u, NULL);
1762  u->ctrl->rd_timeoutsecs = tosecs;
1763 
1764  return rc;
1765 /*@=usereleased =compdef@*/
1766 }
1767 
1769  /*@globals fileSystem @*/
1770  /*@modifies u, data, fileSystem @*/
1771 {
1772  int rc = 0;
1773 
1774  URLSANE(u);
1775  assert(data->ftpFileDoneNeeded);
1776 
1777  if (data->ftpFileDoneNeeded) {
1778  data->ftpFileDoneNeeded = 0;
1779  u->ctrl = fdFree(u->ctrl, "open data (ftpFileDone)");
1780  u->ctrl = fdFree(u->ctrl, "grab data (ftpFileDone)");
1781  rc = ftpCheckResponse(u, NULL);
1782  }
1783  return rc;
1784 }
1785 
1786 #ifndef WITH_NEON
1787 static int httpResp(urlinfo u, FD_t ctrl, /*@out@*/ char ** str)
1788  /*@globals fileSystem @*/
1789  /*@modifies ctrl, *str, fileSystem @*/
1790 {
1791  int ec = 0;
1792  int rc;
1793 
1794  URLSANE(u);
1795  rc = checkResponse(u, ctrl, &ec, str);
1796 
1797 if (_ftp_debug && !(rc == 0 && (ec == 200 || ec == 201)))
1798 fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec);
1799 
1800  switch (ec) {
1801  case 200:
1802  case 201: /* 201 Created. */
1803  break;
1804  case 204: /* HACK: if overwriting, 204 No Content. */
1805  case 403: /* 403 Forbidden. */
1806  ctrl->syserrno = EACCES; /* HACK */
1807  rc = FTPERR_UNKNOWN;
1808  break;
1809  default:
1810  rc = FTPERR_FILE_NOT_FOUND;
1811  break;
1812  }
1813  return rc;
1814 }
1815 
1816 static int httpReq(FD_t ctrl, const char * httpCmd, const char * httpArg)
1817  /*@globals h_errno, fileSystem, internalState @*/
1818  /*@modifies ctrl, fileSystem, internalState @*/
1819 {
1820  urlinfo u;
1821  const char * host;
1822  const char * path;
1823  char hthost[NI_MAXHOST];
1824  int port;
1825  int rc;
1826  char * req;
1827  size_t len;
1828  int retrying = 0;
1829 
1830 assert(ctrl != NULL);
1831  u = ctrl->u;
1832  URLSANE(u);
1833 
1834  if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL))
1835  return FTPERR_BAD_HOSTNAME;
1836  if (strchr(host, ':'))
1837  sprintf(hthost, "[%s]", host);
1838  else
1839  strcpy(hthost, host);
1840 
1841  if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80;
1842  path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg;
1843  if (path == NULL) path = "";
1844 
1845 reopen:
1846  if (fdFileno(ctrl) >= 0 && (rc = fdWritable(ctrl, 0)) < 1) {
1847  /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1848  }
1849 
1850 /*@-usereleased@*/
1851  if (fdFileno(ctrl) < 0) {
1852  rc = tcpConnect(ctrl, host, port);
1853  if (rc < 0)
1854  goto errxit2;
1855  ctrl = fdLink(ctrl, "open ctrl (httpReq)");
1856  }
1857 
1858  len = sizeof("\
1859 req x HTTP/1.0\r\n\
1860 User-Agent: rpm/3.0.4\r\n\
1861 Host: y:z\r\n\
1862 Accept: text/plain\r\n\
1863 Transfer-Encoding: chunked\r\n\
1864 \r\n\
1865 ") + strlen(httpCmd) + strlen(path) + sizeof(VERSION) + strlen(hthost) + 20;
1866 
1867  req = alloca(len);
1868  *req = '\0';
1869 
1870  if (!strcmp(httpCmd, "PUT")) {
1871  sprintf(req, "\
1872 %s %s HTTP/1.%d\r\n\
1873 User-Agent: rpm/%s\r\n\
1874 Host: %s:%d\r\n\
1875 Accept: text/plain\r\n\
1876 Transfer-Encoding: chunked\r\n\
1877 \r\n\
1878 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, hthost, port);
1879 } else {
1880  sprintf(req, "\
1881 %s %s HTTP/1.%d\r\n\
1882 User-Agent: rpm/%s\r\n\
1883 Host: %s:%d\r\n\
1884 Accept: text/plain\r\n\
1885 \r\n\
1886 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, hthost, port);
1887 }
1888 
1889 if (_ftp_debug)
1890 fprintf(stderr, "-> %s", req);
1891 
1892  len = strlen(req);
1893  if (fdWrite(ctrl, req, len) != (ssize_t)len) {
1895  goto errxit;
1896  }
1897 
1898  if (!strcmp(httpCmd, "PUT")) {
1899  ctrl->wr_chunked = 1;
1900  } else {
1901 
1902  rc = httpResp(u, ctrl, NULL);
1903 
1904  if (rc) {
1905  if (!retrying) { /* not HTTP_OK */
1906  retrying = 1;
1907  /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1908  goto reopen;
1909  }
1910  goto errxit;
1911  }
1912  }
1913 
1914  ctrl = fdLink(ctrl, "open data (httpReq)");
1915  return 0;
1916 
1917 errxit:
1918  /*@-observertrans@*/
1919  fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
1920  /*@=observertrans@*/
1921 errxit2:
1922  if (fdFileno(ctrl) >= 0)
1923  /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1924  return rc;
1925 /*@=usereleased@*/
1926 }
1927 #endif /* WITH_NEON */
1928 
1929 /* XXX DYING: unused */
1931 {
1932  FDSANE(fd);
1933  if (fd->u == NULL)
1934  return NULL;
1935 /*@-retexpose@*/
1936  return urlLink(fd->u, "ufdGetUrlinfo");
1937 /*@=retexpose@*/
1938 }
1939 
1940 /* =============================================================== */
1941 static ssize_t ufdRead(void * cookie, /*@out@*/ char * buf, size_t count)
1942  /*@globals fileSystem, internalState @*/
1943  /*@modifies buf, fileSystem, internalState @*/
1944  /*@requires maxSet(buf) >= (count - 1) @*/
1945 {
1946  FD_t fd = c2f(cookie);
1947  size_t bytesRead;
1948  size_t total;
1949 
1950  if (fdGetIo(fd) == fdio) {
1951  struct stat sb;
1952  int fdno = fdFileno(fd);
1953  (void) fstat(fdno, &sb);
1954  if (S_ISREG(sb.st_mode))
1955  return fdRead(fd, buf, count);
1956  }
1957 
1958  UFDONLY(fd);
1959  assert(fd->rd_timeoutsecs >= 0);
1960 
1961  for (total = 0; total < count; total += bytesRead) {
1962 
1963  int rc;
1964 
1965  bytesRead = 0;
1966 
1967  /* Is there data to read? */
1968  if (fd->bytesRemain == 0) return (ssize_t) total; /* XXX simulate EOF */
1969  rc = fdReadable(fd, fd->rd_timeoutsecs);
1970 
1971  switch (rc) {
1972  case -1: /* error */
1973  case 0: /* timeout */
1974  return (ssize_t) total;
1975  /*@notreached@*/ /*@switchbreak@*/ break;
1976  default: /* data to read */
1977  /*@switchbreak@*/ break;
1978  }
1979 
1980  rc = (int) fdRead(fd, buf + total, count - total);
1981 
1982  if (rc < 0) {
1983  switch (errno) {
1984  case EWOULDBLOCK:
1985  continue;
1986  /*@notreached@*/ /*@switchbreak@*/ break;
1987  default:
1988  /*@switchbreak@*/ break;
1989  }
1990 if (_rpmio_debug)
1991 fprintf(stderr, "*** read: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
1992  return rc;
1993  /*@notreached@*/ break;
1994  } else if (rc == 0) {
1995  return (ssize_t) total;
1996  /*@notreached@*/ break;
1997  }
1998  bytesRead = (size_t) rc;
1999  }
2000 
2001  return (ssize_t) count;
2002 }
2003 
2004 static ssize_t ufdWrite(void * cookie, const char * buf, size_t count)
2005  /*@globals fileSystem, internalState @*/
2006  /*@modifies fileSystem, internalState @*/
2007 {
2008  FD_t fd = c2f(cookie);
2009  size_t bytesWritten;
2010  size_t total = 0;
2011 
2012 #ifdef NOTYET
2013  if (fdGetIo(fd) == fdio) {
2014  struct stat sb;
2015  (void) fstat(fdGetFdno(fd), &sb);
2016  if (S_ISREG(sb.st_mode))
2017  return fdWrite(fd, buf, count);
2018  }
2019 #endif
2020 
2021  UFDONLY(fd);
2022 
2023  for (total = 0; total < count; total += bytesWritten) {
2024 
2025  int rc;
2026 
2027  bytesWritten = 0;
2028 
2029  /* Is there room to write data? */
2030  if (fd->bytesRemain == 0) {
2031 fprintf(stderr, "*** ufdWrite fd %p WRITE PAST END OF CONTENT\n", fd);
2032  return (ssize_t) total; /* XXX simulate EOF */
2033  }
2034  rc = fdWritable(fd, 2); /* XXX configurable? */
2035 
2036  switch (rc) {
2037  case -1: /* error */
2038  case 0: /* timeout */
2039  return (ssize_t) total;
2040  /*@notreached@*/ /*@switchbreak@*/ break;
2041  default: /* data to write */
2042  /*@switchbreak@*/ break;
2043  }
2044 
2045  rc = (int) fdWrite(fd, buf + total, count - total);
2046 
2047  if (rc < 0) {
2048  switch (errno) {
2049  case EWOULDBLOCK:
2050  continue;
2051  /*@notreached@*/ /*@switchbreak@*/ break;
2052  default:
2053  /*@switchbreak@*/ break;
2054  }
2055 if (_rpmio_debug)
2056 fprintf(stderr, "*** write: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
2057  return rc;
2058  /*@notreached@*/ break;
2059  } else if (rc == 0) {
2060  return (ssize_t) total;
2061  /*@notreached@*/ break;
2062  }
2063  bytesWritten = (size_t) rc;
2064  }
2065 
2066  return (ssize_t) count;
2067 }
2068 
2069 static int ufdSeek(void * cookie, _libio_pos_t pos, int whence)
2070  /*@globals fileSystem, internalState @*/
2071  /*@modifies fileSystem, internalState @*/
2072 {
2073  FD_t fd = c2f(cookie);
2074 
2075  switch (urlType(fd->u)) {
2076  case URL_IS_UNKNOWN:
2077  case URL_IS_PATH:
2078  break;
2079  case URL_IS_DASH:
2080  case URL_IS_HKP:
2081  case URL_IS_FTP:
2082  case URL_IS_HTTP:
2083  case URL_IS_HTTPS:
2084  case URL_IS_MONGO: /* XXX FIXME */
2085  default:
2086  return -2;
2087  /*@notreached@*/ break;
2088  }
2089  return fdSeek(cookie, pos, whence);
2090 }
2091 
2092 /*@-usereleased@*/ /* LCL: fd handling is tricky here. */
2093 int ufdClose( /*@only@*/ void * cookie)
2094 {
2095  FD_t fd = c2f(cookie);
2096 
2097  UFDONLY(fd);
2098 
2099  if (fd->u) {
2100  urlinfo u = (urlinfo) fd->u;
2101 
2102 /*@-evalorder @*/
2103  if (fd == u->data)
2104  fd = u->data = fdFree(fd, "grab data (ufdClose persist)");
2105  else
2106  fd = fdFree(fd, "grab data (ufdClose)");
2107 assert(fd != NULL);
2108  (void) urlFree(fd->u, "url (ufdClose)");
2109  fd->u = NULL;
2110  u->ctrl = fdFree(u->ctrl, "grab ctrl (ufdClose)");
2111 /*@=evalorder @*/
2112 
2113  if (urlType(u) == URL_IS_FTP) {
2114 
2115  /* XXX if not using libio, lose the fp from fpio */
2116  { FILE * fp;
2117  /*@+voidabstract -nullpass@*/
2118  fp = fdGetFILE(fd);
2119  if (noLibio && fp)
2120  fdSetFp(fd, NULL);
2121  /*@=voidabstract =nullpass@*/
2122  }
2123 
2124  /*
2125  * Non-error FTP has 4 refs on the data fd:
2126  * "persist data (ufdOpen FTP)" rpmio.c:888
2127  * "grab data (ufdOpen FTP)" rpmio.c:892
2128  * "open data (ftpReq)" ftp.c:633
2129  * "fopencookie" rpmio.c:1507
2130  *
2131  * Non-error FTP has 5 refs on the ctrl fd:
2132  * "persist ctrl" url.c:176
2133  * "grab ctrl (urlConnect FTP)" rpmio.c:404
2134  * "open ctrl" ftp.c:504
2135  * "grab data (ftpReq)" ftp.c:661
2136  * "open data (ftpReq)" ftp.c:662
2137  */
2138  if (fd->bytesRemain > 0) {
2139  if (fd->ftpFileDoneNeeded) {
2140  if (fdReadable(u->ctrl, 0) > 0)
2141  (void) ftpFileDone(u, fd);
2142  else
2143  (void) ftpAbort(u, fd);
2144  }
2145  } else {
2146  int rc;
2147  /* XXX STOR et al require close before ftpFileDone */
2148  /*@-refcounttrans@*/
2149  rc = fdClose(fd);
2150  /*@=refcounttrans@*/
2151 #if 0 /* XXX error exit from ufdOpen does not have this set */
2152  assert(fd->ftpFileDoneNeeded != 0);
2153 #endif
2154  /*@-compdef@*/ /* FIX: u->data undefined */
2155  if (fd->ftpFileDoneNeeded)
2156  (void) ftpFileDone(u, fd);
2157  /*@=compdef@*/
2158  return rc;
2159  }
2160  }
2161 
2162  /* XXX Why not (u->urltype == URL_IS_HTTP) ??? */
2163  /* XXX Why not (u->urltype == URL_IS_HTTPS) ??? */
2164  /* XXX Why not (u->urltype == URL_IS_HKP) ??? */
2165  if (u->scheme != NULL
2166  && (!strncmp(u->scheme, "http", sizeof("http")-1) || !strncmp(u->scheme, "hkp", sizeof("hkp")-1)))
2167  {
2168  /*
2169  * HTTP has 4 (or 5 if persistent malloc) refs on the fd:
2170  * "persist ctrl" url.c:177
2171  * "grab ctrl (ufdOpen HTTP)" rpmio.c:924
2172  * "grab data (ufdOpen HTTP)" rpmio.c:928
2173  * "open ctrl (httpReq)" ftp.c:382
2174  * "open data (httpReq)" ftp.c:435
2175  */
2176 
2177 /*@-evalorder @*/
2178  if (fd == u->ctrl)
2179  fd = u->ctrl = fdFree(fd, "open data (ufdClose HTTP persist ctrl)");
2180  else if (fd == u->data)
2181  fd = u->data = fdFree(fd, "open data (ufdClose HTTP persist data)");
2182  else
2183  fd = fdFree(fd, "open data (ufdClose HTTP)");
2184 /*@=evalorder @*/
2185 
2186  /* XXX if not using libio, lose the fp from fpio */
2187  { FILE * fp;
2188  /*@+voidabstract -nullpass@*/
2189  fp = fdGetFILE(fd);
2190  if (noLibio && fp)
2191  fdSetFp(fd, NULL);
2192  /*@=voidabstract =nullpass@*/
2193  }
2194 
2195  /* If content remains, then don't persist. */
2196 assert(fd != NULL);
2197  if (fd->bytesRemain > 0) {
2198  fd->persist = 0;
2199  }
2200  fd->contentLength = fd->bytesRemain = -1;
2201 
2202  /* If persisting, then Fclose will juggle refcounts. */
2203  if (fd->persist && (fd == u->ctrl || fd == u->data))
2204  return 0;
2205  }
2206  }
2207  return fdClose(fd);
2208 }
2209 /*@=usereleased@*/
2210 
2211 /*@-nullstate@*/ /* FIX: u->{ctrl,data}->u undef after XurlLink. */
2212 /*@null@*/ FD_t ftpOpen(const char *url, /*@unused@*/ int flags,
2213  /*@unused@*/ mode_t mode, /*@out@*/ urlinfo *uret)
2214  /*@modifies *uret @*/
2215 {
2216  urlinfo u = NULL;
2217  FD_t fd = NULL;
2218 
2219 #if 0 /* XXX makeTempFile() heartburn */
2220  assert(!(flags & O_RDWR));
2221 #endif
2222  if (urlConnect(url, &u) < 0)
2223  goto exit;
2224 
2225  if (u->data == NULL)
2226  u->data = fdNew("persist data (ftpOpen)");
2227 
2228 assert(u->data != NULL);
2229 /*@-unqualifiedtrans@*/
2230  if (u->data->u == NULL)
2231  fd = u->data = fdLink(u->data, "grab data (ftpOpen persist data)");
2232  else
2233  fd = fdNew("grab data (ftpOpen)");
2234 /*@=unqualifiedtrans@*/
2235 
2236  if (fd != NULL) {
2237  fdSetOpen(fd, url, flags, mode);
2238  fdSetIo(fd, ufdio);
2239  fd->ftpFileDoneNeeded = 0;
2241  fd->contentLength = fd->bytesRemain = -1;
2242 /*@-usereleased@*/
2243  fd->u = urlLink(u, "url (ufdOpen FTP)");
2244 /*@=usereleased@*/
2245  }
2246 
2247 exit:
2248  if (uret)
2249  *uret = u;
2250  /*@-refcounttrans@*/
2251  return fd;
2252  /*@=refcounttrans@*/
2253 }
2254 /*@=nullstate@*/
2255 
2256 static /*@null@*/ FD_t ufdOpen(const char * url, int flags, mode_t mode)
2257  /*@globals h_errno, fileSystem, internalState @*/
2258  /*@modifies fileSystem, internalState @*/
2259 {
2260  FD_t fd = NULL;
2261  const char * cmd;
2262  urlinfo u;
2263  const char * path;
2264  urltype ut = urlPath(url, &path);
2265 
2266 if (_rpmio_debug)
2267 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
2268 
2269 /*@-usereleased@*/
2270  switch (ut) {
2271  case URL_IS_FTP:
2272  fd = ftpOpen(url, flags, mode, &u);
2273  if (fd == NULL || u == NULL)
2274  break;
2275 
2276  /* XXX W2DO? use STOU rather than STOR to prevent clobbering */
2277  cmd = ((flags & O_WRONLY)
2278  ? ((flags & O_APPEND) ? "APPE" :
2279  ((flags & O_CREAT) ? "STOR" : "STOR"))
2280  : ((flags & O_CREAT) ? "STOR" : "RETR"));
2281  u->openError = ftpReq(fd, cmd, path);
2282  if (u->openError < 0) {
2283  /* XXX make sure that we can exit through ufdClose */
2284  fd = fdLink(fd, "error data (ufdOpen FTP)");
2285  } else {
2286  fd->bytesRemain = ((!strcmp(cmd, "RETR"))
2287  ? fd->contentLength : -1);
2288  fd->wr_chunked = 0;
2289  }
2290  break;
2291  case URL_IS_HKP:
2292  case URL_IS_HTTP:
2293  case URL_IS_HTTPS:
2294 #ifdef WITH_NEON
2295  fd = davOpen(url, flags, mode, &u);
2296 #else
2297  fd = httpOpen(url, flags, mode, &u);
2298 #endif
2299  if (fd == NULL || u == NULL)
2300  break;
2301 
2302  cmd = ((flags & O_WRONLY)
2303  ? ((flags & O_APPEND) ? "PUT" :
2304  ((flags & O_CREAT) ? "PUT" : "PUT"))
2305  : "GET");
2306 #ifdef WITH_NEON
2307  u->openError = davReq(fd, cmd, path);
2308 #else
2309  u->openError = httpReq(fd, cmd, path);
2310 #endif
2311  if (u->openError < 0) {
2312  /* XXX make sure that we can exit through ufdClose */
2313  fd = fdLink(fd, "error ctrl (ufdOpen HTTP)");
2314  fd = fdLink(fd, "error data (ufdOpen HTTP)");
2315  } else {
2316  fd->bytesRemain = ((!strcmp(cmd, "GET"))
2317  ? fd->contentLength : -1);
2318  fd->wr_chunked = ((!strcmp(cmd, "PUT"))
2319  ? fd->wr_chunked : 0);
2320  }
2321  break;
2322  case URL_IS_MONGO: /* XXX FIXME */
2323  break;
2324  case URL_IS_DASH:
2325  assert(!(flags & O_RDWR));
2326  fd = fdDup( ((flags & O_WRONLY) ? STDOUT_FILENO : STDIN_FILENO) );
2327  if (fd) {
2328  fdSetOpen(fd, url, flags, mode);
2329  fdSetIo(fd, ufdio);
2330  fd->rd_timeoutsecs = 600; /* XXX W2DO? 10 mins? */
2331  fd->contentLength = fd->bytesRemain = -1;
2332  }
2333  break;
2334  case URL_IS_PATH:
2335  case URL_IS_UNKNOWN:
2336  default:
2337  fd = fdOpen(path, flags, mode);
2338  if (fd) {
2339  fdSetIo(fd, ufdio);
2340  fd->rd_timeoutsecs = 1;
2341  fd->contentLength = fd->bytesRemain = -1;
2342  }
2343  break;
2344  }
2345 
2346  if (fd == NULL) return NULL;
2347  if (Fileno(fd) < 0) {
2348  (void) ufdClose(fd);
2349  return NULL;
2350  }
2351 /*@=usereleased@*/
2352 DBGIO(fd, (stderr, "<--\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd)));
2353  return fd;
2354 }
2355 
2356 /*@-type@*/ /* LCL: function typedefs */
2357 static struct FDIO_s ufdio_s = {
2358  ufdRead, ufdWrite, ufdSeek, ufdClose, NULL, NULL, NULL,
2359 };
2360 /*@=type@*/
2361 
2362 FDIO_t ufdio = /*@-compmempass@*/ &ufdio_s /*@=compmempass@*/ ;
2363 
2364 /* =============================================================== */
2365 /*@observer@*/
2366 static const char * getFdErrstr (FD_t fd)
2367  /*@*/
2368 {
2369  const char *errstr = NULL;
2370 
2371 #if defined(WITH_ZLIB)
2372  if (fdGetIo(fd) == gzdio) {
2373  errstr = (const char *)fd->errcookie;
2374  } else
2375 #endif /* WITH_ZLIB */
2376 
2377 #if defined(WITH_BZIP2)
2378  if (fdGetIo(fd) == bzdio) {
2379  errstr = (const char *)fd->errcookie;
2380  } else
2381 #endif
2382 
2383 #if defined(WITH_XZ)
2384  if (fdGetIo(fd) == lzdio) {
2385  errstr = (const char *)fd->errcookie;
2386  } else
2387  if (fdGetIo(fd) == xzdio) {
2388  errstr = (const char *)fd->errcookie;
2389  } else
2390 #endif
2391 
2392  {
2393  errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
2394  }
2395 
2396  return errstr;
2397 }
2398 
2399 /* =============================================================== */
2400 
2401 const char *Fstrerror(FD_t fd)
2402 {
2403  if (fd == NULL)
2404  return (errno ? strerror(errno) : "");
2405  FDSANE(fd);
2406  return getFdErrstr(fd);
2407 }
2408 
2409 #define FDIOVEC(_fd, _vec) \
2410  ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
2411 
2412 size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) {
2413  fdio_read_function_t _read;
2414  int rc;
2415 
2416  FDSANE(fd);
2417 DBGIO(fd, (stderr, "==> Fread(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
2418 
2419  if (fdGetIo(fd) == fpio) {
2420  /*@+voidabstract -nullpass@*/
2421  rc = (int) fread(buf, size, nmemb, fdGetFILE(fd));
2422  /*@=voidabstract =nullpass@*/
2423  return (size_t) rc;
2424  }
2425 
2426  /*@-nullderef@*/
2427  _read = FDIOVEC(fd, read);
2428  /*@=nullderef@*/
2429 
2430  rc = (int) (_read ? (*_read) (fd, (char *)buf, size * nmemb) : -2);
2431  return (size_t) rc;
2432 }
2433 
2434 size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
2435 {
2436  fdio_write_function_t _write;
2437  int rc;
2438 
2439  FDSANE(fd);
2440 DBGIO(fd, (stderr, "==> Fwrite(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
2441 
2442  if (fdGetIo(fd) == fpio) {
2443  /*@+voidabstract -nullpass@*/
2444  rc = (int) fwrite(buf, size, nmemb, fdGetFILE(fd));
2445  /*@=voidabstract =nullpass@*/
2446  return (size_t) rc;
2447  }
2448 
2449  /*@-nullderef@*/
2450  _write = FDIOVEC(fd, write);
2451  /*@=nullderef@*/
2452 
2453  rc = (int) (_write ? _write(fd, (const char *)buf, size * nmemb) : -2);
2454  return (size_t) rc;
2455 }
2456 
2457 int Fseek(FD_t fd, _libio_off_t offset, int whence)
2458 {
2459  fdio_seek_function_t _seek;
2460 #ifdef USE_COOKIE_SEEK_POINTER
2461  _IO_off64_t o64 = offset;
2462  _libio_pos_t pos = &o64;
2463 #else
2464  _libio_pos_t pos = offset;
2465 #endif
2466 
2467  long int rc;
2468 
2469  FDSANE(fd);
2470 DBGIO(fd, (stderr, "==> Fseek(%p,%ld,%d) %s\n", fd, (long)offset, whence, fdbg(fd)));
2471 
2472  if (fdGetIo(fd) == fpio)
2473  return fseek(fdGetFILE(fd), (long)offset, whence);
2474 
2475  /*@-nullderef@*/
2476  _seek = FDIOVEC(fd, seek);
2477  /*@=nullderef@*/
2478 
2479  rc = (_seek ? _seek(fd, pos, whence) : -2);
2480  return rc;
2481 }
2482 
2483 long Ftell(FD_t fd)
2484 {
2485  long int rc = -2;
2486 
2487  FDSANE(fd);
2488 
2489  if (fdGetIo(fd) == fpio)
2490  rc = ftell(fdGetFILE(fd));
2491  else
2492  errno = EBADF;
2493 DBGIO(fd, (stderr, "<== Ftell(%p) rc %ld %s\n", fd, rc, fdbg(fd)));
2494  return rc;
2495 }
2496 
2497 void Rewind(FD_t fd)
2498 {
2499  FDSANE(fd);
2500 DBGIO(fd, (stderr, "==> Rewind(%p) %s\n", fd, fdbg(fd)));
2501 
2502  if (fdGetIo(fd) == fpio)
2503  rewind(fdGetFILE(fd));
2504 }
2505 
2506 int Fgetpos(FD_t fd, fpos_t *pos)
2507 {
2508  int rc = -2;
2509 
2510  FDSANE(fd);
2511 
2512  if (fdGetIo(fd) == fpio)
2513  rc = fgetpos(fdGetFILE(fd), pos);
2514  else
2515  errno = EBADF;
2516 DBGIO(fd, (stderr, "<== Fgetpos(%p,%p) rc %d %s\n", fd, pos, rc, fdbg(fd)));
2517  return rc;
2518 }
2519 
2520 int Fsetpos(FD_t fd, fpos_t *pos)
2521 {
2522  int rc = -2;
2523 
2524  FDSANE(fd);
2525 
2526  if (fdGetIo(fd) == fpio)
2527  return fgetpos(fdGetFILE(fd), pos);
2528 
2529  errno = EBADF;
2530 DBGIO(fd, (stderr, "<== Fsetpos(%p,%p) rc %d %s\n", fd, pos, rc, fdbg(fd)));
2531  return rc;
2532 }
2533 
2534 int Fclose(FD_t fd)
2535 {
2536  int rc = 0, ec = 0;
2537 
2538  FDSANE(fd);
2539 DBGIO(fd, (stderr, "==> Fclose(%p) %s\n", (fd ? fd : NULL), fdbg(fd)));
2540 
2541 /*@-usereleased@*/
2542  fd = fdLink(fd, "Fclose");
2543  if (fd != NULL)
2544  while (fd->nfps >= 0) {
2545  FDSTACK_t * fps = &fd->fps[fd->nfps];
2546 
2547  if (fps->io == fpio) {
2548  FILE *fp;
2549  int fpno;
2550 
2551  /*@+voidabstract -nullpass@*/
2552  fp = fdGetFILE(fd);
2553  fpno = fileno(fp);
2554  /*@=voidabstract =nullpass@*/
2555  /* XXX persistent HTTP/1.1 returns the previously opened fp */
2556  if (fd->nfps > 0 && fpno == -1 &&
2557  fd->fps[fd->nfps-1].io == ufdio &&
2558  fd->fps[fd->nfps-1].fp == fp &&
2559  (fd->fps[fd->nfps-1].fdno >= 0 || fd->req != NULL))
2560  {
2561  int hadreqpersist = (fd->req != NULL);
2562 
2563  if (fp)
2564  rc = fflush(fp);
2565  fd->nfps--;
2566  /*@-refcounttrans@*/
2567  rc = ufdClose(fd);
2568  /*@=refcounttrans@*/
2569  if (fdGetFdno(fd) >= 0)
2570  break;
2571  if (!fd->persist)
2572  hadreqpersist = 0;
2573  fdSetFp(fd, NULL);
2574  fd->nfps++;
2575  if (fp) {
2576  /* HACK: flimsy Keepalive wiring. */
2577  if (hadreqpersist) {
2578 #ifdef NOTYET /* XXX not quite right yet. */
2579  (void) davDisconnect(fd);
2580  fd->req = NULL;
2581 #endif
2582  fd->nfps--;
2583 /*@-exposetrans@*/
2584  fdSetFp(fd, fp);
2585 /*@=exposetrans@*/
2586 /*@-refcounttrans@*/
2587  (void) fdClose(fd);
2588 /*@=refcounttrans@*/
2589  fdSetFp(fd, NULL);
2590  fd->nfps++;
2591 /*@-refcounttrans@*/
2592  (void) fdClose(fd);
2593 /*@=refcounttrans@*/
2594  } else
2595  rc = fclose(fp);
2596  }
2597  fdPop(fd);
2598  if (noLibio)
2599  fdSetFp(fd, NULL);
2600  } else {
2601  if (fp)
2602  rc = fclose(fp);
2603  if (fpno == -1) {
2604  fd = fdFree(fd, "fopencookie (Fclose)");
2605  fdPop(fd);
2606  }
2607  }
2608  } else {
2609  /*@-nullderef@*/
2610  fdio_close_function_t _close = FDIOVEC(fd, close);
2611  /*@=nullderef@*/
2612  rc = _close(fd);
2613  }
2614  if (fd == NULL || fd->nfps == 0) /* XXX fd != NULL ever */
2615  break;
2616  if (ec == 0 && rc)
2617  ec = rc;
2618  fdPop(fd);
2619  }
2620  fd = fdFree(fd, "Fclose");
2621  return ec;
2622 /*@=usereleased@*/
2623 }
2624 
2642 static inline void cvtfmode (const char *m,
2643  /*@out@*/ char *stdio, size_t nstdio,
2644  /*@out@*/ char *other, size_t nother,
2645  /*@out@*/ const char **end, /*@out@*/ int * f)
2646  /*@modifies *stdio, *other, *end, *f @*/
2647 {
2648  int flags = 0;
2649  char c;
2650 
2651  switch (*m) {
2652  case 'a':
2653  flags |= O_WRONLY | O_CREAT | O_APPEND;
2654  if (--nstdio > 0) *stdio++ = *m;
2655  break;
2656  case 'w':
2657  flags |= O_WRONLY | O_CREAT | O_TRUNC;
2658  if (--nstdio > 0) *stdio++ = *m;
2659  break;
2660  case 'r':
2661  flags |= O_RDONLY;
2662  if (--nstdio > 0) *stdio++ = *m;
2663  break;
2664  default:
2665  *stdio = '\0';
2666  return;
2667  /*@notreached@*/ break;
2668  }
2669  m++;
2670 
2671  while ((c = *m++) != '\0') {
2672  switch (c) {
2673  case '.':
2674  /*@switchbreak@*/ break;
2675  case '+':
2676  flags &= ~(O_RDONLY|O_WRONLY);
2677  flags |= O_RDWR;
2678  if (--nstdio > 0) *stdio++ = c;
2679  continue;
2680  /*@notreached@*/ /*@switchbreak@*/ break;
2681  case 'x': /* glibc: open file exclusively. */
2682  flags |= O_EXCL;
2683  /*@fallthrough@*/
2684  case 'm': /* glibc: mmap'd reads */
2685  case 'c': /* glibc: no cancel */
2686 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3
2687  if (--nstdio > 0) *stdio++ = c;
2688 #endif
2689  continue;
2690  /*@notreached@*/ /*@switchbreak@*/ break;
2691  case 'b':
2692  if (--nstdio > 0) *stdio++ = c;
2693  continue;
2694  /*@notreached@*/ /*@switchbreak@*/ break;
2695  default:
2696  if (--nother > 0) *other++ = c;
2697  continue;
2698  /*@notreached@*/ /*@switchbreak@*/ break;
2699  }
2700  break;
2701  }
2702  if (c == '\0') m--; /* one too far */
2703 
2704  *stdio = *other = '\0';
2705  if (end != NULL)
2706  *end = (*m != '\0' ? m : NULL);
2707  if (f != NULL)
2708  *f = flags;
2709 }
2710 
2711 #if _USE_LIBIO
2712 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
2713 /* XXX retrofit glibc-2.1.x typedef on glibc-2.0.x systems */
2714 typedef _IO_cookie_io_functions_t cookie_io_functions_t;
2715 #endif
2716 #endif
2717 
2718 FD_t Fdopen(FD_t ofd, const char *fmode)
2719 {
2720  char stdio[20], other[20], zstdio[40+1];
2721  const char *end = NULL;
2722  FDIO_t iof = NULL;
2723  FD_t fd = ofd;
2724 
2725 if (_rpmio_debug)
2726 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
2727  FDSANE(fd);
2728 
2729  if (fmode == NULL)
2730  return NULL;
2731 
2732  cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
2733  if (stdio[0] == '\0')
2734  return NULL;
2735  zstdio[0] = '\0';
2736  (void) stpcpy( stpcpy(zstdio, stdio), other);
2737 
2738  if (end == NULL && other[0] == '\0')
2739  /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
2740 
2741  if (end && *end) {
2742  if (!strcmp(end, "fdio")) {
2743  iof = fdio;
2744 #if defined(WITH_ZLIB)
2745  } else if (!strcmp(end, "gzdio")) {
2746  iof = gzdio;
2747  /*@-internalglobs@*/
2748  fd = iof->_fdopen(fd, zstdio);
2749  /*@=internalglobs@*/
2750 #endif
2751 #if defined(WITH_BZIP2)
2752  } else if (!strcmp(end, "bzdio")) {
2753  iof = bzdio;
2754  /*@-internalglobs@*/
2755  fd = iof->_fdopen(fd, zstdio);
2756  /*@=internalglobs@*/
2757 #endif
2758 #if defined(WITH_XZ)
2759  } else if (!strcmp(end, "lzdio")) {
2760  iof = lzdio;
2761  fd = iof->_fdopen(fd, zstdio);
2762  } else if (!strcmp(end, "xzdio")) {
2763  iof = xzdio;
2764  fd = iof->_fdopen(fd, zstdio);
2765 #endif
2766  } else if (!strcmp(end, "ufdio")) {
2767  iof = ufdio;
2768  } else if (!strcmp(end, "fpio")) {
2769  iof = fpio;
2770  if (noLibio) {
2771  int fdno = Fileno(fd);
2772  FILE * fp = fdopen(fdno, stdio);
2773 /*@+voidabstract -nullpass@*/
2774 if (_rpmio_debug)
2775 fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp);
2776 /*@=voidabstract =nullpass@*/
2777  if (fp == NULL)
2778  return NULL;
2779  /* XXX gzdio/bzdio use fp for private data */
2780  /*@+voidabstract@*/
2781  if (fdGetFp(fd) == NULL)
2782  fdSetFp(fd, fp);
2783  fdPush(fd, fpio, fp, fdno); /* Push fpio onto stack */
2784  /*@=voidabstract@*/
2785  }
2786  }
2787  } else if (other[0] != '\0') {
2788  for (end = other; *end && strchr("0123456789fh", *end); end++)
2789  {};
2790  if (*end == '\0') {
2791 #if defined(WITH_ZLIB)
2792  iof = gzdio;
2793  /*@-internalglobs@*/
2794  fd = iof->_fdopen(fd, zstdio);
2795  /*@=internalglobs@*/
2796 #endif
2797  }
2798  }
2799  if (iof == NULL)
2800  /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
2801 
2802  if (!noLibio) {
2803  FILE * fp = NULL;
2804 
2805 #if _USE_LIBIO
2806  { cookie_io_functions_t ciof;
2807  ciof.read = iof->read;
2808  ciof.write = iof->write;
2809  ciof.seek = iof->seek;
2810  ciof.close = iof->close;
2811  fp = fopencookie(fd, stdio, ciof);
2812 DBGIO(fd, (stderr, "<-- fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp));
2813  }
2814 #endif
2815 
2816  if (fp) {
2817  /* XXX gzdio/bzdio use fp for private data */
2818  /*@+voidabstract -nullpass@*/
2819  if (fdGetFp(fd) == NULL)
2820  fdSetFp(fd, fp);
2821  fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
2822  /*@=voidabstract =nullpass@*/
2823  fd = fdLink(fd, "fopencookie");
2824  }
2825  }
2826 
2827 /*@-refcounttrans -retalias -usereleased @*/
2828 DBGIO(fd, (stderr, "<== Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
2829  return fd;
2830 /*@=refcounttrans =retalias =usereleased @*/
2831 }
2832 
2833 FD_t Fopen(const char *path, const char *_fmode)
2834 {
2835  const char * fmode = NULL;
2836  char stdio[20], other[20];
2837  const char *end = NULL;
2838  mode_t perms = 0666;
2839  int flags = 0;
2840  FD_t fd = NULL;
2841 
2842  if (path == NULL || _fmode == NULL)
2843  goto exit;
2844 /*@-globs -mods@*/
2845  fmode = rpmExpand(_fmode, NULL);
2846 /*@=globs =mods@*/
2847 
2848 if (_rpmio_debug)
2849 fprintf(stderr, "==> Fopen(%s, %s)\n", path, fmode);
2850 
2851  stdio[0] = '\0';
2852  cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
2853  if (stdio[0] == '\0')
2854  goto exit;
2855 
2856  if (end && !strcmp(end, "fdio")) {
2857  fd = fdOpen(path, flags, perms);
2858  if (fdFileno(fd) < 0) {
2859  if (fd) (void) fdClose(fd);
2860  fd = NULL;
2861  goto exit;
2862  }
2863  } else {
2864  FILE *fp;
2865  int fdno;
2866  int isHTTP = 0;
2867 
2868  /* XXX gzdio/bzdio/lzdio through here too */
2869 
2870  switch (urlIsURL(path)) {
2871  case URL_IS_HKP:
2872  case URL_IS_HTTP:
2873  case URL_IS_HTTPS:
2874  isHTTP = 1;
2875  /*@fallthrough@*/
2876  case URL_IS_PATH:
2877  case URL_IS_DASH:
2878  case URL_IS_FTP:
2879  case URL_IS_UNKNOWN:
2880  fd = ufdOpen(path, flags, perms);
2881  if (fd == NULL || !(fdFileno(fd) >= 0 || fd->req != NULL)) {
2882  if (fd) (void) fdClose(fd);
2883  fd = NULL;
2884  goto exit;
2885  }
2886  break;
2887  case URL_IS_MONGO: /* XXX FIXME */
2888  default:
2889  if (fd) (void) fdClose(fd);
2890  fd = NULL;
2891  goto exit;
2892  /*@notreached@*/ break;
2893  }
2894 
2895  /* XXX persistent HTTP/1.1 returns the previously opened fp */
2896  if (isHTTP && ((fp = (FILE *) fdGetFp(fd)) != NULL)
2897  && ((fdno = fdGetFdno(fd)) >= 0 || fd->req != NULL))
2898  {
2899  /*@+voidabstract@*/
2900  fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
2901  /*@=voidabstract@*/
2902  goto exit;
2903  }
2904  }
2905 
2906  if (fd)
2907  fd = Fdopen(fd, fmode);
2908 exit:
2909 
2910 if (_rpmio_debug)
2911 fprintf(stderr, "<== Fopen(%s, %s) fd %p\n", path, fmode, fd);
2912  fmode = _free(fmode);
2913  return fd;
2914 }
2915 
2916 int Fflush(FD_t fd)
2917 {
2918  void * vh;
2919  if (fd == NULL) return -1;
2920  if (fdGetIo(fd) == fpio)
2921  /*@+voidabstract -nullpass@*/
2922  return fflush(fdGetFILE(fd));
2923  /*@=voidabstract =nullpass@*/
2924 
2925  vh = fdGetFp(fd);
2926 #if defined(WITH_ZLIB)
2927  if (vh && fdGetIo(fd) == gzdio && gzdio->_flush != NULL)
2928  return (*gzdio->_flush) ((void *)fd);
2929 #endif
2930 #if defined(WITH_BZIP2)
2931  if (vh && fdGetIo(fd) == bzdio && bzdio->_flush != NULL)
2932  return (*bzdio->_flush) ((void *)fd);
2933 #endif
2934 #if defined(WITH_XZ)
2935  if (vh && fdGetIo(fd) == lzdio && lzdio->_flush != NULL)
2936  return (*lzdio->_flush) ((void *)fd);
2937  if (vh && fdGetIo(fd) == xzdio && xzdio->_flush != NULL)
2938  return (*xzdio->_flush) ((void *)fd);
2939 #endif
2940 
2941  return 0;
2942 }
2943 
2944 int Ferror(FD_t fd)
2945 {
2946  int i, rc = 0;
2947 
2948  if (fd == NULL) return -1;
2949  if (fd->req != NULL) {
2950  /* HACK: flimsy wiring for neon errors. */
2951  rc = (fd->req == (void *)-1 || fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2952  } else
2953  for (i = fd->nfps; rc == 0 && i >= 0; i--) {
2954  FDSTACK_t * fps = &fd->fps[i];
2955  int ec;
2956 
2957  if (fps->io == fpio) {
2958  /*@+voidabstract -nullpass@*/
2959  ec = ferror(fdGetFILE(fd));
2960  /*@=voidabstract =nullpass@*/
2961 #if defined(WITH_ZLIB)
2962  } else if (fps->io == gzdio) {
2963  ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2964  i--; /* XXX fdio under gzdio always has fdno == -1 */
2965 #endif
2966 #if defined(WITH_BZIP2)
2967  } else if (fps->io == bzdio) {
2968  ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2969  i--; /* XXX fdio under bzdio always has fdno == -1 */
2970 #endif
2971 #if defined(WITH_XZ)
2972  } else if (fps->io == lzdio) {
2973  ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2974  i--; /* XXX fdio under lzdio always has fdno == -1 */
2975  } else if (fps->io == xzdio) {
2976  ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2977  i--; /* XXX fdio under xzdio always has fdno == -1 */
2978 #endif
2979  } else {
2980  /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
2981  ec = (fdFileno(fd) < 0 ? -1 : 0);
2982  }
2983 
2984  if (rc == 0 && ec)
2985  rc = ec;
2986  }
2987 DBGIO(fd, (stderr, "<== Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
2988  return rc;
2989 }
2990 
2991 int Fileno(FD_t fd)
2992 {
2993  int i, rc = -1;
2994 
2995  if (fd == NULL)
2996  return -1;
2997  if (fd->req != NULL)
2998  rc = 123456789; /* HACK: https has no steenkin fileno. */
2999  else
3000  for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
3001  rc = fd->fps[i].fdno;
3002  }
3003 
3004 DBGIO(fd, (stderr, "<== Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
3005  return rc;
3006 }
3007 
3008 /* XXX this is naive */
3009 int Fcntl(FD_t fd, int op, void *lip)
3010 {
3011  return fcntl(Fileno(fd), op, lip);
3012 }
3013 
3014 /* =============================================================== */
3015 /* Helper routines that may be generally useful.
3016  */
3017 int rpmioMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid)
3018 {
3019  char * d, * de;
3020  int created = 0;
3021  int rc;
3022 
3023  if (path == NULL || *path == '\0')
3024  return -1;
3025  d = (char *) alloca(strlen(path)+2);
3026  de = stpcpy(d, path);
3027  de[1] = '\0';
3028  for (de = d; *de != '\0'; de++) {
3029  struct stat st;
3030  char savec;
3031 
3032  while (*de && *de != '/') de++;
3033  savec = de[1];
3034  de[1] = '\0';
3035 
3036  rc = Stat(d, &st);
3037  if (rc) {
3038  switch(errno) {
3039  default:
3040  return errno;
3041  /*@notreached@*/ /*@switchbreak@*/ break;
3042  case ENOENT:
3043  /*@switchbreak@*/ break;
3044  }
3045  rc = Mkdir(d, mode);
3046  if (rc)
3047  return errno;
3048  created = 1;
3049  if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) {
3050  rc = Chown(d, uid, gid);
3051  if (rc)
3052  return errno;
3053  }
3054  } else if (!S_ISDIR(st.st_mode)) {
3055  return ENOTDIR;
3056  }
3057  de[1] = savec;
3058  }
3059  rc = 0;
3060  if (created)
3061  rpmlog(RPMLOG_DEBUG, D_("created directory(s) %s mode 0%o\n"),
3062  path, (unsigned)mode);
3063  return rc;
3064 }
3065 
3066 #define _PATH "/bin:/usr/bin:/sbin:/usr/sbin"
3067 /*@unchecked@*/ /*@observer@*/
3068 static const char *_path = _PATH;
3069 
3070 #define alloca_strdup(_s) strcpy((char *)alloca(strlen(_s)+1), (_s))
3071 
3072 int rpmioAccess(const char * FN, const char * path, int mode)
3073 {
3074  char fn[4096];
3075  char * bn;
3076  char * r, * re;
3077  char * t, * te;
3078  int negate = 0;
3079  int rc = 0;
3080 
3081  /* Empty paths are always accessible. */
3082  if (FN == NULL || *FN == '\0')
3083  return 0;
3084 
3085  if (mode == 0)
3086  mode = X_OK;
3087 
3088  /* Strip filename out of its name space wrapper. */
3089  bn = (char *) alloca_strdup(FN);
3090  for (t = bn; t && *t; t++) {
3091  if (*t != '(')
3092  continue;
3093  *t++ = '\0';
3094 
3095  /* Permit negation on name space tests. */
3096  if (*bn == '!') {
3097  negate = 1;
3098  bn++;
3099  }
3100 
3101  /* Set access flags from name space marker. */
3102  if (strlen(bn) == 3
3103  && strchr("Rr_", bn[0]) != NULL
3104  && strchr("Ww_", bn[1]) != NULL
3105  && strchr("Xx_", bn[2]) != NULL) {
3106  mode = 0;
3107  if (strchr("Rr", bn[0]) != NULL)
3108  mode |= R_OK;
3109  if (strchr("Ww", bn[1]) != NULL)
3110  mode |= W_OK;
3111  if (strchr("Xx", bn[2]) != NULL)
3112  mode |= X_OK;
3113  if (mode == 0)
3114  mode = F_OK;
3115  } else if (!strcmp(bn, "exists"))
3116  mode = F_OK;
3117  else if (!strcmp(bn, "executable"))
3118  mode = X_OK;
3119  else if (!strcmp(bn, "readable"))
3120  mode = R_OK;
3121  else if (!strcmp(bn, "writable"))
3122  mode = W_OK;
3123 
3124  bn = t;
3125  te = bn + strlen(t) - 1;
3126  if (*te != ')') /* XXX syntax error, never exists */
3127  return 1;
3128  *te = '\0';
3129  break;
3130  }
3131 
3132  /* Empty paths are always accessible. */
3133  if (*bn == '\0')
3134  goto exit;
3135 
3136  /* Check absolute path for access. */
3137  if (*bn == '/') {
3138  rc = (Access(bn, mode) != 0 ? 1 : 0);
3139 if (_rpmio_debug)
3140 fprintf(stderr, "*** rpmioAccess(\"%s\", 0x%x) rc %d\n", bn, mode, rc);
3141  goto exit;
3142  }
3143 
3144  /* Find path to search. */
3145  if (path == NULL)
3146  path = getenv("PATH");
3147  if (path == NULL)
3148  path = _path;
3149  if (path == NULL) {
3150  rc = 1;
3151  goto exit;
3152  }
3153 
3154  /* Look for relative basename on PATH. */
3155  for (r = alloca_strdup(path); r != NULL && *r != '\0'; r = re) {
3156 
3157  /* Find next element, terminate current element. */
3158  for (re = r; (re = strchr(re, ':')) != NULL; re++) {
3159  if (!(re[1] == '/' && re[2] == '/'))
3160  /*@innerbreak@*/ break;
3161  }
3162  if (re && *re == ':')
3163  *re++ = '\0';
3164  else
3165  re = r + strlen(r);
3166 
3167  /* Expand ~/ to $HOME/ */
3168  fn[0] = '\0';
3169  t = fn;
3170  *t = '\0'; /* XXX redundant. */
3171  if (r[0] == '~' && r[1] == '/') {
3172  const char * home = getenv("HOME");
3173  if (home == NULL) /* XXX No HOME? */
3174  continue;
3175  if (strlen(home) > (sizeof(fn) - strlen(r))) /* XXX too big */
3176  continue;
3177  t = stpcpy(t, home);
3178  r++; /* skip ~ */
3179  }
3180  t = stpcpy(t, r);
3181  if (t[-1] != '/' && *bn != '/')
3182  *t++ = '/';
3183  t = stpcpy(t, bn);
3184  t = rpmCleanPath(fn);
3185  if (t == NULL) /* XXX can't happen */
3186  continue;
3187 
3188  /* Check absolute path for access. */
3189  rc = (Access(t, mode) != 0 ? 1 : 0);
3190 if (_rpmio_debug)
3191 fprintf(stderr, "*** rpmioAccess(\"%s\", 0x%x) rc %d\n", t, mode, rc);
3192  if (rc == 0)
3193  goto exit;
3194  }
3195 
3196  rc = 1;
3197 
3198 exit:
3199  if (negate)
3200  rc ^= 1;
3201  return rc;
3202 }
3203 
3204 #if defined(WITH_NSS) && !defined(__LCLINT__) /* XXX TODO: add nssDestroy */
3205 #ifdef __cplusplus
3206 extern "C" {
3207 #endif
3208 /*@-exportheader@*/
3209 #ifdef HAVE_NSS_INITCONTEXT
3210 extern void NSS_ShutdownContext(void * _nss_context);
3211 #else
3212 extern void NSS_Shutdown(void);
3213 #endif
3214 extern void PL_ArenaFinish(void);
3215 extern void PR_Cleanup(void);
3216 /*@=exportheader@*/
3217 #ifdef __cplusplus
3218 }
3219 #endif
3220 
3221 /*@unchecked@*/
3222 int _rpmnss_init = 0;
3223 
3224 /*@unchecked@*/
3225 void * _rpmnss_context = NULL;
3226 #endif
3227 
3228 void rpmioClean(void)
3229 {
3230 /*@-nestedextern@*/
3231  extern rpmioPool _avxPool;
3232  extern rpmioPool _urlPool;
3233  extern rpmioPool _xarPool;
3234  extern rpmioPool _digPool;
3235  extern rpmioPool _rpmiobPool;
3236  extern rpmioPool _rpmvcPool;
3237  extern rpmioPool _rpmvtPool;
3238 /*@-shadow@*/
3239  extern rpmioPool _mirePool;
3240  extern rpmioPool _rpmbfPool;
3241  extern rpmioPool _rpmhkpPool;
3242  extern rpmioPool _htmlPool;
3243  extern rpmioPool _htPool;
3244  extern rpmioPool _cphPool;
3245  extern rpmioPool _ctxPool;
3246  extern rpmioPool _rpmsmPool;
3247  extern rpmioPool _rpmspPool;
3248  extern rpmioPool _rpmsxPool;
3249  extern rpmioPool _rpmsyckPool;
3250 /*@=shadow@*/
3251 
3252  extern rpmioPool _rpmasnPool;
3253  extern rpmioPool _rpmbagPool;
3254  extern rpmioPool _rpmcvsPool;
3255  extern rpmioPool _rpmgitPool;
3256  extern rpmioPool _rpmsetPool;
3257  extern rpmioPool _rpmsvnPool;
3258  extern rpmioPool _rpmtpmPool;
3259 
3260  extern rpmioPool _rpmaugPool;
3261  extern rpmioPool _rpmcudfPool;
3262  extern rpmioPool _rpmficlPool;
3263  extern rpmioPool _rpmjniPool;
3264  extern rpmioPool _rpmjsPool;
3265  extern rpmioPool _rpmluavPool;
3266  extern rpmioPool _rpmluaPool;
3267  extern rpmioPool _rpmmgPool;
3268  extern rpmioPool _rpmmgoPool;
3269  extern rpmioPool _rpmmrbPool;
3270 #ifdef NOTYET
3271  extern rpmioPool _rpmnixPool;
3272 #endif
3273  extern rpmioPool _odbcPool;
3274  extern rpmioPool _rpmperlPool;
3275  extern rpmioPool _rpmpythonPool;
3276  extern rpmioPool _rpmrubyPool;
3277  extern rpmioPool _rpmsqlPool;
3278  extern rpmioPool _rpmsquirrelPool;
3279  extern rpmioPool _rpmtclPool;
3280 /*@=nestedextern@*/
3281 
3282 #if defined(WITH_LUA)
3283  (void) rpmluaFree(NULL);
3284 #endif
3285 #if defined(WITH_NEON)
3286  davDestroy();
3287 #endif
3288 #if defined(WITH_NSS) && !defined(__LCLINT__)
3289  if (_rpmnss_init) {
3290 #ifdef HAVE_NSS_INITCONTEXT
3291  if (_rpmnss_context != NULL)
3292  (void) NSS_ShutdownContext(_rpmnss_context);
3293 #else
3294  (void) NSS_Shutdown();
3295 #endif
3296  PL_ArenaFinish();
3297  PR_Cleanup();
3298  _rpmnss_context = NULL;
3299  _rpmnss_init = 0;
3300  }
3301 #endif
3302  urlFreeCache();
3303 
3305  _rpmtclPool = rpmioFreePool(_rpmtclPool);
3307  _rpmsquirrelPool = rpmioFreePool(_rpmsquirrelPool);
3309  _rpmsqlPool = rpmioFreePool(_rpmsqlPool);
3311  _rpmrubyPool = rpmioFreePool(_rpmrubyPool);
3313  _rpmpythonPool = rpmioFreePool(_rpmpythonPool);
3315  _rpmperlPool = rpmioFreePool(_rpmperlPool);
3316  _rpmmrbI = rpmmrbFree(_rpmmrbI);
3317  _rpmmrbPool = rpmioFreePool(_rpmmrbPool);
3319  _rpmjsPool = rpmioFreePool(_rpmjsPool);
3320  _rpmjniI = rpmjniFree(_rpmjniI);
3321  _rpmjniPool = rpmioFreePool(_rpmjniPool);
3323  _rpmficlPool = rpmioFreePool(_rpmficlPool);
3324 
3326  _rpmgitPool = rpmioFreePool(_rpmgitPool);
3327 
3329  _rpmaugPool = rpmioFreePool(_rpmaugPool);
3331  _rpmmgoPool = rpmioFreePool(_rpmmgoPool);
3332 
3333  _rpmasnPool = rpmioFreePool(_rpmasnPool);
3334  _rpmbagPool = rpmioFreePool(_rpmbagPool);
3335  _rpmcvsPool = rpmioFreePool(_rpmcvsPool);
3336  _odbcPool = rpmioFreePool(_odbcPool);
3337  _rpmsetPool = rpmioFreePool(_rpmsetPool);
3338  _rpmsvnPool = rpmioFreePool(_rpmsvnPool);
3339  _rpmtpmPool = rpmioFreePool(_rpmtpmPool);
3340 
3341 #ifdef NOTYET /* XXX FIXME: dig out the recursion deadlock. */
3342  _rpmnixI = rpmnixFree(_rpmnixI);
3343  _rpmnixPool = rpmioFreePool(_rpmnixPool);
3344 #endif
3345 
3346  _rpmcudfPool = rpmioFreePool(_rpmcudfPool);
3347  _rpmluavPool = rpmioFreePool(_rpmluavPool);
3348  _rpmluaPool = rpmioFreePool(_rpmluaPool);
3349 
3351  _rpmhkpPool = rpmioFreePool(_rpmhkpPool);
3354 
3355  _rpmvcPool = rpmioFreePool(_rpmvcPool);
3356  _rpmvtPool = rpmioFreePool(_rpmvtPool);
3357 
3359  _rpmsmPool = rpmioFreePool(_rpmsmPool);
3360  _rpmspPool = rpmioFreePool(_rpmspPool);
3362  _rpmsxPool = rpmioFreePool(_rpmsxPool);
3363 
3364  _htmlPool = rpmioFreePool(_htmlPool);
3365  _mirePool = rpmioFreePool(_mirePool);
3366  _rpmmgPool = rpmioFreePool(_rpmmgPool);
3367  _rpmbfPool = rpmioFreePool(_rpmbfPool);
3368  _htPool = rpmioFreePool(_htPool);
3369  _cphPool = rpmioFreePool(_cphPool);
3370  _ctxPool = rpmioFreePool(_ctxPool);
3371  _rpmsyckPool = rpmioFreePool(_rpmsyckPool);
3372  _rpmiobPool = rpmioFreePool(_rpmiobPool);
3373  _digPool = rpmioFreePool(_digPool);
3374  _xarPool = rpmioFreePool(_xarPool);
3375  _avxPool = rpmioFreePool(_avxPool);
3376  _urlPool = rpmioFreePool(_urlPool);
3377  _fdPool = rpmioFreePool(_fdPool);
3378 
3379  rpmlogClose();
3380 }
3381 
3382 /*@-type@*/ /* LCL: function typedefs */
3383 static struct FDIO_s fpio_s = {
3384  ufdRead, ufdWrite, fdSeek, ufdClose, NULL, NULL, NULL,
3385 };
3386 /*@=type@*/
3387 
3388 FDIO_t fpio = /*@-compmempass@*/ &fpio_s /*@=compmempass@*/ ;
int davDisconnect(void *_u)
Close active neon transfer(s) (if any).
int _dav_debug
Definition: rpmio.c:195
FDSTAT_t stats
const char const double d
Definition: bson.h:800
FDIO_t fdio
Definition: rpmio.c:578
static int fdSeekNot(void *cookie, _libio_pos_t pos, int whence)
Definition: rpmio.c:285
int ufdCopy(FD_t sfd, FD_t tfd)
Definition: rpmio.c:1549
int ftpCmd(const char *cmd, const char *url, const char *arg2)
Definition: rpmio.c:1674
#define UFDONLY(fd)
Definition: rpmio.c:157
rpmsm rpmsmFree(rpmsm sm)
Destroy a semanage wrapper.
rpmioPool _rpmsvnPool
Definition: rpmsvn.c:54
rpmioPool _rpmsetPool
Definition: set.c:1309
static int mygethostbyname(const char *host, struct in_addr *address)
Definition: rpmio.c:833
#define fdOpen
Definition: rpmio.c:132
int fdWritable(FD_t fd, int secs)
Definition: rpmio.c:580
mongo_error_t const char * errstr
Definition: mongo.h:922
int _url_iobuf_size
Definition: url.c:66
const char * scheme
Definition: rpmurl.h:57
#define fdWrite
Definition: rpmio.c:136
int Fcntl(FD_t fd, int op, void *lip)
fcntl(2) clone.
Definition: rpmio.c:3009
static int ufdSeek(void *cookie, _libio_pos_t pos, int whence)
Definition: rpmio.c:2069
rpmioPool _rpmsqlPool
Definition: rpmsql.c:5362
rpmioPool _rpmpythonPool
Definition: rpmpython.c:38
void rpmioClean(void)
Free all memory allocated by rpmio usage.
Definition: rpmio.c:3228
pgpDig pgpDigFree(pgpDig dig)
Destroy a container for parsed OpenPGP packates.
rpmtcl _rpmtclI
Definition: rpmtcl.c:17
static void fdstat_enter(FD_t fd, int opx)
const char const char size_t len
Definition: bson.h:823
off_t _libio_off_t
Hide libio API lossage.
Definition: rpmio.h:31
static int fdGetFdno(FD_t fd)
FD_t data
Definition: rpmurl.h:80
char * getenv(const char *name)
rpmioPool _rpmvcPool
Definition: rpmsql.c:599
const char int port
Definition: mongo.h:251
static void * fdGetFp(FD_t fd)
const char * password
Definition: rpmurl.h:61
static void fdSetFdno(FD_t fd, int fdno)
const char * user
Definition: rpmurl.h:59
enum urltype_e urltype
Supported URL types.
static const char * _path
Definition: rpmio.c:3068
rpmioPool _rpmficlPool
Definition: rpmficl.c:49
rpmhkp _rpmhkpI
Definition: rpmhkp.c:22
rpmioPool _rpmcvsPool
Definition: rpmcvs.c:29
const char const char * cmd
Definition: mongo.h:777
ssize_t bytesRemain
static int ftpTimeoutSecs
Definition: rpmio.c:175
const char * fdbg(FD_t fd)
Definition: rpmio.c:199
rpmioPool _rpmspPool
Definition: rpmsp.c:58
struct urlinfo_s * urlinfo
Definition: rpmurl.h:37
rpmsquirrel rpmsquirrelFree(rpmsquirrel squirrel)
Destroy a squirrel interpreter.
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
fwrite(3) clone.
Definition: rpmio.c:2434
time_t lastModified
char * rpmCleanPath(char *path)
Canonicalize file path.
Definition: macro.c:3339
rpmruby _rpmrubyI
Current (global) interpreter instance.
Definition: rpmruby.c:32
rpmioPool _rpmsxPool
Definition: rpmsx.c:81
int Fsetpos(FD_t fd, fpos_t *pos)
Definition: rpmio.c:2520
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
URL control structure.
Definition: rpmurl.h:52
int magic
rpmjs rpmjsFree(rpmjs js)
Destroy a js interpreter.
rpmsx _rpmsxI
Definition: rpmsx.c:64
#define RPMURL_SERVER_HASRANGE
Definition: rpmurl.h:119
static int httpResp(urlinfo u, FD_t ctrl, char **str)
Definition: rpmio.c:1787
rpmioItem rpmioLinkPoolItem(rpmioItem item, const char *msg, const char *fn, unsigned ln)
Increment a pool item refcount.
Definition: rpmmalloc.c:165
int Access(const char *path, int amode)
access(2) clone.
Definition: rpmrpc.c:2196
rpmioPool _rpmjsPool
Definition: rpmjs.c:140
#define IAC
Definition: rpmio.c:1692
rpmsx rpmsxFree(rpmsx sx)
Destroy a SELinux wrapper.
int rpmioMkpath(const char *path, mode_t mode, uid_t uid, gid_t gid)
Insure that directories in path exist, creating as needed.
Definition: rpmio.c:3017
#define fdClose
Definition: rpmio.c:138
urltype urlIsURL(const char *url)
Return type of URL.
Definition: url.c:409
rpmioPool _rpmvtPool
Definition: rpmsql.c:90
rpmioPool _rpmaugPool
Definition: rpmaug.c:58
static int ftpFileDone(urlinfo u, FD_t data)
Definition: rpmio.c:1768
#define FDSANE(fd)
void rpmlogClose(void)
Close desriptor used to write to system logger.
Definition: rpmlog.c:69
rpmsquirrel _rpmsquirrelI
Definition: rpmsquirrel.c:27
#define VERSION
Definition: config.h:1306
int Fgetpos(FD_t fd, fpos_t *pos)
Definition: rpmio.c:2506
const char * urlStrerror(const char *url)
Definition: rpmio.c:808
#define R_OK
Definition: system.h:234
int Stat(const char *path, struct stat *st)
stat(2) clone.
Definition: rpmrpc.c:1361
const void * errcookie
pgpDig dig
FD_t fdLink(void *cookie, const char *msg)
static struct FDIO_s fpio_s
Definition: rpmio.c:3383
const char * contentType
ssize_t davRead(void *cookie, char *buf, size_t count)
#define __const
Definition: fnmatch.h:30
urltype urlType(void *_u)
Definition: url.c:424
int fdFgets(FD_t fd, char *buf, size_t len)
Definition: rpmio.c:687
static int ftpLogin(urlinfo u)
Definition: rpmio.c:1202
int Fflush(FD_t fd)
fflush(3) clone.
Definition: rpmio.c:2916
int errno
static void fdPush(FD_t fd, FDIO_t io, void *fp, int fdno)
ssize_t(* fdio_write_function_t)(void *cookie, const char *buf, size_t nbytes)
Definition: rpmio.h:68
int ufdClose(void *cookie)
Definition: rpmio.c:2093
#define fdRead
Definition: rpmio.c:134
rpmmgo rpmmgoFree(rpmmgo mgo)
Destroy a mongo wrapper.
rpmioPool _rpmasnPool
Definition: rpmasn.c:40
rpmioPool _rpmgitPool
Definition: rpmgit.c:2714
fdio_fdopen_function_t _fdopen
Definition: rpmio.h:115
FDIO_t xzdio
int rd_timeoutsecs
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
const char * ftpStrerror(int errorNumber)
Definition: rpmio.c:753
Definition: rpmio.h:107
FD_t fdDup(int fdno)
Definition: rpmio.c:266
int persist
off_t _libio_pos_t
Definition: rpmio.h:32
rpmgit _rpmgitI
Definition: rpmgit.c:2717
rpmhkp rpmhkpFree(rpmhkp hkp)
Destroy a hkp handle.
static FDIO_t fdGetIo(FD_t fd)
int Fseek(FD_t fd, _libio_off_t offset, int whence)
fseek(3) clone.
Definition: rpmio.c:2457
rpmpython _rpmpythonI
Definition: rpmpython.c:23
const char * host
Definition: rpmurl.h:63
int nfps
FD_t fdNew(const char *msg)
FD_t ftpOpen(const char *url, int flags, mode_t mode, urlinfo *uret)
Definition: rpmio.c:2212
DIGEST_CTX * digests
static void fdSetSyserrno(FD_t fd, int syserrno, const void *errcookie)
rpmioPool _rpmbagPool
Definition: rpmbag.c:39
void Rewind(FD_t fd)
Definition: rpmio.c:2497
FDIO_t ufdio
Definition: rpmio.c:2362
#define _fd(_a)
Definition: psm.h:32
static void fdUpdateDigests(FD_t fd, const unsigned char *buf, ssize_t buflen)
Update digest(s) attached to fd.
int flags
static int getHostAddress(const char *host, struct in_addr *address)
Definition: rpmio.c:851
struct _filter_s _rpmhkp_crl
Definition: rpmhkp.c:25
static FD_t ufdOpen(const char *url, int flags, mode_t mode)
Definition: rpmio.c:2256
rpmpython rpmpythonFree(rpmpython python)
Destroy a python interpreter.
rpmioPool _rpmtpmPool
Definition: rpmtpm.c:252
char * alloca()
rpmioPool _odbcPool
Definition: rpmodbc.c:1226
int openError
Definition: rpmurl.h:116
const char * str
Definition: bson.h:593
int Chown(const char *path, uid_t owner, gid_t group)
chown(2) clone.
Definition: rpmrpc.c:1674
rpmioPool _rpmsyckPool
Definition: rpmsyck.c:18
int port
Definition: rpmurl.h:75
static int ftpCommand(urlinfo u, char **str,...)
Definition: rpmio.c:1164
static int rpm_inet_aton(const char *cp, struct in_addr *inp)
Definition: rpmio.c:112
int(* fdio_close_function_t)(void *cookie)
Definition: rpmio.h:80
const char * url
Definition: rpmurl.h:55
#define fdGetFILE(_fd)
Definition: rpmio.c:159
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
const char * proxyu
Definition: rpmurl.h:71
fdio_close_function_t close
Definition: rpmio.h:111
rpmbf rpmbfFree(rpmbf bf)
Destroy a Bloom filter.
struct _FD_s * FD_t
Definition: rpmio.h:43
rpmgit rpmgitFree(rpmgit git)
Destroy a git wrapper.
const char * mode
Definition: mongo.h:440
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:220
#define HAVE_GETADDRINFO
Definition: config.h:217
void *(* rpmCallbackFunction)(const void *h, const rpmCallbackType what, const rpmuint64_t amount, const rpmuint64_t total, fnpyKey key, rpmCallbackData data)
Definition: rpmiotypes.h:528
rpmioPool _digPool
Definition: rpmpgp.c:1295
FD_t fdFree(FD_t fd, const char *msg)
rpmioPool _rpmperlPool
Definition: rpmperl.c:44
FDIO_t lzdio
const void * inp
Definition: bson.h:1157
int wr_chunked
FDIO_t gzdio
int Mkdir(const char *path, mode_t mode)
mkdir(2) clone.
Definition: rpmrpc.c:73
const char const bson * data
Definition: mongo.h:463
static void fdPop(FD_t fd)
#define X_OK
Definition: system.h:232
int fdReadable(FD_t fd, int secs)
Definition: rpmio.c:635
static ssize_t ufdWrite(void *cookie, const char *buf, size_t count)
Definition: rpmio.c:2004
static void fdSetOpen(FD_t fd, const char *path, int flags, mode_t mode)
int rpmioAccess(const char *FN, const char *path, int mode)
Check FN access, expanding relative paths and twiddles.
Definition: rpmio.c:3072
rpmioPool _rpmmgPool
Definition: rpmmg.c:41
rpmioPool _rpmrubyPool
The pool of Ruby interpreter instances.
Definition: rpmruby.c:54
Digest private data.
Definition: digest.c:130
static int tcpConnect(FD_t ctrl, const char *host, int port)
Definition: rpmio.c:880
rpmioPool _rpmtclPool
Definition: rpmtcl.c:34
The FD_t File Handle data structure.
fdio_flush_function_t _flush
Definition: rpmio.h:117
const char const char * user
Definition: mongo.h:828
ssize_t contentLength
rpmioPool _rpmhkpPool
Definition: rpmhkp.c:94
rpmioPool _rpmsmPool
Definition: rpmsm.c:327
int allow
Definition: rpmurl.h:118
int bufAlloced
Definition: rpmurl.h:113
static void fdFini(void *_fd)
Definition: rpmio.c:297
char * buf
Definition: rpmurl.h:115
rpmioPool _mirePool
Definition: mire.c:79
void * rpmluaFree(rpmlua lua)
FD_t ctrl
Definition: rpmurl.h:78
rpmficl _rpmficlI
Definition: rpmficl.c:17
static int urlConnect(const char *url, urlinfo *uret)
Definition: rpmio.c:1613
const char time_t secs
Definition: bson.h:1028
const char const bson const bson * op
Definition: mongo.h:505
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3238
int noLibio
Definition: rpmio.c:167
rpmperl _rpmperlI
Definition: rpmperl.c:22
rpmaug rpmaugFree(rpmaug aug)
Destroy a augeas wrapper.
int proxyp
Definition: rpmurl.h:74
rpmioPool _ctxPool
Definition: digest.c:174
Embedded Ruby interpreter.
void * ufdGetUrlinfo(FD_t fd)
Definition: rpmio.c:1930
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
struct _filter_s _rpmhkp_awol
Definition: rpmhkp.c:24
int _ftp_debug
Definition: rpmio.c:190
const char * proxyh
Definition: rpmurl.h:73
const char * host
Definition: mongo.h:251
rpmioPool _fdPool
Definition: rpmio.c:337
FDIO_t bzdio
rpmaug _rpmaugI
Definition: rpmaug.c:36
static int ftpAbort(urlinfo u, FD_t data)
Definition: rpmio.c:1704
rpmsql _rpmsqlI
Definition: rpmsql.c:52
static int fdFileno(void *cookie)
#define IP
Definition: rpmio.c:1695
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
#define IPPORT_FTP
Definition: rpmio.c:104
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
int syserrno
#define alloca_strdup(_s)
Definition: rpmio.c:3070
static const char * getFdErrstr(FD_t fd)
Definition: rpmio.c:2366
rpmioPool _rpmluaPool
Definition: rpmlua.c:61
void * u
FD_t XfdNew(const char *msg, const char *fn, unsigned ln)
Definition: rpmio.c:357
rpmxar xar
rpmruby rpmrubyFree(rpmruby ruby)
Destroys a Ruby interpreter instance.
static int ftpCheckResponse(urlinfo u, char **str)
Definition: rpmio.c:1138
ssize_t davWrite(void *cookie, const char *buf, size_t count)
struct @8 * FDSTAT_t
Cumulative statistics for a descriptor.
size_t ndigests
FD_t httpOpen(const char *url, int flags, mode_t mode, urlinfo *uret)
Definition: rpmdav.c:2222
static struct FDIO_s ufdio_s
Definition: rpmio.c:2357
static int httpReq(FD_t ctrl, const char *httpCmd, const char *httpArg)
Definition: rpmio.c:1816
int ufdGetFile(FD_t sfd, FD_t tfd)
Definition: rpmio.c:1661
rpmioPool _urlPool
Definition: url.c:158
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
static void fdSetIo(FD_t fd, FDIO_t io)
int urlSplit(const char *url, urlinfo *uret)
Parse URL string into a control structure.
Definition: url.c:476
rpmsql rpmsqlFree(rpmsql sql)
Destroy a sql interpreter.
unsigned long long fd_cpioPos
int davClose(void *cookie)
static ssize_t ufdRead(void *cookie, char *buf, size_t count)
Definition: rpmio.c:1941
const char const int i
Definition: bson.h:778
static int xisdigit(int c)
Definition: rpmiotypes.h:546
rpmioPool _rpmsquirrelPool
Definition: rpmsquirrel.c:44
rpmmgo _rpmmgoI
Definition: mongo.c:45
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
int _av_debug
Definition: rpmio.c:185
#define inet_aton(cp, inp)
Definition: rpmio.c:111
int httpVersion
Definition: rpmurl.h:117
void davDestroy(void)
Free global neon+openSSL state memory.
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:109
char * stpcpy(char *dest, const char *src)
static int fdSeek(void *cookie, _libio_pos_t pos, int whence)
Definition: rpmio.c:479
const char const char size_t size
Definition: bson.h:895
rpmioPool _rpmbfPool
Definition: rpmbf.c:36
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
static struct FDIO_s fdio_s
Definition: rpmio.c:573
#define SHUT_RDWR
Definition: rpmio.c:1701
FD_t Fdopen(FD_t ofd, const char *fmode)
Definition: rpmio.c:2718
const char * contentDisposition
static int checkResponse(void *_u, FD_t ctrl, int *ecp, char **str)
Definition: rpmio.c:975
#define DBGIO(_f, _x)
#define F_OK
Definition: system.h:231
void urlFreeCache(void)
Free cached URL control structures.
Definition: url.c:202
#define URLSANE(u)
Definition: rpmurl.h:33
FD_t davOpen(const char *url, int flags, mode_t mode, urlinfo *uret)
Open a URL.
int davReq(FD_t ctrl, const char *httpCmd, const char *httpArg)
Send a http request.
rpmioPool _htPool
Definition: rpmhash.c:261
const char * opath
rpmtcl rpmtclFree(rpmtcl tcl)
Destroy a tcl interpreter.
rpmioPool _rpmluavPool
Definition: rpmlua.c:64
fdio_write_function_t write
Definition: rpmio.h:109
rpmioPool _htmlPool
Definition: rpmdav.c:1120
int Fileno(FD_t fd)
fileno(3) clone.
Definition: rpmio.c:2991
static FD_t c2f(void *cookie)
int rpmDigestFinal(DIGEST_CTX ctx, void *datap, size_t *lenp, int asAscii)
Return digest and destroy context.
Definition: digest.c:1000
#define TIMEOUT_SECS
Definition: rpmio.c:170
rpmxar rpmxarFree(rpmxar xar, const char *msg)
Destroy a xar archive instance.
void * req
#define FDMAGIC
ssize_t(* fdio_read_function_t)(void *cookie, char *buf, size_t nbytes)
Definition: rpmio.h:60
int _rpmio_debug
Definition: rpmio.c:180
int oflags
fdio_read_function_t read
Definition: rpmio.h:108
#define _(Text)
Definition: system.h:29
rpmficl rpmficlFree(rpmficl ficl)
Destroy a ficl interpreter.
rpmioPool _xarPool
Definition: rpmxar.c:73
FDSTACK_t fps[8]
#define D_(Text)
Definition: system.h:526
struct rpmioItem_s _item
int ftpFileDoneNeeded
static void fdSetFp(FD_t fd, void *fp)
int(* fdio_seek_function_t)(void *cookie, _libio_pos_t pos, int whence)
Definition: rpmio.h:74
rpmjs _rpmjsI
Definition: rpmjs.c:80
rpmsm _rpmsmI
Definition: rpmsm.c:24
rpmperl rpmperlFree(rpmperl perl)
Destroy a perl interpreter.
static FD_t fdGetPool(rpmioPool pool)
Definition: rpmio.c:339
ssize_t xarRead(void *cookie, char *buf, size_t count)
Definition: rpmxar.c:229
long Ftell(FD_t fd)
Definition: rpmio.c:2483
#define DM
Definition: rpmio.c:1698
fdio_seek_function_t seek
Definition: rpmio.h:110
int ftpReq(FD_t data, const char *ftpCmd, const char *ftpArg)
Definition: rpmio.c:1277
rpmioPool _rpmiobPool
Definition: rpmiob.c:28
urlinfo urlFree(urlinfo u, const char *msg)
Dereference a URL control structure instance.
static void fdstat_exit(FD_t fd, int opx, ssize_t rc)
rpmioPool _rpmcudfPool
Definition: rpmcudf.c:458
#define FDIOVEC(_fd, _vec)
Definition: rpmio.c:2409
#define NI_MAXHOST
Definition: rpmio.c:17
rpmioPool rpmioFreePool(rpmioPool pool)
Reclaim memory pool items.
Definition: rpmmalloc.c:72
static void cvtfmode(const char *m, char *stdio, size_t nstdio, char *other, size_t nother, const char **end, int *f)
Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
Definition: rpmio.c:2642
#define _PATH
Definition: rpmio.c:3066
mode_t omode
rpmioPool _avxPool
Definition: rpmdir.c:46
#define W_OK
Definition: system.h:233
#define NI_MAXSERV
Definition: mongo.c:1588
int j
Definition: mongo.h:438
FDIO_t fpio
Definition: rpmio.c:3388
rpmioPool _rpmmgoPool
Definition: mongo.c:3558
urlinfo urlLink(urlinfo u, const char *msg)
Reference a URL control structure instance.