1 #define PY_SSIZE_T_CLEAN
2 #include "Python.h"
3 #include "structmember.h"
4
5 #include "common.h"
6 #include "memory.h"
7
8
9 /****************** Internal use only **********************/
10 PyObject *
shm_str(SharedMemory * self)11 shm_str(SharedMemory *self) {
12 return PyUnicode_FromFormat("Key=%ld, id=%d", (long)self->key, self->id);
13 }
14
15 PyObject *
shm_repr(SharedMemory * self)16 shm_repr(SharedMemory *self) {
17 return PyUnicode_FromFormat("sysv_ipc.SharedMemory(%ld)", (long)self->key);
18 }
19
20 PyObject *
shm_attach(SharedMemory * self,void * address,int shmat_flags)21 shm_attach(SharedMemory *self, void *address, int shmat_flags) {
22 DPRINTF("attaching memory @ address %p with id %d using flags 0x%x\n",
23 address, self->id, shmat_flags);
24
25 self->address = shmat(self->id, address, shmat_flags);
26
27 if ((void *)-1 == self->address) {
28 self->address = NULL;
29 switch (errno) {
30 case EACCES:
31 PyErr_SetString(pPermissionsException, "No permission to attach");
32 break;
33
34 case ENOMEM:
35 PyErr_SetString(PyExc_MemoryError, "Not enough memory");
36 break;
37
38 case EINVAL:
39 PyErr_SetString(PyExc_ValueError, "Invalid id, address, or flags");
40 break;
41
42 default:
43 PyErr_SetFromErrno(PyExc_OSError);
44 break;
45 }
46
47 goto error_return;
48 }
49 else {
50 // memory was attached successfully
51 self->read_only = (shmat_flags & SHM_RDONLY) ? 1 : 0;
52 DPRINTF("set memory's internal read_only flag to %d\n", self->read_only);
53 }
54
55 Py_RETURN_NONE;
56
57 error_return:
58 return NULL;
59 }
60
61
62 PyObject *
shm_remove(int shared_memory_id)63 shm_remove(int shared_memory_id) {
64 struct shmid_ds shm_info;
65
66 DPRINTF("removing shm with id %d\n", shared_memory_id);
67 if (-1 == shmctl(shared_memory_id, IPC_RMID, &shm_info)) {
68 switch (errno) {
69 case EIDRM:
70 case EINVAL:
71 PyErr_Format(pExistentialException,
72 "No shared memory with id %d exists",
73 shared_memory_id);
74 break;
75
76 case EPERM:
77 PyErr_SetString(pPermissionsException,
78 "You do not have permission to remove the shared memory");
79 break;
80
81 default:
82 PyErr_SetFromErrno(PyExc_OSError);
83 break;
84 }
85 goto error_return;
86 }
87
88 Py_RETURN_NONE;
89
90 error_return:
91 return NULL;
92 }
93
94
95 static PyObject *
shm_get_value(int shared_memory_id,enum GET_SET_IDENTIFIERS field)96 shm_get_value(int shared_memory_id, enum GET_SET_IDENTIFIERS field) {
97 // Gets one of the values in GET_SET_IDENTIFIERS and returns it as a boxed Python int or long.
98 // The caller assumes responsibility for the reference.
99 // If an error occurs, sets the Python error and returns NULL.
100 struct shmid_ds shm_info;
101 PyObject *py_value = NULL;
102
103 DPRINTF("Calling shmctl(...IPC_STAT...), field = %d\n", field);
104 if (-1 == shmctl(shared_memory_id, IPC_STAT, &shm_info)) {
105 switch (errno) {
106 case EIDRM:
107 case EINVAL:
108 PyErr_Format(pExistentialException,
109 "No shared memory with id %d exists",
110 shared_memory_id);
111 break;
112
113 case EACCES:
114 PyErr_SetString(pPermissionsException,
115 "You do not have permission to read the shared memory attribute");
116 break;
117
118 default:
119 PyErr_SetFromErrno(PyExc_OSError);
120 break;
121 }
122
123 goto error_return;
124 }
125
126 switch (field) {
127 case SVIFP_SHM_SIZE:
128 py_value = SIZE_T_TO_PY(shm_info.shm_segsz);
129 break;
130
131 case SVIFP_SHM_LAST_ATTACH_TIME:
132 py_value = TIME_T_TO_PY(shm_info.shm_atime);
133 break;
134
135 case SVIFP_SHM_LAST_DETACH_TIME:
136 py_value = TIME_T_TO_PY(shm_info.shm_dtime);
137 break;
138
139 case SVIFP_SHM_LAST_CHANGE_TIME:
140 py_value = TIME_T_TO_PY(shm_info.shm_ctime);
141 break;
142
143 case SVIFP_SHM_CREATOR_PID:
144 py_value = PID_T_TO_PY(shm_info.shm_cpid);
145 break;
146
147 case SVIFP_SHM_LAST_AT_DT_PID:
148 py_value = PID_T_TO_PY(shm_info.shm_lpid);
149 break;
150
151 case SVIFP_SHM_NUMBER_ATTACHED:
152 // shm_nattch is unsigned
153 // ref: http://www.opengroup.org/onlinepubs/007908799/xsh/sysshm.h.html
154 py_value = PyLong_FromUnsignedLong(shm_info.shm_nattch);
155 break;
156
157 case SVIFP_IPC_PERM_UID:
158 py_value = UID_T_TO_PY(shm_info.shm_perm.uid);
159 break;
160
161 case SVIFP_IPC_PERM_GID:
162 py_value = GID_T_TO_PY(shm_info.shm_perm.gid);
163 break;
164
165 case SVIFP_IPC_PERM_CUID:
166 py_value = UID_T_TO_PY(shm_info.shm_perm.cuid);
167 break;
168
169 case SVIFP_IPC_PERM_CGID:
170 py_value = GID_T_TO_PY(shm_info.shm_perm.cgid);
171 break;
172
173 case SVIFP_IPC_PERM_MODE:
174 py_value = MODE_T_TO_PY(shm_info.shm_perm.mode);
175 break;
176
177 default:
178 PyErr_Format(pInternalException, "Bad field %d passed to shm_get_value", field);
179 goto error_return;
180 break;
181 }
182
183 return py_value;
184
185 error_return:
186 return NULL;
187 }
188
189
190 static int
shm_set_ipc_perm_value(int id,enum GET_SET_IDENTIFIERS field,union ipc_perm_value value)191 shm_set_ipc_perm_value(int id, enum GET_SET_IDENTIFIERS field, union ipc_perm_value value) {
192 struct shmid_ds shm_info;
193
194 if (-1 == shmctl(id, IPC_STAT, &shm_info)) {
195 switch (errno) {
196 case EIDRM:
197 case EINVAL:
198 PyErr_Format(pExistentialException,
199 "No shared memory with id %d exists", id);
200 break;
201
202 case EACCES:
203 PyErr_SetString(pPermissionsException,
204 "You do not have permission to read the shared memory attribute");
205 break;
206
207 default:
208 PyErr_SetFromErrno(PyExc_OSError);
209 break;
210 }
211 goto error_return;
212 }
213
214 switch (field) {
215 case SVIFP_IPC_PERM_UID:
216 shm_info.shm_perm.uid = value.uid;
217 break;
218
219 case SVIFP_IPC_PERM_GID:
220 shm_info.shm_perm.gid = value.gid;
221 break;
222
223 case SVIFP_IPC_PERM_MODE:
224 shm_info.shm_perm.mode = value.mode;
225 break;
226
227 default:
228 PyErr_Format(pInternalException,
229 "Bad field %d passed to shm_set_ipc_perm_value",
230 field);
231 goto error_return;
232 break;
233 }
234
235 if (-1 == shmctl(id, IPC_SET, &shm_info)) {
236 switch (errno) {
237 case EIDRM:
238 case EINVAL:
239 PyErr_Format(pExistentialException,
240 "No shared memory with id %d exists", id);
241 break;
242
243 case EPERM:
244 PyErr_SetString(pPermissionsException,
245 "You do not have permission to change the shared memory's attributes");
246 break;
247
248 default:
249 PyErr_SetFromErrno(PyExc_OSError);
250 break;
251 }
252
253 goto error_return;
254 }
255
256 return 0;
257
258 error_return:
259 return -1;
260 }
261
262 int
shm_get_buffer(SharedMemory * self,Py_buffer * view,int flags)263 shm_get_buffer(SharedMemory *self, Py_buffer *view, int flags)
264 // Implementation of buffer interface (getbufferproc). The buffer implementation in Python 3.x was
265 // backported to 2.7, and the 3.x documentation is more complete and easier to understand.
266 // https://docs.python.org/3/c-api/typeobj.html#buffer-structs
267 {
268 PyObject *py_size = shm_get_value(self->id, SVIFP_SHM_SIZE);
269 Py_ssize_t size;
270
271 if (!py_size) {
272 // If shm_get_value() failed, the Python error will already be set so there's no
273 // need for me to set it here.
274 return -1;
275 }
276 else {
277 size = PyLong_AsSsize_t(py_size);
278 Py_DECREF(py_size);
279 return PyBuffer_FillInfo(view,
280 (PyObject *)self,
281 self->address,
282 size,
283 0,
284 flags);
285 }
286 }
287
288
289 /****************** Class methods **********************/
290
291
292 void
SharedMemory_dealloc(SharedMemory * self)293 SharedMemory_dealloc(SharedMemory *self) {
294 Py_TYPE(self)->tp_free((PyObject*)self);
295 }
296
297 PyObject *
SharedMemory_new(PyTypeObject * type,PyObject * args,PyObject * kwlist)298 SharedMemory_new(PyTypeObject *type, PyObject *args, PyObject *kwlist) {
299 SharedMemory *self;
300
301 self = (SharedMemory *)type->tp_alloc(type, 0);
302
303 if (NULL != self) {
304 self->key = (key_t)-1;
305 self->id = 0;
306 self->read_only = 0;
307 self->address = NULL;
308 }
309
310 return (PyObject *)self;
311 }
312
313
314 int
SharedMemory_init(SharedMemory * self,PyObject * args,PyObject * keywords)315 SharedMemory_init(SharedMemory *self, PyObject *args, PyObject *keywords) {
316 NoneableKey key;
317 int mode = 0600;
318 unsigned long size = 0;
319 int shmget_flags = 0;
320 int shmat_flags = 0;
321 char init_character = ' ';
322 char *keyword_list[ ] = {"key", "flags", "mode", "size", "init_character", NULL};
323 PyObject *py_size = NULL;
324
325 DPRINTF("Inside SharedMemory_init()\n");
326
327 if (!PyArg_ParseTupleAndKeywords(args, keywords, "O&|iikc", keyword_list,
328 &convert_key_param, &key,
329 &shmget_flags, &mode, &size,
330 &init_character))
331 goto error_return;
332
333 mode &= 0777;
334 shmget_flags &= ~0777;
335
336 DPRINTF("key is none = %d, key value = %ld\n", key.is_none, (long)key.value);
337
338 if ( !(shmget_flags & IPC_CREAT) && (shmget_flags & IPC_EXCL) ) {
339 PyErr_SetString(PyExc_ValueError,
340 "IPC_EXCL must be combined with IPC_CREAT");
341 goto error_return;
342 }
343
344 if (key.is_none && ((shmget_flags & IPC_EXCL) != IPC_EXCL)) {
345 PyErr_SetString(PyExc_ValueError,
346 "Key can only be None if IPC_EXCL is set");
347 goto error_return;
348 }
349
350 // When creating a new segment, the default size is PAGE_SIZE.
351 if (((shmget_flags & IPC_CREX) == IPC_CREX) && (!size))
352 size = PAGE_SIZE;
353
354 if (key.is_none) {
355 // (key == None) ==> generate a key for the caller
356 do {
357 errno = 0;
358 self->key = get_random_key();
359
360 DPRINTF("Calling shmget, key=%ld, size=%lu, mode=%o, flags=0x%x\n",
361 (long)self->key, size, mode, shmget_flags);
362 self->id = shmget(self->key, size, mode | shmget_flags);
363 } while ( (-1 == self->id) && (EEXIST == errno) );
364 }
365 else {
366 // (key != None) ==> use key supplied by the caller
367 self->key = key.value;
368
369 DPRINTF("Calling shmget, key=%ld, size=%lu, mode=%o, flags=0x%x\n",
370 (long)self->key, size, mode, shmget_flags);
371 self->id = shmget(self->key, size, mode | shmget_flags);
372 }
373
374 DPRINTF("id == %d\n", self->id);
375
376 if (self->id == -1) {
377 switch (errno) {
378 case EACCES:
379 PyErr_Format(pPermissionsException,
380 "Permission %o cannot be granted on the existing segment",
381 mode);
382 break;
383
384 case EEXIST:
385 PyErr_Format(pExistentialException,
386 "Shared memory with the key %ld already exists",
387 (long)self->key);
388 break;
389
390 case ENOENT:
391 PyErr_Format(pExistentialException,
392 "No shared memory exists with the key %ld", (long)self->key);
393 break;
394
395 case EINVAL:
396 PyErr_SetString(PyExc_ValueError, "The size is invalid");
397 break;
398
399 case ENOMEM:
400 PyErr_SetString(PyExc_MemoryError, "Not enough memory");
401 break;
402
403 case ENOSPC:
404 PyErr_SetString(PyExc_OSError,
405 "Not enough shared memory identifiers available (ENOSPC)");
406 break;
407
408 default:
409 PyErr_SetFromErrno(PyExc_OSError);
410 break;
411 }
412 goto error_return;
413 }
414
415 // Attach the memory. If no write permissions requested, attach read-only.
416 shmat_flags = (mode & 0200) ? 0 : SHM_RDONLY;
417 if (NULL == shm_attach(self, NULL, shmat_flags)) {
418 // Bad news, something went wrong.
419 goto error_return;
420 }
421
422 if ( ((shmget_flags & IPC_CREX) == IPC_CREX) && (!(shmat_flags & SHM_RDONLY)) ) {
423 // Initialize the memory.
424
425 py_size = shm_get_value(self->id, SVIFP_SHM_SIZE);
426
427 if (!py_size)
428 goto error_return;
429 else {
430 size = PyLong_AsUnsignedLongMask(py_size);
431
432 DPRINTF("memsetting address %p to %lu bytes of ASCII 0x%x (%c)\n", \
433 self->address, size, (int)init_character, init_character);
434 memset(self->address, init_character, size);
435 }
436
437 Py_DECREF(py_size);
438 }
439
440 return 0;
441
442 error_return:
443 return -1;
444 }
445
446
447 PyObject *
SharedMemory_attach(SharedMemory * self,PyObject * args,PyObject * keywords)448 SharedMemory_attach(SharedMemory *self, PyObject *args, PyObject *keywords) {
449 PyObject *py_address = NULL;
450 void *address = NULL;
451 int flags = 0;
452 static char *keyword_list[ ] = {"address", "flags", NULL};
453
454 DPRINTF("Inside SharedMemory_attach()\n");
455
456 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|Oi", keyword_list,
457 &py_address, &flags))
458 goto error_return;
459
460 if ((!py_address) || (py_address == Py_None))
461 address = NULL;
462 else {
463 if (PyLong_Check(py_address))
464 address = PyLong_AsVoidPtr(py_address);
465 else {
466 PyErr_SetString(PyExc_TypeError, "address must be a long");
467 goto error_return;
468 }
469 }
470
471 return shm_attach(self, address, flags);
472
473 error_return:
474 return NULL;
475 }
476
477
478 PyObject *
SharedMemory_detach(SharedMemory * self)479 SharedMemory_detach(SharedMemory *self) {
480 if (-1 == shmdt(self->address)) {
481 self->address = NULL;
482 switch (errno) {
483 case EINVAL:
484 PyErr_SetNone(pNotAttachedException);
485 break;
486
487 default:
488 PyErr_SetFromErrno(PyExc_OSError);
489 break;
490 }
491 goto error_return;
492 }
493
494 self->address = NULL;
495
496 Py_RETURN_NONE;
497
498 error_return:
499 return NULL;
500 }
501
502
503 PyObject *
SharedMemory_read(SharedMemory * self,PyObject * args,PyObject * keywords)504 SharedMemory_read(SharedMemory *self, PyObject *args, PyObject *keywords) {
505 /* Tricky business here. A memory segment's size is a size_t which is
506 ulong or smaller. However, the largest string that Python can
507 construct is of ssize_t which is long or smaller. Therefore, the
508 size and offset variables must be ulongs while the byte_count
509 must be a long (and must not exceed LONG_MAX).
510 Mind your math!
511 */
512 long byte_count = 0;
513 unsigned long offset = 0;
514 unsigned long size;
515 PyObject *py_size;
516 char *keyword_list[ ] = {"byte_count", "offset", NULL};
517
518 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|lk", keyword_list,
519 &byte_count, &offset))
520 goto error_return;
521
522 if (self->address == NULL) {
523 PyErr_SetString(pNotAttachedException,
524 "Read attempt on unattached memory segment");
525 goto error_return;
526 }
527
528 if ( (py_size = shm_get_value(self->id, SVIFP_SHM_SIZE)) ) {
529 size = PyLong_AsUnsignedLongMask(py_size);
530 Py_DECREF(py_size);
531 }
532 else
533 goto error_return;
534
535 DPRINTF("offset = %lu, byte_count = %ld, size = %lu\n",
536 offset, byte_count, size);
537
538 if (offset >= size) {
539 PyErr_SetString(PyExc_ValueError, "The offset must be less than the segment size");
540 goto error_return;
541 }
542
543 if (byte_count < 0) {
544 PyErr_SetString(PyExc_ValueError, "The byte_count cannot be negative");
545 goto error_return;
546 }
547
548 /* If the caller didn't specify a byte count or specified one that would
549 read past the end of the segment, return everything from the offset to
550 the end of the segment.
551 Be careful here not to express the second if condition w/addition, e.g.
552 (byte_count + offset > size)
553 It might be more intuitive but since byte_count is a long and offset
554 is a ulong, their sum could cause an arithmetic overflow. */
555 if ((!byte_count) || ((unsigned long)byte_count > size - offset)) {
556 // byte_count needs to be calculated
557 if (size - offset <= (unsigned long)PY_STRING_LENGTH_MAX)
558 byte_count = size - offset;
559 else {
560 // Caller is asking for more bytes than I can stuff into
561 // a Python string.
562 PyErr_Format(PyExc_ValueError,
563 "The byte_count cannot exceed Python's max string length %ld",
564 (long)PY_STRING_LENGTH_MAX);
565 goto error_return;
566 }
567 }
568
569 return PyBytes_FromStringAndSize(self->address + offset, byte_count);
570
571 error_return:
572 return NULL;
573 }
574
575
576 PyObject *
SharedMemory_write(SharedMemory * self,PyObject * args,PyObject * kw)577 SharedMemory_write(SharedMemory *self, PyObject *args, PyObject *kw) {
578 /* See comments for read() regarding "size issues". Note that here
579 Python provides the byte_count so it can't be negative.
580
581 In Python >= 2.5, the Python argument specifier 's#' expects a
582 py_ssize_t for its second parameter. A long is long enough. It might
583 be too big, though, on platforms where a long is larger than
584 py_ssize_t. Therefore I *must* initialize it to 0 so that whatever
585 Python doesn't write to is zeroed out.
586 */
587 unsigned long offset = 0;
588 unsigned long size;
589 PyObject *py_size;
590 char *keyword_list[ ] = {"s", "offset", NULL};
591 static char args_format[] = "s*|k";
592 Py_buffer data;
593
594 if (!PyArg_ParseTupleAndKeywords(args, kw, args_format, keyword_list,
595 &data,
596 &offset))
597 goto error_return;
598
599 if (self->read_only) {
600 PyErr_SetString(PyExc_OSError, "Write attempt on read-only memory segment");
601 goto error_return;
602 }
603
604 if (self->address == NULL) {
605 PyErr_SetString(pNotAttachedException, "Write attempt on unattached memory segment");
606 goto error_return;
607 }
608
609 if ( (py_size = shm_get_value(self->id, SVIFP_SHM_SIZE)) ) {
610 size = PyLong_AsUnsignedLongMask(py_size);
611 Py_DECREF(py_size);
612 }
613 else
614 goto error_return;
615
616 DPRINTF("write size check; size=%lu, offset=%lu, dat.len=%ld\n",
617 size, offset, data.len);
618
619 // Remember that offset and size are both ulongs, so size > offset, then
620 // size - offset (as in the second part of the if expression) will evaluate
621 // to a "negative" number which is a very large ulong.
622 if ((offset > size) || ((unsigned long)data.len > size - offset)) {
623 PyErr_SetString(PyExc_ValueError, "Attempt to write past end of memory segment");
624 goto error_return;
625 }
626
627 memcpy((self->address + offset), data.buf, data.len);
628
629 PyBuffer_Release(&data);
630
631 Py_RETURN_NONE;
632
633 error_return:
634 PyBuffer_Release(&data);
635 return NULL;
636 }
637
638 PyObject *
SharedMemory_remove(SharedMemory * self)639 SharedMemory_remove(SharedMemory *self) {
640 return shm_remove(self->id);
641 }
642
643
644 PyObject *
shm_get_key(SharedMemory * self)645 shm_get_key(SharedMemory *self) {
646 return KEY_T_TO_PY(self->key);
647 }
648
649 PyObject *
shm_get_size(SharedMemory * self)650 shm_get_size(SharedMemory *self) {
651 return shm_get_value(self->id, SVIFP_SHM_SIZE);
652 }
653
654 PyObject *
shm_get_address(SharedMemory * self)655 shm_get_address(SharedMemory *self) {
656 return PyLong_FromVoidPtr(self->address);
657 }
658
659 PyObject *
shm_get_attached(SharedMemory * self)660 shm_get_attached(SharedMemory *self) {
661 if (self->address)
662 Py_RETURN_TRUE;
663 else
664 Py_RETURN_FALSE;
665 }
666
667 PyObject *
shm_get_last_attach_time(SharedMemory * self)668 shm_get_last_attach_time(SharedMemory *self) {
669 return shm_get_value(self->id, SVIFP_SHM_LAST_ATTACH_TIME);
670 }
671
672 PyObject *
shm_get_last_detach_time(SharedMemory * self)673 shm_get_last_detach_time(SharedMemory *self) {
674 return shm_get_value(self->id, SVIFP_SHM_LAST_DETACH_TIME);
675 }
676
677 PyObject *
shm_get_last_change_time(SharedMemory * self)678 shm_get_last_change_time(SharedMemory *self) {
679 return shm_get_value(self->id, SVIFP_SHM_LAST_CHANGE_TIME);
680 }
681
682 PyObject *
shm_get_creator_pid(SharedMemory * self)683 shm_get_creator_pid(SharedMemory *self) {
684 return shm_get_value(self->id, SVIFP_SHM_CREATOR_PID);
685 }
686
687 PyObject *
shm_get_last_pid(SharedMemory * self)688 shm_get_last_pid(SharedMemory *self) {
689 return shm_get_value(self->id, SVIFP_SHM_LAST_AT_DT_PID);
690 }
691
692 PyObject *
shm_get_number_attached(SharedMemory * self)693 shm_get_number_attached(SharedMemory *self) {
694 return shm_get_value(self->id, SVIFP_SHM_NUMBER_ATTACHED);
695 }
696
697 PyObject *
shm_get_uid(SharedMemory * self)698 shm_get_uid(SharedMemory *self) {
699 return shm_get_value(self->id, SVIFP_IPC_PERM_UID);
700 }
701
702 PyObject *
shm_get_cuid(SharedMemory * self)703 shm_get_cuid(SharedMemory *self) {
704 return shm_get_value(self->id, SVIFP_IPC_PERM_CUID);
705 }
706
707 PyObject *
shm_get_cgid(SharedMemory * self)708 shm_get_cgid(SharedMemory *self) {
709 return shm_get_value(self->id, SVIFP_IPC_PERM_CGID);
710 }
711
712 PyObject *
shm_get_mode(SharedMemory * self)713 shm_get_mode(SharedMemory *self) {
714 return shm_get_value(self->id, SVIFP_IPC_PERM_MODE);
715 }
716
717 int
shm_set_uid(SharedMemory * self,PyObject * py_value)718 shm_set_uid(SharedMemory *self, PyObject *py_value) {
719 union ipc_perm_value new_value;
720
721 if (!PyLong_Check(py_value))
722 {
723 PyErr_SetString(PyExc_TypeError, "Attribute 'uid' must be an integer");
724 goto error_return;
725 }
726
727 new_value.uid = PyLong_AsLong(py_value);
728
729 if (((uid_t)-1 == new_value.uid) && PyErr_Occurred()) {
730 // no idea what could have gone wrong -- punt it up to the caller
731 goto error_return;
732 }
733
734 return shm_set_ipc_perm_value(self->id, SVIFP_IPC_PERM_UID, new_value);
735
736 error_return:
737 return -1;
738 }
739
740
741 PyObject *
shm_get_gid(SharedMemory * self)742 shm_get_gid(SharedMemory *self) {
743 return shm_get_value(self->id, SVIFP_IPC_PERM_GID);
744 }
745
746 int
shm_set_gid(SharedMemory * self,PyObject * py_value)747 shm_set_gid(SharedMemory *self, PyObject *py_value) {
748 union ipc_perm_value new_value;
749
750 if (!PyLong_Check(py_value))
751 {
752 PyErr_Format(PyExc_TypeError, "attribute 'gid' must be an integer");
753 goto error_return;
754 }
755
756 new_value.gid = PyLong_AsLong(py_value);
757
758 if (((gid_t)-1 == new_value.gid) && PyErr_Occurred()) {
759 // no idea what could have gone wrong -- punt it up to the caller
760 goto error_return;
761 }
762
763 return shm_set_ipc_perm_value(self->id, SVIFP_IPC_PERM_GID, new_value);
764
765 error_return:
766 return -1;
767 }
768
769 int
shm_set_mode(SharedMemory * self,PyObject * py_value)770 shm_set_mode(SharedMemory *self, PyObject *py_value) {
771 union ipc_perm_value new_value;
772
773 if (!PyLong_Check(py_value))
774 {
775 PyErr_Format(PyExc_TypeError, "attribute 'mode' must be an integer");
776 goto error_return;
777 }
778
779 new_value.mode = PyLong_AsLong(py_value);
780
781 if (((mode_t)-1 == new_value.mode) && PyErr_Occurred()) {
782 // no idea what could have gone wrong -- punt it up to the caller
783 goto error_return;
784 }
785
786 return shm_set_ipc_perm_value(self->id, SVIFP_IPC_PERM_MODE, new_value);
787
788 error_return:
789 return -1;
790 }
791
792