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 {
|
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. |
| Also see events: |
[secure_coding][secure_coding][secure_coding] |
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 {
|
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. |
| Also see events: |
[secure_coding][secure_coding][secure_coding] |
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
|
Event secure_coding: |
[VERY RISKY]. Using "sprintf" can cause a buffer overflow when done incorrectly. Because sprintf() assumes an arbitrarily long string, callers must be careful not to overflow the actual space of the destination. Use snprintf() instead, or correct precision specifiers. |
| Also see events: |
[secure_coding][secure_coding][secure_coding] |
270 sprintf ( newpath, "/proc/%d%s", currentPid, &path [ index ] );
271 }
|
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. |
| Also see events: |
[secure_coding][secure_coding][secure_coding] |
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);
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 }