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