~straemer/ubuntu/quantal/update-manager/fix-for-1058070

« back to all changes in this revision

Viewing changes to UpdateManager/fdsend/fdsend.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson, Colin Watson, Adam Conrad, Barry Warsaw, Michael Vogt, Stéphane Graber, Steve Langasek
  • Date: 2012-06-14 00:57:42 UTC
  • Revision ID: package-import@ubuntu.com-20120614005742-2tnicupbt5io911y
Tags: 1:0.163
[ Colin Watson ]
* Isolate tests from local configuration in
  /etc/update-manager/release-upgrades.d/.
* Use Python attributes rather than GObject.get_data and GObject.set_data,
  which have been removed upstream (LP: #1009859).
* Switch default view class to Gtk3 and replace python-gobject dependency
  with python-gi.
* Port away from old-style apt.Package candidateFoo and installedFoo
  properties, preferring candidate.foo and installed.foo.  In a number of
  cases we have to check whether candidate/installed is non-None first.
* Use apt_pkg.version_compare rather than apt_pkg.VersionCompare.
* Use apt_pkg.uri_to_filename rather than apt_pkg.URItoFileName.
* Use apt_pkg.TagFile (and related new-style API) rather than
  apt_pkg.ParseTagFile.
* Use apt_pkg.PackageManager rather than apt_pkg.GetPackageManager.
* Use apt_pkg.Acquire rather than apt_pkg.GetAcquire.
* Use mark_foo/marked_foo rather than markFoo/markedFoo.
* Use apt_pkg.ActionGroup rather than apt_pkg.GetPkgActionGroup.
* Use apt_pkg.ProblemResolver rather than apt_pkg.GetPkgProblemResolver.
* Use apt_pkg.read_config_file rather than apt_pkg.ReadConfigFile.
* Use new spelling of apt_pkg.DepCache methods.
* Rename several local cache methods to PEP-8 style to avoid showing up in
  the output of /usr/share/python-apt/migrate-0.8.py.
* Use apt_pkg.size_to_str rather than apt_pkg.SizeToStr.
* Use apt_pkg.PackageManager.get_archives rather than
  apt_pkg.PackageManager.GetArchives.
* Use apt_pkg.Acquire.fetch_needed rather than
  apt_pkg.Acquire.FetchNeeded.
* Use new spelling of apt_pkg.Package/Version/Dependency methods.
* Use apt_pkg.pkgsystem_lock rather than apt_pkg.PkgSystemLock.
* Use new spelling of apt_pkg dependency parsing methods.
* Use new spelling of apt_pkg.SourceList methods.
* Bump python-apt (build-)dependency to >= 0.8.0.
* Add a scheme for excluding false positives from the pyflakes test, and
  enable it by default.
* Rearrange the OptionParser workaround from 1:0.154.5 to work with Python
  3, using gettext or ugettext as appropriate.
* Always pass bytes to hashlib.md5.update.
* Fix DistUpgradeAptCdrom to account for gzip files being opened in binary
  mode.
* Convert the last use of os.popen to subprocess.check_output, which makes
  it easier to read str rather than bytes.  (This requires Python 2.7.)
* Decode bytes read from urlopened file objects.
* UpdateManager/backend/InstallBackendSynaptic.py
  - Keep a reference to the data tuple passed to GObject.child_watch_add
    to avoid attempts to destroy it without a thread context
    (LP: #724687).
  - Open temporary synaptic selections file in text mode.
* Define __bool__ rather than __nonzero__ method in Python 3.
* sort(cmp=) and sorted(cmp=) no longer work in Python 3.  Use appropriate
  key= arguments instead.
* Fix ResourceWarning while reading /proc/mounts.
* Make update-manager-kde depend on psmisc, for killall.
* DistUpgrade/DistUpgradeView.py:
  - Use floor division in FuzzyTimeToStr.
* DistUpgrade/DistUpgradeViewText.py:
  - Flush stdout after printing confirmation message, since it doesn't
    have a trailing newline.
* Use the appropriate Unicode gettext methods in both Python 2 and 3, and
  drop lots of Python-3-unfriendly Unicode mangling as a result.
* DistUpgrade/DistUpgradeViewKDE.py:
  - Open the terminal log in binary mode.
* data/do-release-upgrade.8:
  - Provide a more useful NAME section.
* DistUpgrade/DistUpgradeCache.py:
  - Tolerate SyntaxError from attempting to import NvidiaDetector, until
    such time as a complete ubuntu-drivers-common Python 3 port is in the
    archive.
* Switch #! lines over to python3, apart from dist-upgrader which needs to
  stay as Python 2 for a while longer (and have some special arrangement
  for running with Python 3 for upgrades from >= quantal).
* Run tests under both Python 2 and 3.

[ Adam Conrad ]
* Merge branch from Michael Terry to drop auto-upgrade-tester
  from update-manager and move it into its own source package

[ Barry Warsaw ]
* Begin refactoring of Computer Janitor code by renaming and
  re-situating all of it to janitor/plugincore.  This will eventually be
  removed from here into its own separate branch.
* Merge the temporary Python 3 sprint branch back into trunk, and close
  the py3 sprint branch.
* Moved UpdateManager/backend and UpdateManager/UnitySupport.py to the
  python*-update-manager packages for apturl.

[ Michael Vogt ]
* UpdateManager/GtkProgress.py:
  - fix python-apt 0.8 API crash

[ Stéphane Graber ]
* Drop fdsend as it's not used and doesn't build with python3.
* Make update-manager-core a binary all packages (everything is python).
* Split update-manager-core into python-update-manager,
  python3-update-manager and update-manager-core.
* Build-depend and depend on python-apt >= 0.8.5~ as we need proper
  python3 support.

[ Steve Langasek ]
* tests/test_country_mirror.py: the test suite shouldn't fail if $LANG
  isn't set in the environment.
* update-manager is now using python3 as an interpreter, so fix these up
  to actually be python3 packages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* fdsend - SCM_RIGHTS file descriptor passing for Python.
2
 
 *
3
 
 * $Id: fdsend.c,v 1.1.1.1 2004/11/04 06:15:03 mjp Exp $
4
 
 *
5
 
 * Copyright (C) 2004 Michael J. Pomraning <mjp{AT}pilcrow.madison.wi.us>
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or modify
8
 
 * it under the terms of the GNU General Public License as published by
9
 
 * the Free Software Foundation; either version 2 of the License, or
10
 
 * (at your option) any later version.
11
 
 * 
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 
 * 
21
 
 * Portions of this file -- preliminary defines and socketpair() routine --
22
 
 * are derived from scgi version 1.2, which is is Copyright (c) 2004
23
 
 * Corporation for National Research Initiatives; All Rights Reserved.
24
 
 */
25
 
 
26
 
#include "Python.h"
27
 
 
28
 
#ifndef __OpenBSD__
29
 
#ifndef _XOPEN_SOURCE
30
 
#define _XOPEN_SOURCE 500
31
 
#endif
32
 
#ifndef _XOPEN_SOURCE_EXTENDED
33
 
#define _XOPEN_SOURCE_EXTENDED 1 /* Solaris <= 2.7 needs this too */
34
 
#endif
35
 
#endif /* __OpenBSD__ */
36
 
 
37
 
#include <sys/types.h>
38
 
#include <sys/socket.h>
39
 
#include <sys/uio.h>
40
 
#include <stddef.h>
41
 
 
42
 
static PyObject *socketmodule_error = NULL;
43
 
 
44
 
/* obj2fd
45
 
 *
46
 
 * A PyArg_Parse... format converter.
47
 
 */
48
 
static int
49
 
obj2fd(PyObject *o, void *p) {
50
 
        int fd = -1;
51
 
 
52
 
        if (o == Py_None)
53
 
                goto okay;
54
 
 
55
 
        if ((fd = PyObject_AsFileDescriptor(o)) == -1)
56
 
                return 0;
57
 
okay:
58
 
        *(int *)p = fd;
59
 
 
60
 
        return 1;
61
 
}
62
 
 
63
 
/* pack_control
64
 
 *
65
 
 * Cram a sequence of open files (or file descriptors) into the ancillary
66
 
 * data of a msghdr.  Note that the msg_control member is dynamically
67
 
 * allocated by this function, and may be freed by a call to
68
 
 * free_packed_control().
69
 
 */
70
 
static int
71
 
pack_control(PyObject *seq, struct msghdr *msg) {
72
 
        PyObject *fast_seq = NULL;
73
 
        int i, sz;
74
 
        int *fd_ptr = NULL;
75
 
        struct cmsghdr *cmsg;
76
 
        int ok = 0;
77
 
 
78
 
        fast_seq = PySequence_Fast(seq, "files argument must be a sequence");
79
 
        if (NULL == fast_seq) return 0;
80
 
 
81
 
        sz = PySequence_Fast_GET_SIZE(fast_seq);
82
 
        if (0 == sz) {
83
 
                msg->msg_controllen = 0;
84
 
                msg->msg_control = NULL;
85
 
                return 1;
86
 
        }
87
 
        msg->msg_controllen = CMSG_SPACE(sizeof(int) * sz);
88
 
        msg->msg_control = PyMem_Malloc(msg->msg_controllen);
89
 
        if (NULL == msg->msg_control) return 0;
90
 
 
91
 
        cmsg = CMSG_FIRSTHDR(msg);
92
 
        cmsg->cmsg_len = CMSG_LEN(sizeof(int) * sz);
93
 
        cmsg->cmsg_level = SOL_SOCKET;
94
 
        cmsg->cmsg_type = SCM_RIGHTS;
95
 
        fd_ptr = (int *)CMSG_DATA(cmsg);
96
 
        for (i = 0; i < sz; i++) {
97
 
                PyObject *f;
98
 
                int fd;
99
 
 
100
 
                f = PySequence_Fast_GET_ITEM(fast_seq, i);
101
 
                if (f == NULL) goto error;
102
 
                if ((fd = PyObject_AsFileDescriptor(f)) == -1) goto error;
103
 
                *fd_ptr = fd;
104
 
                fd_ptr++;
105
 
        }
106
 
        ok = 1;
107
 
 
108
 
out:
109
 
        Py_DECREF(fast_seq);
110
 
        return ok;
111
 
 
112
 
error:
113
 
        ok = 0;
114
 
        if (msg->msg_control) PyMem_Free(msg->msg_control);
115
 
        goto out;
116
 
}
117
 
 
118
 
static void
119
 
free_packed_control(struct msghdr *msg)
120
 
{
121
 
        if (NULL == msg) return;
122
 
        if (msg->msg_control) PyMem_Free(msg->msg_control);
123
 
        return;
124
 
}
125
 
 
126
 
/* unpack_control
127
 
 *
128
 
 * Unpack the ancillary data, assuming SCM_RIGHTS (file descriptor passing).
129
 
 *
130
 
 * Be prepared for:
131
 
 *   - more than one cmsghdr
132
 
 *   - more than one fd per cmsghdr
133
 
 */
134
 
static PyObject *
135
 
unpack_control(struct msghdr *msg) {
136
 
        struct cmsghdr *cmsg;
137
 
        int i = 0;
138
 
        PyObject *tup = NULL;
139
 
 
140
 
        for (cmsg = CMSG_FIRSTHDR(msg);
141
 
             cmsg != NULL;
142
 
             cmsg = CMSG_NXTHDR(msg,cmsg)) {
143
 
                if (cmsg->cmsg_level != SOL_SOCKET
144
 
                    || cmsg->cmsg_type != SCM_RIGHTS) {
145
 
                        PyErr_SetString(PyExc_RuntimeError,
146
 
                                        "Unexpected cmsg level or type found");
147
 
                        goto error;
148
 
                }
149
 
                i += (cmsg->cmsg_len - sizeof(struct cmsghdr))/sizeof(int);
150
 
        }
151
 
 
152
 
        tup = PyTuple_New(i);
153
 
        if (NULL == tup) goto error;
154
 
 
155
 
        i = 0;
156
 
        for (cmsg = CMSG_FIRSTHDR(msg);
157
 
             cmsg != NULL; 
158
 
             cmsg = CMSG_NXTHDR(msg,cmsg)) {
159
 
                int j;
160
 
                int *pfd = (int *)CMSG_DATA(cmsg);
161
 
                int upper_bound;
162
 
                upper_bound = cmsg->cmsg_len
163
 
                              - sizeof(struct cmsghdr) 
164
 
                              - sizeof(int);
165
 
                for (j = 0; j <= upper_bound; j += sizeof(int)) {
166
 
                        PyTuple_SET_ITEM(tup, i, PyLong_FromLong((long)pfd[i]));
167
 
                        i++;
168
 
                }
169
 
        }
170
 
        return tup;
171
 
error:
172
 
        if (tup) { Py_DECREF(tup); }
173
 
 
174
 
        return NULL;
175
 
}
176
 
 
177
 
static PyObject *
178
 
fdsend_sendfds(PyObject *dummy, PyObject *args, PyObject *kw)
179
 
{
180
 
        struct msghdr mh;
181
 
        struct iovec iov;
182
 
        int fd, r, flags = 0;
183
 
        PyObject *fds = Py_None;
184
 
 
185
 
        static char *keywords[] = {"fd", "msg", "flags", "fds", 0};
186
 
        if (!PyArg_ParseTupleAndKeywords(args, kw, "O&s#|iO:sendfds",
187
 
                                         keywords,
188
 
                                         obj2fd, &fd,
189
 
                                         &iov.iov_base, &iov.iov_len,
190
 
                                         &flags, &fds))
191
 
                return NULL;
192
 
 
193
 
        memset(&mh, '\0', sizeof(mh));
194
 
        mh.msg_iov = &iov;
195
 
        mh.msg_iovlen = 1;
196
 
 
197
 
        if (fds != Py_None) {
198
 
                if (! pack_control(fds, &mh)) return NULL;
199
 
        }
200
 
        Py_BEGIN_ALLOW_THREADS
201
 
        r = sendmsg(fd, &mh, flags);
202
 
        Py_END_ALLOW_THREADS
203
 
        free_packed_control(&mh);
204
 
 
205
 
        if (r < 0)
206
 
                return PyErr_SetFromErrno(socketmodule_error);
207
 
 
208
 
        return PyInt_FromLong((long) r);
209
 
}
210
 
 
211
 
static PyObject *
212
 
fdsend_recvfds(PyObject *dummy, PyObject *args, PyObject *kw)
213
 
{
214
 
        struct msghdr mh;
215
 
        struct iovec iov;
216
 
        struct cmsghdr *cmsg;
217
 
        PyObject *buf;
218
 
        int numfds = 32;
219
 
        int fd, r, flags = 0;
220
 
        PyObject *ret = NULL;
221
 
 
222
 
        static char *keywords[] = {"fd", "len", "flags", "numfds", 0};
223
 
        if (!PyArg_ParseTupleAndKeywords(args, kw, "O&i|ii:recvfds", keywords,
224
 
                                        obj2fd, &fd, &iov.iov_len, &flags,
225
 
                                        &numfds))
226
 
                return NULL;
227
 
 
228
 
        memset(&mh, '\0', sizeof(mh));
229
 
        
230
 
        if (numfds > 0) {
231
 
                mh.msg_controllen = CMSG_SPACE(sizeof(int) * numfds);
232
 
                mh.msg_control = PyMem_Malloc(mh.msg_controllen);
233
 
                if (NULL == mh.msg_control) return NULL;
234
 
        }
235
 
 
236
 
        buf = PyString_FromStringAndSize((char *) 0, iov.iov_len);
237
 
        if (NULL == buf) goto error;
238
 
        iov.iov_base = (void *)PyString_AS_STRING(buf);
239
 
        /* uncomment the following for clearer strace(1)ing */
240
 
        /* memset(iov.iov_base, '\0', iov.iov_len); */
241
 
 
242
 
        mh.msg_iov = &iov;
243
 
        mh.msg_iovlen = 1;
244
 
 
245
 
        Py_BEGIN_ALLOW_THREADS
246
 
        r = recvmsg(fd, &mh, flags);
247
 
        Py_END_ALLOW_THREADS
248
 
 
249
 
        if (r < 0) {
250
 
                PyErr_SetFromErrno(socketmodule_error);
251
 
                goto error;
252
 
        }
253
 
        
254
 
        if (r != iov.iov_len)
255
 
                _PyString_Resize(&buf, r);
256
 
        cmsg = CMSG_FIRSTHDR(&mh);
257
 
        if (NULL == cmsg
258
 
            || cmsg->cmsg_level != SOL_SOCKET
259
 
            || cmsg->cmsg_type != SCM_RIGHTS)
260
 
                return Py_BuildValue("(N())", buf);
261
 
 
262
 
        ret = Py_BuildValue("(OO)", buf, unpack_control(&mh));
263
 
 
264
 
out:
265
 
        if (mh.msg_control) PyMem_Free(mh.msg_control);
266
 
        return ret;
267
 
 
268
 
error:
269
 
        if (buf) { Py_DECREF(buf); }
270
 
        goto out;
271
 
}
272
 
 
273
 
static char fdsend_sendfds__doc__[] =
274
 
"sendfds(fd, msg, flags=0, fds=None) -> bytes_sent\n"
275
 
"\n"
276
 
"Send msg across the socket represented by fd, optionally accompanied by a\n"
277
 
"sequence (tuple or list) of open file handles.  For example:\n"
278
 
"\n"
279
 
"  >>> devnull = open(\"/dev/null\")\n"
280
 
"  >>> sendfds(the_socket, \"null device\", (devnull,))\n"
281
 
"\n"
282
 
"The socket fd and members of the fds sequence may be any representation\n"
283
 
"described in the module docstring.\n"
284
 
"\n"
285
 
"Note that most underlying implementations require at least a one byte msg\n"
286
 
"to transmit open files.";
287
 
 
288
 
static char fdsend_recvfds__doc__[] =
289
 
"recvfds(fd, len, flags=0, numfds=64) -> (message, fd_tuple)\n"
290
 
"\n"
291
 
"Receive a message of up to length len and up to numfds new files from socket\n"
292
 
"object fd.\n"
293
 
"\n"
294
 
"Though the socket object may be given as any of the representations listed\n"
295
 
"in the module docstring, new files returned in fd_tuple are always integral\n"
296
 
"file descriptors.  See os.fdopen for a means of transforming them into\n"
297
 
"Python file objects.\n"
298
 
"\n"
299
 
"There is presently no way to detect msg_flags values (e.g., MSG_CTRUNC).";
300
 
 
301
 
static char socketpair__doc__[] =
302
 
"socketpair(family, type, proto=0) -> (fd, fd)\n"
303
 
"\n"
304
 
"Provided as a convenience for Python versions lacking a socket.socketpair\n"
305
 
"implementation.";
306
 
 
307
 
static PyObject *
308
 
fdsend_socketpair(PyObject *self, PyObject *args)
309
 
{
310
 
        int family, type, proto=0;
311
 
        int fd[2];
312
 
 
313
 
        if (!PyArg_ParseTuple(args, "ii|i:socketpair", &family, &type, &proto))
314
 
                return NULL;
315
 
 
316
 
        if (socketpair(family, type, proto, fd) < 0) {
317
 
                PyErr_SetFromErrno(PyExc_IOError);
318
 
                return NULL;
319
 
        }
320
 
 
321
 
        return Py_BuildValue("(ii)", (long) fd[0], (long) fd[1]);
322
 
}
323
 
 
324
 
 
325
 
/* List of functions */
326
 
 
327
 
static PyMethodDef fdsend_methods[] = {
328
 
        {"sendfds", (PyCFunction)fdsend_sendfds,
329
 
                METH_VARARGS|METH_KEYWORDS, fdsend_sendfds__doc__},
330
 
        {"recvfds", (PyCFunction)fdsend_recvfds,
331
 
                METH_VARARGS|METH_KEYWORDS, fdsend_recvfds__doc__},
332
 
        {"socketpair",  fdsend_socketpair, METH_VARARGS, socketpair__doc__},
333
 
        {NULL,          NULL}           /* sentinel */
334
 
};
335
 
 
336
 
static char module__doc__[] =
337
 
"fdsend allows the passing of open files between unrelated processes via\n"
338
 
"local sockets (using SCM_RIGHTS), a process known as file descriptor\n"
339
 
"passing.  The following functions are available:\n"
340
 
"\n"
341
 
"  sendfds()\n"
342
 
"  recvfds()\n"
343
 
"  socketpair()\n"
344
 
"\n"
345
 
"Unlike some other simplifications of the sendmsg()/recvmsg() interface,\n"
346
 
"fdsend allows multiple files to be transferred in a single operation, and\n"
347
 
"permits ordinary socket messages to accompany the files.  Additionally,\n"
348
 
"fdsend understands bona fide Python sockets and files, as well as objects\n"
349
 
"implementing fileno() methods and integers representing file descriptors.\n"
350
 
"\n"
351
 
"Errors are raised via the socket.error exception object.";
352
 
 
353
 
DL_EXPORT(void)
354
 
initfdsend(void)
355
 
{
356
 
        PyObject *m, *sm;
357
 
 
358
 
        /* Create the module and add the functions and documentation */
359
 
        m = Py_InitModule3("fdsend", fdsend_methods, module__doc__);
360
 
        if ((sm = PyImport_ImportModule("socket")) != NULL) {
361
 
                socketmodule_error = PyObject_GetAttrString(sm, "error");
362
 
        }
363
 
}