~ubuntu-branches/ubuntu/precise/wget/precise-proposed

« back to all changes in this revision

Viewing changes to lib/fcntl.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-10-19 00:00:09 UTC
  • mfrom: (2.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20111019000009-8p33w3wz4b1rdri0
Tags: 1.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
  - Depend on libssl-dev 0.9.8k-7ubuntu4 (LP: #503339)
* Dropped changes, superseded in Debian:
  - Keep build dependencies in main:
    + debian/control: remove info2man build-dep
    + debian/patches/series: disable wget-infopod_generated_manpage
  - Mark wget Multi-Arch: foreign, so packages that aren't of the same arch
    can depend on it.
* Pass --with-ssl=openssl; we don't want to use gnutls, there's no udeb for
  it.
* Add a second build pass for the udeb, so we can build without libidn.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Provide file descriptor control.
 
2
 
 
3
   Copyright (C) 2009-2011 Free Software Foundation, Inc.
 
4
 
 
5
   This program is free software: you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation; either version 3 of the License, or
 
8
   (at your option) any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
/* Written by Eric Blake <ebb9@byu.net>.  */
 
19
 
 
20
#include <config.h>
 
21
 
 
22
/* Specification.  */
 
23
#include <fcntl.h>
 
24
 
 
25
#include <errno.h>
 
26
#include <limits.h>
 
27
#include <stdarg.h>
 
28
#include <unistd.h>
 
29
 
 
30
#if !HAVE_FCNTL
 
31
# define rpl_fcntl fcntl
 
32
#endif
 
33
#undef fcntl
 
34
 
 
35
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
36
/* Get declarations of the Win32 API functions.  */
 
37
# define WIN32_LEAN_AND_MEAN
 
38
# include <windows.h>
 
39
 
 
40
/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
 
41
# define OPEN_MAX_MAX 0x10000
 
42
 
 
43
/* Duplicate OLDFD into the first available slot of at least NEWFD,
 
44
   which must be positive, with FLAGS determining whether the duplicate
 
45
   will be inheritable.  */
 
46
static int
 
47
dupfd (int oldfd, int newfd, int flags)
 
48
{
 
49
  /* Mingw has no way to create an arbitrary fd.  Iterate until all
 
50
     file descriptors less than newfd are filled up.  */
 
51
  HANDLE curr_process = GetCurrentProcess ();
 
52
  HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
 
53
  unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
 
54
  unsigned int fds_to_close_bound = 0;
 
55
  int result;
 
56
  BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
 
57
  int mode;
 
58
 
 
59
  if (newfd < 0 || getdtablesize () <= newfd)
 
60
    {
 
61
      errno = EINVAL;
 
62
      return -1;
 
63
    }
 
64
  if (old_handle == INVALID_HANDLE_VALUE
 
65
      || (mode = setmode (oldfd, O_BINARY)) == -1)
 
66
    {
 
67
      /* oldfd is not open, or is an unassigned standard file
 
68
         descriptor.  */
 
69
      errno = EBADF;
 
70
      return -1;
 
71
    }
 
72
  setmode (oldfd, mode);
 
73
  flags |= mode;
 
74
 
 
75
  for (;;)
 
76
    {
 
77
      HANDLE new_handle;
 
78
      int duplicated_fd;
 
79
      unsigned int index;
 
80
 
 
81
      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
 
82
                            old_handle,             /* SourceHandle */
 
83
                            curr_process,           /* TargetProcessHandle */
 
84
                            (PHANDLE) &new_handle,  /* TargetHandle */
 
85
                            (DWORD) 0,              /* DesiredAccess */
 
86
                            inherit,                /* InheritHandle */
 
87
                            DUPLICATE_SAME_ACCESS)) /* Options */
 
88
        {
 
89
          /* TODO: Translate GetLastError () into errno.  */
 
90
          errno = EMFILE;
 
91
          result = -1;
 
92
          break;
 
93
        }
 
94
      duplicated_fd = _open_osfhandle ((long) new_handle, flags);
 
95
      if (duplicated_fd < 0)
 
96
        {
 
97
          CloseHandle (new_handle);
 
98
          errno = EMFILE;
 
99
          result = -1;
 
100
          break;
 
101
        }
 
102
      if (newfd <= duplicated_fd)
 
103
        {
 
104
          result = duplicated_fd;
 
105
          break;
 
106
        }
 
107
 
 
108
      /* Set the bit duplicated_fd in fds_to_close[].  */
 
109
      index = (unsigned int) duplicated_fd / CHAR_BIT;
 
110
      if (fds_to_close_bound <= index)
 
111
        {
 
112
          if (sizeof fds_to_close <= index)
 
113
            /* Need to increase OPEN_MAX_MAX.  */
 
114
            abort ();
 
115
          memset (fds_to_close + fds_to_close_bound, '\0',
 
116
                  index + 1 - fds_to_close_bound);
 
117
          fds_to_close_bound = index + 1;
 
118
        }
 
119
      fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
 
120
    }
 
121
 
 
122
  /* Close the previous fds that turned out to be too small.  */
 
123
  {
 
124
    int saved_errno = errno;
 
125
    unsigned int duplicated_fd;
 
126
 
 
127
    for (duplicated_fd = 0;
 
128
         duplicated_fd < fds_to_close_bound * CHAR_BIT;
 
129
         duplicated_fd++)
 
130
      if ((fds_to_close[duplicated_fd / CHAR_BIT]
 
131
           >> (duplicated_fd % CHAR_BIT))
 
132
          & 1)
 
133
        close (duplicated_fd);
 
134
 
 
135
    errno = saved_errno;
 
136
  }
 
137
 
 
138
# if REPLACE_FCHDIR
 
139
  if (0 <= result)
 
140
    result = _gl_register_dup (oldfd, result);
 
141
# endif
 
142
  return result;
 
143
}
 
144
#endif /* W32 */
 
145
 
 
146
/* Perform the specified ACTION on the file descriptor FD, possibly
 
147
   using the argument ARG further described below.  This replacement
 
148
   handles the following actions, and forwards all others on to the
 
149
   native fcntl.  An unrecognized ACTION returns -1 with errno set to
 
150
   EINVAL.
 
151
 
 
152
   F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
 
153
   If successful, return the duplicate, which will be inheritable;
 
154
   otherwise return -1 and set errno.
 
155
 
 
156
   F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
 
157
   target fd.  If successful, return the duplicate, which will not be
 
158
   inheritable; otherwise return -1 and set errno.
 
159
 
 
160
   F_GETFD - ARG need not be present.  If successful, return a
 
161
   non-negative value containing the descriptor flags of FD (only
 
162
   FD_CLOEXEC is portable, but other flags may be present); otherwise
 
163
   return -1 and set errno.  */
 
164
 
 
165
int
 
166
rpl_fcntl (int fd, int action, /* arg */...)
 
167
{
 
168
  va_list arg;
 
169
  int result = -1;
 
170
  va_start (arg, action);
 
171
  switch (action)
 
172
    {
 
173
 
 
174
#if !HAVE_FCNTL
 
175
    case F_DUPFD:
 
176
      {
 
177
        int target = va_arg (arg, int);
 
178
        result = dupfd (fd, target, 0);
 
179
        break;
 
180
      }
 
181
#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
 
182
    case F_DUPFD:
 
183
      {
 
184
        int target = va_arg (arg, int);
 
185
        /* Detect invalid target; needed for cygwin 1.5.x.  */
 
186
        if (target < 0 || getdtablesize () <= target)
 
187
          errno = EINVAL;
 
188
        else
 
189
          {
 
190
            /* Haiku alpha 2 loses fd flags on original.  */
 
191
            int flags = fcntl (fd, F_GETFD);
 
192
            if (flags < 0)
 
193
              {
 
194
                result = -1;
 
195
                break;
 
196
              }
 
197
            result = fcntl (fd, action, target);
 
198
            if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
 
199
              {
 
200
                int saved_errno = errno;
 
201
                close (result);
 
202
                result = -1;
 
203
                errno = saved_errno;
 
204
              }
 
205
# if REPLACE_FCHDIR
 
206
            if (0 <= result)
 
207
              result = _gl_register_dup (fd, result);
 
208
# endif
 
209
          }
 
210
        break;
 
211
      } /* F_DUPFD */
 
212
#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
 
213
 
 
214
    case F_DUPFD_CLOEXEC:
 
215
      {
 
216
        int target = va_arg (arg, int);
 
217
 
 
218
#if !HAVE_FCNTL
 
219
        result = dupfd (fd, target, O_CLOEXEC);
 
220
        break;
 
221
#else /* HAVE_FCNTL */
 
222
        /* Try the system call first, if the headers claim it exists
 
223
           (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
 
224
           may be running with a glibc that has the macro but with an
 
225
           older kernel that does not support it.  Cache the
 
226
           information on whether the system call really works, but
 
227
           avoid caching failure if the corresponding F_DUPFD fails
 
228
           for any reason.  0 = unknown, 1 = yes, -1 = no.  */
 
229
        static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
 
230
        if (0 <= have_dupfd_cloexec)
 
231
          {
 
232
            result = fcntl (fd, action, target);
 
233
            if (0 <= result || errno != EINVAL)
 
234
              {
 
235
                have_dupfd_cloexec = 1;
 
236
# if REPLACE_FCHDIR
 
237
                if (0 <= result)
 
238
                  result = _gl_register_dup (fd, result);
 
239
# endif
 
240
              }
 
241
            else
 
242
              {
 
243
                result = rpl_fcntl (fd, F_DUPFD, target);
 
244
                if (result < 0)
 
245
                  break;
 
246
                have_dupfd_cloexec = -1;
 
247
              }
 
248
          }
 
249
        else
 
250
          result = rpl_fcntl (fd, F_DUPFD, target);
 
251
        if (0 <= result && have_dupfd_cloexec == -1)
 
252
          {
 
253
            int flags = fcntl (result, F_GETFD);
 
254
            if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
 
255
              {
 
256
                int saved_errno = errno;
 
257
                close (result);
 
258
                errno = saved_errno;
 
259
                result = -1;
 
260
              }
 
261
          }
 
262
        break;
 
263
#endif /* HAVE_FCNTL */
 
264
      } /* F_DUPFD_CLOEXEC */
 
265
 
 
266
#if !HAVE_FCNTL
 
267
    case F_GETFD:
 
268
      {
 
269
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
270
        HANDLE handle = (HANDLE) _get_osfhandle (fd);
 
271
        DWORD flags;
 
272
        if (handle == INVALID_HANDLE_VALUE
 
273
            || GetHandleInformation (handle, &flags) == 0)
 
274
          errno = EBADF;
 
275
        else
 
276
          result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
 
277
# else /* !W32 */
 
278
        /* Use dup2 to reject invalid file descriptors.  No way to
 
279
           access this information, so punt.  */
 
280
        if (0 <= dup2 (fd, fd))
 
281
          result = 0;
 
282
# endif /* !W32 */
 
283
        break;
 
284
      } /* F_GETFD */
 
285
#endif /* !HAVE_FCNTL */
 
286
 
 
287
      /* Implementing F_SETFD on mingw is not trivial - there is no
 
288
         API for changing the O_NOINHERIT bit on an fd, and merely
 
289
         changing the HANDLE_FLAG_INHERIT bit on the underlying handle
 
290
         can lead to odd state.  It may be possible by duplicating the
 
291
         handle, using _open_osfhandle with the right flags, then
 
292
         using dup2 to move the duplicate onto the original, but that
 
293
         is not supported for now.  */
 
294
 
 
295
    default:
 
296
      {
 
297
#if HAVE_FCNTL
 
298
        void *p = va_arg (arg, void *);
 
299
        result = fcntl (fd, action, p);
 
300
#else
 
301
        errno = EINVAL;
 
302
#endif
 
303
        break;
 
304
      }
 
305
    }
 
306
  va_end (arg);
 
307
  return result;
 
308
}