1 /****************************************************************************
2 * Copyright (C) 2006-2010 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3 * jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu *
4 * *
5 * This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src). *
6 * *
7 * DMTCP:dmtcp/src is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP:dmtcp/src 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 Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <vector>
25 #include <list>
26 #include <string>
27 #include <fcntl.h>
28 #include <signal.h>
29 #include <sys/ipc.h>
30 #include <sys/shm.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <unistd.h>
34 #include <sys/syscall.h>
35 #include <linux/version.h>
36 #include <limits.h>
37 #include "uniquepid.h"
38 #include "dmtcpworker.h"
39 #include "dmtcpmessagetypes.h"
40 #include "protectedfds.h"
41 #include "constants.h"
42 #include "connectionmanager.h"
43 #include "syscallwrappers.h"
44 #include "sysvipc.h"
45 #include "util.h"
46 #include "../jalib/jassert.h"
47 #include "../jalib/jconvert.h"
48
49 extern "C" void exit ( int status )
50 {
51 dmtcp::DmtcpWorker::setExitInProgress();
52 _real_exit ( status );
53 for (;;); // Without this, gcc emits warning: `noreturn' fnc does return
54 }
55
56 #ifdef EXTERNAL_SOCKET_HANDLING
57 extern dmtcp::vector <dmtcp::ConnectionIdentifier> externalTcpConnections;
58 static void processClose(dmtcp::ConnectionIdentifier conId)
59 {
60 if ( dmtcp::DmtcpWorker::waitingForExternalSocketsToClose() == true ) {
61 dmtcp::vector <dmtcp::ConnectionIdentifier>::iterator i = externalTcpConnections.begin();
62 for ( i = externalTcpConnections.begin(); i != externalTcpConnections.end(); ++i ) {
63 if ( conId == *i ) {
64 externalTcpConnections.erase(i);
65 break;
66 }
67 }
68 if ( externalTcpConnections.empty() == true ) {
69 }
70 sleep(4);
71 }
72 }
73 #endif
74
75 extern "C" int close ( int fd )
76 {
77 if ( dmtcp::ProtectedFDs::isProtected ( fd ) )
78 {
79 JTRACE ( "blocked attempt to close protected fd" ) ( fd );
80 errno = EBADF;
81 return -1;
82 }
83
84 #ifdef EXTERNAL_SOCKET_HANDLING
85 dmtcp::ConnectionIdentifier conId;
86 if ( dmtcp::WorkerState::currentState() == dmtcp::WorkerState::RUNNING &&
87 dmtcp::DmtcpWorker::waitingForExternalSocketsToClose() == true &&
88 dup2(fd,fd) != -1 ) {
89 conId = dmtcp::KernelDeviceToConnection::instance().retrieve(fd).id();
90 }
91 #endif
92
93 int rv = _real_close ( fd );
94
95 #ifdef EXTERNAL_SOCKET_HANDLING
96 if (rv == 0) {
97 processClose(conId);
98 }
99 #endif
100
101 return rv;
102 }
103
104 extern "C" int fclose(FILE *fp)
105 {
106 int fd = fileno(fp);
107 if ( dmtcp::ProtectedFDs::isProtected ( fd ) )
108 {
109 JTRACE ( "blocked attempt to fclose protected fd" ) ( fd );
110 errno = EBADF;
111 return -1;
112 }
113
114 #ifdef EXTERNAL_SOCKET_HANDLING
115 dmtcp::ConnectionIdentifier conId;
116
117 if ( dmtcp::WorkerState::currentState() == dmtcp::WorkerState::RUNNING &&
118 dmtcp::DmtcpWorker::waitingForExternalSocketsToClose() == true &&
119 dup2(fd,fd) != -1 ) {
120 conId = dmtcp::KernelDeviceToConnection::instance().retrieve(fd).id();
121 }
122 #endif
123
124 int rv = _real_fclose(fp);
125
126 #ifdef EXTERNAL_SOCKET_HANDLING
127 if (rv == 0 ) {
128 processClose(conId);
129 }
130 #endif
131 return rv;
132 }
133
134 /* epoll is currently not supported by DMTCP */
135 extern "C" int epoll_create(int size)
136 {
137 JWARNING (false) .Text("epoll is currently not supported by DMTCP.");
138 errno = EPERM;
139 return -1;
140 }
141
142 extern "C" int socketpair ( int d, int type, int protocol, int sv[2] )
143 {
144 WRAPPER_EXECUTION_DISABLE_CKPT();
145
146 JASSERT ( sv != NULL );
147 int rv = _real_socketpair ( d,type,protocol,sv );
148 JTRACE ( "socketpair()" ) ( sv[0] ) ( sv[1] );
149
150 dmtcp::TcpConnection *a, *b;
151
152 a = new dmtcp::TcpConnection ( d, type, protocol );
153 a->onConnect();
154 b = new dmtcp::TcpConnection ( *a, a->id() );
155
156 dmtcp::KernelDeviceToConnection::instance().create ( sv[0] , a );
157 dmtcp::KernelDeviceToConnection::instance().create ( sv[1] , b );
158
159 WRAPPER_EXECUTION_ENABLE_CKPT();
160
161 return rv;
162 }
163
164 extern "C" int pipe ( int fds[2] )
165 {
166 JTRACE ( "promoting pipe() to socketpair()" );
167 //just promote pipes to socketpairs
168 return socketpair ( AF_UNIX, SOCK_STREAM, 0, fds );
169 }
170
171 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
172 // pipe2 appeared in Linux 2.6.27
173 extern "C" int pipe2 ( int fds[2], int flags )
174 {
175 JTRACE ( "promoting pipe2() to socketpair()" );
176 //just promote pipes to socketpairs
177 int newFlags = 0;
178 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
179 if (flags & O_NONBLOCK != 0) newFlags |= SOCK_NONBLOCK;
180 if (flags & O_CLOEXEC != 0) newFlags |= SOCK_CLOEXEC;
181 #endif
182 return socketpair ( AF_UNIX, SOCK_STREAM | newFlags, 0, fds );
183 }
184 #endif
185
186
187 static int ptsname_r_work ( int fd, char * buf, size_t buflen )
188 {
189 JTRACE ( "Calling ptsname_r" );
190
191 dmtcp::Connection* c = &dmtcp::KernelDeviceToConnection::instance().retrieve ( fd );
192 dmtcp::PtyConnection* ptyCon = (dmtcp::PtyConnection*) c;
193
194 dmtcp::string uniquePtsName = ptyCon->uniquePtsName();
195
196 JTRACE("ptsname_r") (uniquePtsName);
197
198 if ( uniquePtsName.length() >= buflen )
199 {
200 JWARNING ( false ) ( uniquePtsName ) ( uniquePtsName.length() ) ( buflen )
201 .Text ( "fake ptsname() too long for user buffer" );
202 errno = ERANGE;
203 return -1;
204 }
205
206 strcpy ( buf, uniquePtsName.c_str() );
207
208 return 0;
209 }
210
211 extern "C" char *ptsname ( int fd )
212 {
213 /* No need to acquire Wrapper Protection lock since it will be done in ptsname_r */
214 JTRACE ( "ptsname() promoted to ptsname_r()" );
215 static char tmpbuf[PATH_MAX];
216
217 if ( ptsname_r ( fd, tmpbuf, sizeof ( tmpbuf ) ) != 0 )
218 {
219 return NULL;
220 }
221
222 return tmpbuf;
223 }
224
225 extern "C" int ptsname_r ( int fd, char * buf, size_t buflen )
226 {
227 WRAPPER_EXECUTION_DISABLE_CKPT();
228
229 int retVal = ptsname_r_work(fd, buf, buflen);
230
231 WRAPPER_EXECUTION_ENABLE_CKPT();
232
233 return retVal;
234 }
235
236 #ifdef PID_VIRTUALIZATION
237 #include <virtualpidtable.h>
238
239 static void updateProcPath ( const char *path, char *newpath )
240 {
241 char temp [ 10 ];
242 int index, tempIndex;
243
244 if ( path == "" || path == NULL )
245 {
246 strcpy(newpath, "");
247 return;
248 }
249
250 if ( dmtcp::Util::strStartsWith ( path, "/proc/" ) )
251 {
252 index = 6;
253 tempIndex = 0;
254 while ( path [ index ] != '/' )
255 {
256 if ( path [ index ] >= '0' && path [ index ] <= '9' )
257 temp [ tempIndex++ ] = path [ index++ ];
258 else
259 {
260 strcpy ( newpath, path );
261 return;
262 }
263 }
264 temp [ tempIndex ] = '\0';
265 pid_t originalPid = atoi ( temp );
266 pid_t currentPid = dmtcp::VirtualPidTable::instance().originalToCurrentPid( originalPid );
267 if (currentPid == -1)
268 currentPid = originalPid;
269
270 sprintf ( newpath, "/proc/%d%s", currentPid, &path [ index ] );
271 }
272 else strcpy ( newpath, path );
273 return;
274 }
275 #else
276 void updateProcPath ( const char *path, char *newpath )
277 {
278 if ( path == "" || path == NULL ) {
279 strcpy( newpath, "" );
280 return;
281 }
282 strcpy ( newpath, path );
283 return;
284 }
285 #endif
286
287 // The current implementation simply increments the last count and returns it.
288 // Although highly unlikely, this can cause a problem if the counter resets to
289 // zero. In that case we should have some more sophisticated code which checks
290 // to see if the value pointed by counter is in use or not.
291 static int getNextFreeSlavePtyNum()
292 {
293 static int counter = -1;
294 counter++;
295 JASSERT(counter != -1) .Text ("See the comment above");
296 return counter;
297 }
298
299 #define DMTCP_PTS_PREFIX_STR "dmtcp_"
300 #define UNIQUE_PTS_PREFIX_STR "/dev/pts/dmtcp_"
301 //DMTCP_PTS_PREFIX_STR
302
303 static int _nextPtmxId()
304 {
305 static int id = 0;
306 return id++;
307 }
308
309 // XXX: The current implementation for handling Pseudo-Terminal Master-Slave pairs
310 // works only if the process involved in it are restarted from the same
311 // dmtcp_restart command. -- KAPIL
312
313 static void processDevPtmxConnection (int fd)
314 {
315 char ptsName[21];
316
317 JASSERT(_real_ptsname_r(fd, ptsName, 21) == 0) (JASSERT_ERRNO);
318
319 dmtcp::string ptsNameStr = ptsName;
320 dmtcp::string uniquePtsNameStr;
321
322 // glibc allows only 20 char long ptsname
323 // Check if there is enough room to insert the string "dmtcp_" before the
324 // terminal number, if not then we ASSERT here.
325 JASSERT((strlen(ptsName) + strlen("dmtcp_")) <= 20)
326 .Text("string /dev/pts/<n> too long, can not be virtualized."
327 "Once possible workarong here is to replace the string"
328 "\"dmtcp_\" with something short like \"d_\" or even "
329 "\"d\" and recompile DMTCP");
330
331 // Generate new Unique ptsName
332 uniquePtsNameStr = UNIQUE_PTS_PREFIX_STR;
333 uniquePtsNameStr += jalib::XToString(getNextFreeSlavePtyNum());
334
335 dmtcp::string deviceName = "ptmx[" + ptsNameStr + "]:" + "/dev/ptmx";
336
337 // dmtcp::string deviceName = "ptmx[" + dmtcp::UniquePid::ThisProcess().toString()
338 // + ":" + jalib::XToString ( _nextPtmxId() )
339 // + "]:" + device;
340
341 JTRACE ( "creating ptmx connection" ) ( deviceName ) ( ptsNameStr ) ( uniquePtsNameStr );
342
343 int type = dmtcp::PtyConnection::PTY_MASTER;
344 dmtcp::Connection * c = new dmtcp::PtyConnection ( ptsNameStr, uniquePtsNameStr, type );
345
346 dmtcp::KernelDeviceToConnection::instance().createPtyDevice ( fd, deviceName, c );
347
348 dmtcp::UniquePtsNameToPtmxConId::instance().add ( uniquePtsNameStr, c->id() );
349 }
350
351 static void processDevPtsConnection (int fd, const char* uniquePtsName, const char* ptsName)
352 {
353 dmtcp::string ptsNameStr = ptsName;
354 dmtcp::string uniquePtsNameStr = uniquePtsName;
355
356 dmtcp::string deviceName = "pts:" + ptsNameStr;
357
358 JTRACE ( "creating pts connection" ) ( deviceName ) ( ptsNameStr ) ( uniquePtsNameStr );
359
360 int type = dmtcp::PtyConnection::PTY_SLAVE;
361 dmtcp::Connection * c = new dmtcp::PtyConnection ( ptsNameStr, uniquePtsNameStr, type );
362
363 dmtcp::KernelDeviceToConnection::instance().createPtyDevice ( fd, deviceName, c );
364 }
365
366 extern "C" int getpt()
367 {
368 int fd = _real_getpt();
369 if ( fd >= 0 ) {
370 processDevPtmxConnection(fd);
371 }
372 return fd;
373 }
374
375 extern "C" int open (const char *path, int flags, ... )
376 {
377 va_list ap;
378 mode_t mode;
379 int rc;
380 char newpath [ PATH_MAX ] = {0} ;
381
382 // Handling the variable number of arguments
383 va_start( ap, flags );
384 mode = va_arg ( ap, mode_t );
385 va_end ( ap );
386
387 /* If DMTCP has not yet initialized, it might be that JASSERT_INIT() is
388 * calling this function to open jassert log files. Therefore we shouldn't be
389 * playing with locks etc.
390 *
391 * FIXME: The following check is not required anymore. JASSERT_INIT calls
392 * libc:open directly.
393 */
394 if ( dmtcp::WorkerState::currentState() == dmtcp::WorkerState::UNKNOWN ) {
395 return _real_open ( path, flags, mode );
396 }
397
398 WRAPPER_EXECUTION_DISABLE_CKPT();
399
400 if ( dmtcp::Util::strStartsWith(path, UNIQUE_PTS_PREFIX_STR) ) {
401 dmtcp::string currPtsDevName = dmtcp::UniquePtsNameToPtmxConId::instance().retrieveCurrentPtsDeviceName(path);
|
Event secure_coding: |
[VERY RISKY]. Using "strcpy" can cause a buffer overflow when done incorrectly. If the destination string of a strcpy() is not large enough then anything might happen. Use strncpy() instead. |
402 strcpy(newpath, currPtsDevName.c_str());
403 } else {
404 updateProcPath ( path, newpath );
405 }
406
407 int fd = _real_open( newpath, flags, mode );
408
409 if ( fd >= 0 && strcmp(path, "/dev/ptmx") == 0 ) {
410 processDevPtmxConnection(fd);
411 } else if ( fd >= 0 && dmtcp::Util::strStartsWith(path, UNIQUE_PTS_PREFIX_STR) ) {
412 processDevPtsConnection(fd, path, newpath);
413 }
414
415 WRAPPER_EXECUTION_ENABLE_CKPT();
416
417 return fd;
418 }
419
420 extern "C" FILE *fopen (const char* path, const char* mode)
421 {
422 /* If DMTCP has not yet initialized, it might be that JASSERT_INIT() is
423 * calling this function to open jassert log files. Therefore we shouldn't be
424 * playing with locks etc.
425 *
426 * FIXME: The following check is not required anymore. JASSERT_INIT calls
427 * libc:open directly.
428 */
429 if ( dmtcp::WorkerState::currentState() == dmtcp::WorkerState::UNKNOWN ) {
430 return _real_fopen ( path, mode );
431 }
432
433 WRAPPER_EXECUTION_DISABLE_CKPT();
434
435 char newpath [ PATH_MAX ] = {0} ;
436 int fd = -1;
437
438 if ( dmtcp::Util::strStartsWith(path, UNIQUE_PTS_PREFIX_STR) ) {
439 dmtcp::string currPtsDevName = dmtcp::UniquePtsNameToPtmxConId::instance().retrieveCurrentPtsDeviceName(path);
440 strcpy(newpath, currPtsDevName.c_str());
441 } else {
442 updateProcPath ( path, newpath );
443 }
444
445 FILE *file = _real_fopen ( newpath, mode );
446
447 if (file != NULL) {
448 fd = fileno(file);
449 }
450
451 if ( fd >= 0 && strcmp(path, "/dev/ptmx") == 0 ) {
452 processDevPtmxConnection(fd);
453 } else if ( fd >= 0 && dmtcp::Util::strStartsWith(path, UNIQUE_PTS_PREFIX_STR) ) {
454 processDevPtsConnection(fd, path, newpath);
455 }
456
457 WRAPPER_EXECUTION_ENABLE_CKPT();
458
459 return file;
460 }
461
462 static void updateStatPath(const char *path, char *newpath)
463 {
464 if ( dmtcp::WorkerState::currentState() == dmtcp::WorkerState::UNKNOWN ) {
465 strncpy(newpath, path, PATH_MAX);
466 } else if ( dmtcp::Util::strStartsWith(path, UNIQUE_PTS_PREFIX_STR) ) {
467 dmtcp::string currPtsDevName = dmtcp::UniquePtsNameToPtmxConId::instance().retrieveCurrentPtsDeviceName(path);
468 strcpy(newpath, currPtsDevName.c_str());
469 } else {
470 updateProcPath ( path, newpath );
471 }
472 }
473
474 extern "C"
475 int __xstat(int vers, const char *path, struct stat *buf)
476 {
477 char newpath [ PATH_MAX ] = {0} ;
478 WRAPPER_EXECUTION_DISABLE_CKPT();
479 updateStatPath(path, newpath);
480 int rc = _real_xstat( vers, newpath, buf );
481 WRAPPER_EXECUTION_ENABLE_CKPT();
482 return rc;
483 }
484
485 extern "C"
486 int __xstat64(int vers, const char *path, struct stat64 *buf)
487 {
488 char newpath [ PATH_MAX ] = {0} ;
489 WRAPPER_EXECUTION_DISABLE_CKPT();
490 updateStatPath(path, newpath);
491 int rc = _real_xstat64( vers, newpath, buf );
492 WRAPPER_EXECUTION_ENABLE_CKPT();
493 return rc;
494 }
495
496 extern "C"
497 int __lxstat(int vers, const char *path, struct stat *buf)
498 {
499 char newpath [ PATH_MAX ] = {0} ;
500 WRAPPER_EXECUTION_DISABLE_CKPT();
501 updateStatPath(path, newpath);
502 int rc = _real_lxstat( vers, newpath, buf );
503 WRAPPER_EXECUTION_ENABLE_CKPT();
504 return rc;
505 }
506
507 extern "C"
508 int __lxstat64(int vers, const char *path, struct stat64 *buf)
509 {
510 char newpath [ PATH_MAX ] = {0} ;
511 WRAPPER_EXECUTION_DISABLE_CKPT();
512 updateStatPath(path, newpath);
513 int rc = _real_lxstat64( vers, newpath, buf );
514 WRAPPER_EXECUTION_ENABLE_CKPT();
515 return rc;
516 }
517
518 // int fstat(int fd, struct stat *buf);
519
520 #ifdef ENABLE_MALLOC_WRAPPER
521 # ifdef ENABLE_DLOPEN
522 # error "ENABLE_MALLOC_WRAPPER can't work with ENABLE_DLOPEN"
523 # endif
524 extern "C" void *calloc(size_t nmemb, size_t size)
525 {
526 WRAPPER_EXECUTION_DISABLE_CKPT();
527 void *retVal = _real_calloc ( nmemb, size );
528 WRAPPER_EXECUTION_ENABLE_CKPT();
529 return retVal;
530 }
531 extern "C" void *malloc(size_t size)
532 {
533 WRAPPER_EXECUTION_DISABLE_CKPT();
534 void *retVal = _real_malloc ( size );
535 WRAPPER_EXECUTION_ENABLE_CKPT();
536 return retVal;
537 }
538 extern "C" void free(void *ptr)
539 {
540 WRAPPER_EXECUTION_DISABLE_CKPT();
541 _real_free ( ptr );
542 WRAPPER_EXECUTION_ENABLE_CKPT();
543 }
544 extern "C" void *realloc(void *ptr, size_t size)
545 {
546 WRAPPER_EXECUTION_DISABLE_CKPT();
547 void *retVal = _real_realloc ( ptr, size );
548 WRAPPER_EXECUTION_ENABLE_CKPT();
549 return retVal;
550 }
551 #endif
552
553
554 /*
555 extern "C" int
556 printf (const char *format, ...)
557 {
558 va_list arg;
559 int done;
560
561 va_start (arg, format);
562 done = vfprintf (stdout, format, arg);
563 va_end (arg);
564
565 return done;
566 }
567
568 extern "C" int
569 fprintf (FILE *stream, const char *format, ...)
570 {
571 va_list arg;
572 int done;
573
574 va_start (arg, format);
575 done = vfprintf (stream, format, arg);
576 va_end (arg);
577
578 return done;
579 }
580
581 extern "C" int
582 vprintf (const char *format, __gnuc_va_list arg)
583 {
584 return vfprintf (stdout, format, arg);
585 }
586
587 extern "C" int
588 vfprintf (FILE *s, const char *format, va_list ap)
589 {
590 WRAPPER_EXECUTION_DISABLE_CKPT();
591 int retVal = _real_vfprintf ( s, format, ap );
592 WRAPPER_EXECUTION_ENABLE_CKPT();
593 return retVal;
594 }
595
596
597 extern "C" int
598 sprintf (char *s, const char *format, ...)
599 {
600 va_list arg;
601 int done;
602
603 va_start (arg, format);
604 done = vsprintf (s, format, arg);
605 va_end (arg);
606
607 return done;
608 }
609
610
611 extern "C" int
612 snprintf (char *s, size_t maxlen, const char *format, ...)
613 {
614 va_list arg;
615 int done;
616
617 va_start (arg, format);
618 done = vsnprintf (s, maxlen, format, arg);
619 va_end (arg);
620
621 return done;
622 }
623
624
625 extern "C" int vsprintf(char *str, const char *format, va_list ap);
626 extern "C" int vsnprintf(char *str, size_t size, const char *format, va_list ap);
627 */
628
629 extern "C"
630 int shmget(key_t key, size_t size, int shmflg)
631 {
632 int ret;
633 WRAPPER_EXECUTION_DISABLE_CKPT();
634 while (true) {
635 ret = _real_shmget(key, size, shmflg);
636 if (ret != -1 &&
637 dmtcp::SysVIPC::instance().isConflictingShmid(ret) == false) {
638 dmtcp::SysVIPC::instance().on_shmget(key, size, shmflg, ret);
639 break;
640 }
641 JASSERT(_real_shmctl(ret, IPC_RMID, NULL) != -1);
642 };
643 JTRACE ("Creating new Shared memory segment" ) (key) (size) (shmflg) (ret);
644 WRAPPER_EXECUTION_ENABLE_CKPT();
645 return ret;
646 }
647
648 extern "C"
649 void *shmat(int shmid, const void *shmaddr, int shmflg)
650 {
651 WRAPPER_EXECUTION_DISABLE_CKPT();
652 int currentShmid = dmtcp::SysVIPC::instance().originalToCurrentShmid(shmid);
653 JASSERT(currentShmid != -1);
654 void *ret = _real_shmat(currentShmid, shmaddr, shmflg);
655 if (ret != (void *) -1) {
656 dmtcp::SysVIPC::instance().on_shmat(shmid, shmaddr, shmflg, ret);
657 JTRACE ("Mapping Shared memory segment" ) (shmid) (shmflg) (ret);
658 }
659 WRAPPER_EXECUTION_ENABLE_CKPT();
660 return ret;
661 }
662
663 extern "C"
664 int shmdt(const void *shmaddr)
665 {
666 WRAPPER_EXECUTION_DISABLE_CKPT();
667 int ret = _real_shmdt(shmaddr);
668 if (ret != -1) {
669 dmtcp::SysVIPC::instance().on_shmdt(shmaddr);
670 JTRACE ("Unmapping Shared memory segment" ) (shmaddr);
671 }
672 WRAPPER_EXECUTION_ENABLE_CKPT();
673 return ret;
674 }
675
676 extern "C"
677 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
678 {
679 WRAPPER_EXECUTION_DISABLE_CKPT();
680 int currentShmid = dmtcp::SysVIPC::instance().originalToCurrentShmid(shmid);
681 JASSERT(currentShmid != -1);
682 int ret = _real_shmctl(currentShmid, cmd, buf);
683 // Change the creater-pid of the shm object to the original so that if
684 // calling thread wants to use it, pid-virtualization layer can take care of
685 // the original to current conversion.
686 // TODO: Need to update uid/gid fields to support uid/gid virtualization.
687 if (buf != NULL) {
688 buf->shm_cpid = dmtcp::VirtualPidTable::instance().currentToOriginalPid(buf->shm_cpid);
689 }
690 WRAPPER_EXECUTION_ENABLE_CKPT();
691 return ret;
692 }
693
694 extern "C" int __clone ( int ( *fn ) ( void *arg ), void *child_stack, int flags, void *arg, int *parent_tidptr, struct user_desc *newtls, int *child_tidptr );
695 pid_t gettid();
696 int tkill(int tid, int sig);
697 int tgkill(int tgid, int tid, int sig);
698
699 #define SYSCALL_VA_START() \
700 va_list ap; \
701 va_start(ap, sys_num)
702
703 #define SYSCALL_VA_END() \
704 va_end(ap)
705
706 #define SYSCALL_GET_ARG(type,arg) type arg = va_arg(ap, type)
707
708 #define SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2) \
709 SYSCALL_GET_ARG(type1,arg1); \
710 SYSCALL_GET_ARG(type2,arg2)
711
712 #define SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3) \
713 SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2); \
714 SYSCALL_GET_ARG(type3,arg3)
715
716 #define SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
717 SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3); \
718 SYSCALL_GET_ARG(type4,arg4)
719
720 #define SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
721 type5,arg5) \
722 SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4); \
723 SYSCALL_GET_ARG(type5,arg5)
724
725 #define SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
726 type5,arg5,type6,arg6) \
727 SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
728 type5,arg5); \
729 SYSCALL_GET_ARG(type6,arg6)
730
731 #define SYSCALL_GET_ARGS_7(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
732 type5,arg5,type6,arg6,type7,arg7) \
733 SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
734 type5,arg5,type6,arg6); \
735 SYSCALL_GET_ARG(type7,arg7)
736
737 /* Comments by Gene:
738 * Here, syscall is the wrapper, and the call to syscall would be _real_syscall
739 * We would add a special case for SYS_gettid, while all others default as below
740 * It depends on the idea that arguments are stored in registers, whose
741 * natural size is: sizeof(void*)
742 * So, we pass six arguments to syscall, and it will ignore any extra arguments
743 * I believe that all Linux system calls have no more than 7 args.
744 * clone() is an example of one with 7 arguments.
745 * If we discover system calls for which the 7 args strategy doesn't work,
746 * we can special case them.
747 *
748 * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not
749 * use any STL here. (--Kapil)
750 */
751 extern "C" long int syscall(long int sys_num, ... )
752 {
753 long int ret;
754 va_list ap;
755
756 va_start(ap, sys_num);
757
758 switch ( sys_num ) {
759 case SYS_gettid:
760 {
761 ret = gettid();
762 break;
763 }
764 case SYS_tkill:
765 {
766 SYSCALL_GET_ARGS_2(int, tid, int, sig);
767 ret = tkill(tid, sig);
768 break;
769 }
770 case SYS_tgkill:
771 {
772 SYSCALL_GET_ARGS_3(int, tgid, int, tid, int, sig);
773 ret = tgkill(tgid, tid, sig);
774 break;
775 }
776
777 case SYS_clone:
778 {
779 typedef int (*fnc) (void*);
780 SYSCALL_GET_ARGS_7(fnc, fn, void*, child_stack, int, flags, void*, arg,
781 pid_t*, pid, struct user_desc*, tls, pid_t*, ctid);
782 ret = __clone(fn, child_stack, flags, arg, pid, tls, ctid);
783 break;
784 }
785
786 case SYS_execve:
787 {
788 SYSCALL_GET_ARGS_3(const char*,filename,char* const *,argv,char* const *,envp);
789 ret = execve(filename,argv,envp);
790 break;
791 }
792
793 case SYS_fork:
794 {
795 ret = fork();
796 break;
797 }
798 case SYS_exit:
799 {
800 SYSCALL_GET_ARG(int,status);
801 exit(status);
802 break;
803 }
804 case SYS_open:
805 {
806 SYSCALL_GET_ARGS_3(const char*,pathname,int,flags,mode_t,mode);
807 ret = open(pathname, flags, mode);
808 break;
809 }
810 case SYS_close:
811 {
812 SYSCALL_GET_ARG(int,fd);
813 ret = close(fd);
814 break;
815 }
816
817 case SYS_rt_sigaction:
818 {
819 SYSCALL_GET_ARGS_3(int,signum,const struct sigaction*,act,struct sigaction*,oldact);
820 ret = sigaction(signum, act, oldact);
821 break;
822 }
823 case SYS_rt_sigprocmask:
824 {
825 SYSCALL_GET_ARGS_3(int,how,const sigset_t*,set,sigset_t*,oldset);
826 ret = sigprocmask(how, set, oldset);
827 break;
828 }
829 case SYS_rt_sigtimedwait:
830 {
831 SYSCALL_GET_ARGS_3(const sigset_t*,set,siginfo_t*,info,
832 const struct timespec*, timeout);
833 ret = sigtimedwait(set, info, timeout);
834 break;
835 }
836
837 #ifdef __i386__
838 case SYS_sigaction:
839 {
840 SYSCALL_GET_ARGS_3(int,signum,const struct sigaction*,act,struct sigaction*,oldact);
841 ret = sigaction(signum, act, oldact);
842 break;
843 }
844 case SYS_signal:
845 {
846 typedef void (*sighandler_t)(int);
847 SYSCALL_GET_ARGS_2(int,signum,sighandler_t,handler);
848 // Cast needed: signal returns sighandler_t
849 ret = (long int)signal(signum, handler);
850 break;
851 }
852 case SYS_sigprocmask:
853 {
854 SYSCALL_GET_ARGS_3(int,how,const sigset_t*,set,sigset_t*,oldset);
855 ret = sigprocmask(how, set, oldset);
856 break;
857 }
858 #endif
859
860 #ifdef __x86_64__
861 // These SYS_xxx are only defined for 64-bit Linux
862 case SYS_socket:
863 {
864 SYSCALL_GET_ARGS_3(int,domain,int,type,int,protocol);
865 ret = socket(domain,type,protocol);
866 break;
867 }
868 case SYS_connect:
869 {
870 SYSCALL_GET_ARGS_3(int,sockfd,const struct sockaddr*,addr,socklen_t,addrlen);
871 ret = connect(sockfd, addr, addrlen);
872 break;
873 }
874 case SYS_bind:
875 {
876 SYSCALL_GET_ARGS_3(int,sockfd,const struct sockaddr*,addr,socklen_t,addrlen);
877 ret = bind(sockfd,addr,addrlen);
878 break;
879 }
880 case SYS_listen:
881 {
882 SYSCALL_GET_ARGS_2(int,sockfd,int,backlog);
883 ret = listen(sockfd,backlog);
884 break;
885 }
886 case SYS_accept:
887 {
888 SYSCALL_GET_ARGS_3(int,sockfd,struct sockaddr*,addr,socklen_t*,addrlen);
889 ret = accept(sockfd, addr, addrlen);
890 break;
891 }
892 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
893 # if __GLIBC_PREREQ(2,10)
894 case SYS_accept4:
895 {
896 SYSCALL_GET_ARGS_4(int,sockfd,struct sockaddr*,addr,socklen_t*,addrlen,int,flags);
897 ret = accept4(sockfd, addr, addrlen, flags);
898 break;
899 }
900 # endif
901 #endif
902 case SYS_setsockopt:
903 {
904 SYSCALL_GET_ARGS_5(int,s,int,level,int,optname,const void*,optval,socklen_t,optlen);
905 ret = setsockopt(s, level, optname, optval, optlen);
906 break;
907 }
908
909 case SYS_socketpair:
910 {
911 SYSCALL_GET_ARGS_4(int,d,int,type,int,protocol,int*,sv);
912 ret = socketpair(d,type,protocol,sv);
913 break;
914 }
915 #endif
916
917 case SYS_pipe:
918 {
919 SYSCALL_GET_ARG(int*,fds);
920 ret = pipe(fds);
921 break;
922 }
923 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
924 # if __GLIBC_PREREQ(2,9)
925 case SYS_pipe2:
926 {
927 SYSCALL_GET_ARGS_2(int*,fds,int,flags);
928 ret = pipe2(fds, flags);
929 break;
930 }
931 # endif
932 #endif
933
934 #ifdef PID_VIRTUALIZATION
935 case SYS_getpid:
936 {
937 ret = getpid();
938 break;
939 }
940 case SYS_getppid:
941 {
942 ret = getppid();
943 break;
944 }
945
946 case SYS_getpgrp:
947 {
948 ret = getpgrp();
949 break;
950 }
951
952 case SYS_getpgid:
953 {
954 SYSCALL_GET_ARG(pid_t,pid);
955 ret = getpgid(pid);
956 break;
957 }
958 case SYS_setpgid:
959 {
960 SYSCALL_GET_ARGS_2(pid_t,pid,pid_t,pgid);
961 ret = setpgid(pid, pgid);
962 break;
963 }
964
965 case SYS_getsid:
966 {
967 SYSCALL_GET_ARG(pid_t,pid);
968 ret = getsid(pid);
969 break;
970 }
971 case SYS_setsid:
972 {
973 ret = setsid();
974 break;
975 }
976
977 case SYS_kill:
978 {
979 SYSCALL_GET_ARGS_2(pid_t,pid,int,sig);
980 ret = kill(pid, sig);
981 break;
982 }
983
984 case SYS_waitid:
985 {
986 //SYSCALL_GET_ARGS_4(idtype_t,idtype,id_t,id,siginfo_t*,infop,int,options);
987 SYSCALL_GET_ARGS_4(int,idtype,id_t,id,siginfo_t*,infop,int,options);
988 ret = waitid((idtype_t)idtype, id, infop, options);
989 break;
990 }
991 case SYS_wait4:
992 {
993 SYSCALL_GET_ARGS_4(pid_t,pid,__WAIT_STATUS,status,int,options,
994 struct rusage*,rusage);
995 ret = wait4(pid, status, options, rusage);
996 break;
997 }
998 #ifdef __i386__
999 case SYS_waitpid:
1000 {
1001 SYSCALL_GET_ARGS_3(pid_t,pid,int*,status,int,options);
1002 ret = waitpid(pid, status, options);
1003 break;
1004 }
1005 #endif
1006
1007 case SYS_setgid:
1008 {
1009 SYSCALL_GET_ARG(gid_t,gid);
1010 ret = setgid(gid);
1011 break;
1012 }
1013 case SYS_setuid:
1014 {
1015 SYSCALL_GET_ARG(uid_t,uid);
1016 ret = setuid(uid);
1017 break;
1018 }
1019 #endif /* PID_VIRTUALIZATION */
1020
1021 #ifndef DISABLE_SYS_V_IPC
1022 # ifdef __x86_64__
1023 // These SYS_xxx are only defined for 64-bit Linux
1024 case SYS_shmget:
1025 {
1026 SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg);
1027 ret = shmget(key, size, shmflg);
1028 break;
1029 }
1030 case SYS_shmat:
1031 {
1032 SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg);
1033 ret = (unsigned long) shmat(shmid, shmaddr, shmflg);
1034 break;
1035 }
1036 case SYS_shmdt:
1037 {
1038 SYSCALL_GET_ARG(const void*,shmaddr);
1039 ret = shmdt(shmaddr);
1040 break;
1041 }
1042 case SYS_shmctl:
1043 {
1044 SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf);
1045 ret = shmctl(shmid, cmd, buf);
1046 break;
1047 }
1048 # endif
1049 #endif
1050
1051 default:
1052 {
1053 SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4,
1054 void*, arg5, void*, arg6, void*, arg7);
1055 ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1056 break;
1057 }
1058 }
1059 va_end(ap);
1060 return ret;
1061 }