1 #define PY_SSIZE_T_CLEAN
2 #include "Python.h"
3 #include "structmember.h"
4 
5 #define PY_STRING_LENGTH_MAX  PY_SSIZE_T_MAX
6 
7 #include <sys/ipc.h>
8 #include <sys/shm.h>
9 #include <sys/sem.h>
10 #include <sys/msg.h>
11 
12 #include "probe_results.h"
13 
14 /* Struct to contain a key which can be None */
15 typedef struct {
16     int is_none;
17     key_t value;
18 } NoneableKey;
19 
20 
21 /* These identifiers are prefixed with SVIFP_ which stands for SysV Ipc
22 For Python. It's really just a random string of letters to prevent clashes
23 with other constants (as happens with SHM_SIZE on AIX).
24 */
25 enum GET_SET_IDENTIFIERS {
26     SVIFP_IPC_PERM_UID = 1,
27     SVIFP_IPC_PERM_GID,
28     SVIFP_IPC_PERM_CUID,
29     SVIFP_IPC_PERM_CGID,
30     SVIFP_IPC_PERM_MODE,
31     SVIFP_SEM_OTIME,
32     SVIFP_SHM_SIZE,
33     SVIFP_SHM_LAST_ATTACH_TIME,
34     SVIFP_SHM_LAST_DETACH_TIME,
35     SVIFP_SHM_LAST_CHANGE_TIME,
36     SVIFP_SHM_CREATOR_PID,
37     SVIFP_SHM_LAST_AT_DT_PID,
38     SVIFP_SHM_NUMBER_ATTACHED,
39     SVIFP_MQ_LAST_SEND_TIME,
40     SVIFP_MQ_LAST_RECEIVE_TIME,
41     SVIFP_MQ_LAST_CHANGE_TIME,
42     SVIFP_MQ_CURRENT_MESSAGES,
43     SVIFP_MQ_QUEUE_BYTES_MAX,
44     SVIFP_MQ_LAST_SEND_PID,
45     SVIFP_MQ_LAST_RECEIVE_PID
46 };
47 
48 // Shorthand for lazy typists like me
49 #define IPC_CREX  (IPC_CREAT | IPC_EXCL)
50 
51 #ifdef SYSV_IPC_DEBUG
52 #define DPRINTF(fmt, args...) fprintf(stderr, "+++ " fmt, ## args)
53 #else
54 #define DPRINTF(fmt, args...)
55 #endif
56 
57 /* **************************************************************************
58 I have to do some guessing about types, mostly with regard to key_t. Since I
59 schlep these values back and forth between C and Python, I need to know
60 approximately what types these represent so that I can call the appropriate
61 Python function to convert them to Python values (e.g. PyInt_FromLong(),
62 PyFloat_FromDouble(), etc.)
63 
64 For most of these types the SUSv3 specification states that they're
65 integer-ish which means I can stuff them into a long and not worry. The macros
66 below safely convert each type and above each macro I document why my type
67 assumptions are safe.
68 
69 Unfortunately, key_t is an exception. The SUSv3 specification doesn't get more
70 detailed than saying it is "arithmetic", which includes signed and unsigned
71 short, int, long, long long, float and double (but thankfully excludes
72 pointers). I feel I can safely ignore long long since support for it is far
73 from ubiquitous.
74 
75 Ideally I would cast key_t to double and call PyWhatever_FromDouble() when
76 sending values to Python. Representing it as a double would ensure no data
77 loss regardless of whether it is typedef-ed as int, long, float, etc.
78 
79 In practice, this would be awkward. I have yet to see a platform where
80 key_t is not integer-ish, so most or all users of this library would be
81 surprised if it returned keys as floats.
82 
83 So I store keys as key_t types and cast them to long when Python forces
84 me to be specific. The two disadvantages to this are, (1) if any platforms
85 typedef key_t as a float or double, this code will break, and (2) KEY_MIN
86 and KEY_MAX don't represent the real min and max of keys.
87 
88 Point #1 is mitigated somewhat because if any OS typedefs key_t as float or
89 double, this code should complain loudly during compilation.
90 
91 Typedefs of key_t (for 32 bit systems):
92 OpenSolaris 2008.11 - int
93 OS X 10.5.8 - __int32_t (int)
94 Ubuntu 9.04 - int
95 Freebsd - l_int (int)
96 ************************************************************************** */
97 
98 
99 // key_t is guaranteed to be an arithmetic type. Some earlier versions
100 // of the standard didn't guarantee that it was arithmetic; the standard was
101 // changed to guarantee that it *is* arithmetic.
102 // ref: http://pubs.opengroup.org/onlinepubs/009696899/functions/xsh_chap02_12.html
103 // I assume it is a long; see comment above.
104 // Some functions return (key_t)-1, so I guess this has to be a signed type.
105 // ref: http://www.opengroup.org/austin/interps/doc.tpl?gdid=6226
106 #define KEY_T_TO_PY(key)   PyLong_FromLong(key)
107 
108 // SUSv3 guarantees a uid_t to be an integer type. Some functions return
109 // (uid_t)-1, so I guess this has to be a signed type.
110 // ref: http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
111 // ref: http://www.opengroup.org/onlinepubs/9699919799/functions/chown.html
112 #define UID_T_TO_PY(uid)   PyLong_FromLong(uid)
113 
114 // SUSv3 guarantees a gid_t to be an integer type. Some functions return
115 // (gid_t)-1, so I guess this has to be a signed type.
116 // ref: http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
117 #define GID_T_TO_PY(gid)   PyLong_FromLong(gid)
118 
119 // I'm not sure what guarantees SUSv3 makes about a mode_t, but param 3 of
120 // shmget() is an int that contains flags in addition to the mode, so
121 // mode must be able to fit into an int.
122 // ref: http://www.opengroup.org/onlinepubs/009695399/functions/shmget.html
123 #define MODE_T_TO_PY(mode)   PyLong_FromLong(mode)
124 
125 // I'm not sure what guarantees SUSv3 makes about a time_t, but the times
126 // I deal with here are all guaranteed to be after 1 Jan 1970 which means
127 // they'll always be positive numbers. A ulong sounds appropriate to me,
128 // and Python agrees in posixmodule.c.
129 #define TIME_T_TO_PY(time)   PyLong_FromUnsignedLong(time)
130 
131 // C89 guarantees a size_t to be unsigned and fit into a ulong or smaller.
132 #define SIZE_T_TO_PY(size)   PyLong_FromUnsignedLong(size)
133 
134 // SUSv3 guarantees a pid_t to be a signed integer type. Some functions
135 // return (pid_t)-1 so I guess this has to be signed.
136 // ref: http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/types.h.html#tag_13_67
137 #define PID_T_TO_PY(pid)   PyLong_FromLong(pid)
138 
139 // The SUS guarantees a msglen_t to be an unsigned integer type.
140 // Ditto: msgqnum_t.
141 // ref: http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/msg.h.html
142 #define MSGLEN_T_TO_PY(msglen)     PyLong_FromUnsignedLong(msglen)
143 #define MSGQNUM_T_TO_PY(msgqnum)   PyLong_FromUnsignedLong(msgqnum)
144 
145 /* Utility functions */
146 key_t get_random_key(void);
147 int convert_key_param(PyObject *, void *);
148 
149 /* Custom Exceptions/Errors */
150 extern PyObject *pBaseException;
151 extern PyObject *pInternalException;
152 extern PyObject *pPermissionsException;
153 extern PyObject *pExistentialException;
154 extern PyObject *pBusyException;
155 extern PyObject *pNotAttachedException;
156