Add generated source files and fix thinko in aarch64-asm.c
[binutils-gdb.git] / gdb / nat / linux-namespaces.c
blob292e7e7ffc83c9c0bda6e66a6b83b83c3e4024a2
1 /* Linux namespaces(7) support.
3 Copyright (C) 2015-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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 3 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "gdbsupport/common-defs.h"
21 #include "nat/linux-namespaces.h"
22 #include "gdbsupport/filestuff.h"
23 #include <fcntl.h>
24 #include <sys/syscall.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include "gdbsupport/gdb_wait.h"
29 #include <signal.h>
30 #include <sched.h>
31 #include "gdbsupport/scope-exit.h"
33 /* See nat/linux-namespaces.h. */
34 bool debug_linux_namespaces;
36 /* Handle systems without fork. */
38 static inline pid_t
39 do_fork (void)
41 #ifdef HAVE_FORK
42 return fork ();
43 #else
44 errno = ENOSYS;
45 return -1;
46 #endif
49 /* Handle systems without setns. */
51 static inline int
52 do_setns (int fd, int nstype)
54 #ifdef HAVE_SETNS
55 return setns (fd, nstype);
56 #elif defined __NR_setns
57 return syscall (__NR_setns, fd, nstype);
58 #else
59 errno = ENOSYS;
60 return -1;
61 #endif
64 /* Handle systems without MSG_CMSG_CLOEXEC. */
66 #ifndef MSG_CMSG_CLOEXEC
67 #define MSG_CMSG_CLOEXEC 0
68 #endif
70 /* A Linux namespace. */
72 struct linux_ns
74 /* Filename of this namespace's entries in /proc/PID/ns. */
75 const char *filename;
77 /* Nonzero if this object has been initialized. */
78 int initialized;
80 /* Nonzero if this namespace is supported on this system. */
81 int supported;
83 /* ID of the namespace the calling process is in, used to
84 see if other processes share the namespace. The code in
85 this file assumes that the calling process never changes
86 namespace. */
87 ino_t id;
90 /* Return the absolute filename of process PID's /proc/PID/ns
91 entry for namespace NS. The returned value persists until
92 this function is next called. */
94 static const char *
95 linux_ns_filename (struct linux_ns *ns, int pid)
97 static char filename[PATH_MAX];
99 gdb_assert (pid > 0);
100 xsnprintf (filename, sizeof (filename), "/proc/%d/ns/%s", pid,
101 ns->filename);
103 return filename;
106 /* Return a representation of the caller's TYPE namespace, or
107 NULL if TYPE namespaces are not supported on this system. */
109 static struct linux_ns *
110 linux_ns_get_namespace (enum linux_ns_type type)
112 static struct linux_ns namespaces[NUM_LINUX_NS_TYPES] =
114 { "ipc" },
115 { "mnt" },
116 { "net" },
117 { "pid" },
118 { "user" },
119 { "uts" },
121 struct linux_ns *ns;
123 gdb_assert (type >= 0 && type < NUM_LINUX_NS_TYPES);
124 ns = &namespaces[type];
126 if (!ns->initialized)
128 struct stat sb;
130 if (stat (linux_ns_filename (ns, getpid ()), &sb) == 0)
132 ns->id = sb.st_ino;
134 ns->supported = 1;
137 ns->initialized = 1;
140 return ns->supported ? ns : NULL;
143 /* See nat/linux-namespaces.h. */
146 linux_ns_same (pid_t pid, enum linux_ns_type type)
148 struct linux_ns *ns = linux_ns_get_namespace (type);
149 const char *filename;
150 struct stat sb;
152 /* If the kernel does not support TYPE namespaces then there's
153 effectively only one TYPE namespace that all processes on
154 the system share. */
155 if (ns == NULL)
156 return 1;
158 /* Stat PID's TYPE namespace entry to get the namespace ID. This
159 might fail if the process died, or if we don't have the right
160 permissions (though we should be attached by this time so this
161 seems unlikely). In any event, we can't make any decisions and
162 must throw. */
163 filename = linux_ns_filename (ns, pid);
164 if (stat (filename, &sb) != 0)
165 perror_with_name (filename);
167 return sb.st_ino == ns->id;
170 /* We need to use setns(2) to handle filesystem access in mount
171 namespaces other than our own, but this isn't permitted for
172 multithreaded processes. GDB is multithreaded when compiled
173 with Guile support, and may become multithreaded if compiled
174 with Python support. We deal with this by spawning a single-
175 threaded helper process to access mount namespaces other than
176 our own.
178 The helper process is started the first time a call to setns
179 is required. The main process (GDB or gdbserver) communicates
180 with the helper via sockets, passing file descriptors where
181 necessary using SCM_RIGHTS. Once started the helper process
182 runs until the main process terminates; when this happens the
183 helper will receive socket errors, notice that its parent died,
184 and exit accordingly (see mnsh_maybe_mourn_peer).
186 The protocol is that the main process sends a request in a
187 single message, and the helper replies to every message it
188 receives with a single-message response. If the helper
189 receives a message it does not understand it will reply with
190 a MNSH_MSG_ERROR message. The main process checks all
191 responses it receives with gdb_assert, so if the main process
192 receives something unexpected (which includes MNSH_MSG_ERROR)
193 the main process will call internal_error.
195 For avoidance of doubt, if the helper process receives a
196 message it doesn't handle it will reply with MNSH_MSG_ERROR.
197 If the main process receives MNSH_MSG_ERROR at any time then
198 it will call internal_error. If internal_error causes the
199 main process to exit, the helper will notice this and also
200 exit. The helper will not exit until the main process
201 terminates, so if the user continues through internal_error
202 the helper will still be there awaiting requests from the
203 main process.
205 Messages in both directions have the following payload:
207 - TYPE (enum mnsh_msg_type, always sent) - the message type.
208 - INT1 and
209 - INT2 (int, always sent, though not always used) - two
210 values whose meaning is message-type-dependent.
211 See enum mnsh_msg_type documentation below.
212 - FD (int, optional, sent using SCM_RIGHTS) - an open file
213 descriptor.
214 - BUF (unstructured data, optional) - some data with message-
215 type-dependent meaning.
217 Note that the helper process is the child of a call to fork,
218 so all code in the helper must be async-signal-safe. */
220 /* Mount namespace helper message types. */
222 enum mnsh_msg_type
224 /* A communication error occurred. Receipt of this message
225 by either end will cause an assertion failure in the main
226 process. */
227 MNSH_MSG_ERROR,
229 /* Requests, sent from the main process to the helper. */
231 /* A request that the helper call setns. Arguments should
232 be passed in FD and INT1. Helper should respond with a
233 MNSH_RET_INT. */
234 MNSH_REQ_SETNS,
236 /* A request that the helper call open. Arguments should
237 be passed in BUF, INT1 and INT2. The filename (in BUF)
238 should include a terminating NUL character. The helper
239 should respond with a MNSH_RET_FD. */
240 MNSH_REQ_OPEN,
242 /* A request that the helper call unlink. The single
243 argument (the filename) should be passed in BUF, and
244 should include a terminating NUL character. The helper
245 should respond with a MNSH_RET_INT. */
246 MNSH_REQ_UNLINK,
248 /* A request that the helper call readlink. The single
249 argument (the filename) should be passed in BUF, and
250 should include a terminating NUL character. The helper
251 should respond with a MNSH_RET_INTSTR. */
252 MNSH_REQ_READLINK,
254 /* Responses, sent to the main process from the helper. */
256 /* Return an integer in INT1 and errno in INT2. */
257 MNSH_RET_INT,
259 /* Return a file descriptor in FD if one was opened or an
260 integer in INT1 otherwise. Return errno in INT2. */
261 MNSH_RET_FD,
263 /* Return an integer in INT1, errno in INT2, and optionally
264 some data in BUF. */
265 MNSH_RET_INTSTR,
268 /* Print a string representation of a message using debug_printf.
269 This function is not async-signal-safe so should never be
270 called from the helper. */
272 static void
273 mnsh_debug_print_message (enum mnsh_msg_type type,
274 int fd, int int1, int int2,
275 const void *buf, int bufsiz)
277 gdb_byte *c = (gdb_byte *) buf;
278 gdb_byte *cl = c + bufsiz;
280 switch (type)
282 case MNSH_MSG_ERROR:
283 debug_printf ("ERROR");
284 break;
286 case MNSH_REQ_SETNS:
287 debug_printf ("SETNS");
288 break;
290 case MNSH_REQ_OPEN:
291 debug_printf ("OPEN");
292 break;
294 case MNSH_REQ_UNLINK:
295 debug_printf ("UNLINK");
296 break;
298 case MNSH_REQ_READLINK:
299 debug_printf ("READLINK");
300 break;
302 case MNSH_RET_INT:
303 debug_printf ("INT");
304 break;
306 case MNSH_RET_FD:
307 debug_printf ("FD");
308 break;
310 case MNSH_RET_INTSTR:
311 debug_printf ("INTSTR");
312 break;
314 default:
315 debug_printf ("unknown-packet-%d", type);
318 debug_printf (" %d %d %d \"", fd, int1, int2);
320 for (; c < cl; c++)
321 debug_printf (*c >= ' ' && *c <= '~' ? "%c" : "\\%o", *c);
323 debug_printf ("\"");
326 /* Forward declaration. */
328 static void mnsh_maybe_mourn_peer (void);
330 /* Send a message. The argument SOCK is the file descriptor of the
331 sending socket, the other arguments are the payload to send.
332 Return the number of bytes sent on success. Return -1 on failure
333 and set errno appropriately. This function is called by both the
334 main process and the helper so must be async-signal-safe. */
336 static ssize_t
337 mnsh_send_message (int sock, enum mnsh_msg_type type,
338 int fd, int int1, int int2,
339 const void *buf, int bufsiz)
341 struct msghdr msg;
342 struct iovec iov[4];
343 char fdbuf[CMSG_SPACE (sizeof (fd))];
344 ssize_t size;
346 /* Build the basic TYPE, INT1, INT2 message. */
347 memset (&msg, 0, sizeof (msg));
348 msg.msg_iov = iov;
350 iov[0].iov_base = &type;
351 iov[0].iov_len = sizeof (type);
352 iov[1].iov_base = &int1;
353 iov[1].iov_len = sizeof (int1);
354 iov[2].iov_base = &int2;
355 iov[2].iov_len = sizeof (int2);
357 msg.msg_iovlen = 3;
359 /* Append BUF if supplied. */
360 if (buf != NULL && bufsiz > 0)
362 iov[3].iov_base = alloca (bufsiz);
363 memcpy (iov[3].iov_base, buf, bufsiz);
364 iov[3].iov_len = bufsiz;
366 msg.msg_iovlen ++;
369 /* Attach FD if supplied. */
370 if (fd >= 0)
372 struct cmsghdr *cmsg;
374 msg.msg_control = fdbuf;
375 msg.msg_controllen = sizeof (fdbuf);
377 cmsg = CMSG_FIRSTHDR (&msg);
378 cmsg->cmsg_level = SOL_SOCKET;
379 cmsg->cmsg_type = SCM_RIGHTS;
380 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
382 memcpy (CMSG_DATA (cmsg), &fd, sizeof (int));
384 msg.msg_controllen = cmsg->cmsg_len;
387 /* Send the message. */
388 size = sendmsg (sock, &msg, 0);
390 if (size < 0)
391 mnsh_maybe_mourn_peer ();
393 if (debug_linux_namespaces)
395 debug_printf ("mnsh: send: ");
396 mnsh_debug_print_message (type, fd, int1, int2, buf, bufsiz);
397 debug_printf (" -> %s\n", pulongest (size));
400 return size;
403 /* Receive a message. The argument SOCK is the file descriptor of
404 the receiving socket, the other arguments point to storage for
405 the received payload. Returns the number of bytes stored into
406 BUF on success, which may be zero in the event no BUF was sent.
407 Return -1 on failure and set errno appropriately. This function
408 is called from both the main process and the helper and must be
409 async-signal-safe. */
411 static ssize_t
412 mnsh_recv_message (int sock, enum mnsh_msg_type *type,
413 int *fd, int *int1, int *int2,
414 void *buf, int bufsiz)
416 struct msghdr msg;
417 struct iovec iov[4];
418 char fdbuf[CMSG_SPACE (sizeof (*fd))];
419 struct cmsghdr *cmsg;
420 ssize_t size, fixed_size;
421 int i;
423 /* Build the message to receive data into. */
424 memset (&msg, 0, sizeof (msg));
425 msg.msg_iov = iov;
427 iov[0].iov_base = type;
428 iov[0].iov_len = sizeof (*type);
429 iov[1].iov_base = int1;
430 iov[1].iov_len = sizeof (*int1);
431 iov[2].iov_base = int2;
432 iov[2].iov_len = sizeof (*int2);
433 iov[3].iov_base = buf;
434 iov[3].iov_len = bufsiz;
436 msg.msg_iovlen = 4;
438 for (fixed_size = i = 0; i < msg.msg_iovlen - 1; i++)
439 fixed_size += iov[i].iov_len;
441 msg.msg_control = fdbuf;
442 msg.msg_controllen = sizeof (fdbuf);
444 /* Receive the message. */
445 size = recvmsg (sock, &msg, MSG_CMSG_CLOEXEC);
446 if (size < 0)
448 if (debug_linux_namespaces)
449 debug_printf ("namespace-helper: recv failed (%s)\n",
450 pulongest (size));
452 mnsh_maybe_mourn_peer ();
454 return size;
457 /* Check for truncation. */
458 if (size < fixed_size || (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)))
460 if (debug_linux_namespaces)
461 debug_printf ("namespace-helper: recv truncated (%s 0x%x)\n",
462 pulongest (size), msg.msg_flags);
464 mnsh_maybe_mourn_peer ();
466 errno = EBADMSG;
467 return -1;
470 /* Unpack the file descriptor if supplied. */
471 cmsg = CMSG_FIRSTHDR (&msg);
472 if (cmsg != NULL
473 && cmsg->cmsg_len == CMSG_LEN (sizeof (int))
474 && cmsg->cmsg_level == SOL_SOCKET
475 && cmsg->cmsg_type == SCM_RIGHTS)
476 memcpy (fd, CMSG_DATA (cmsg), sizeof (int));
477 else
478 *fd = -1;
480 if (debug_linux_namespaces)
482 debug_printf ("mnsh: recv: ");
483 mnsh_debug_print_message (*type, *fd, *int1, *int2, buf,
484 size - fixed_size);
485 debug_printf ("\n");
488 /* Return the number of bytes of data in BUF. */
489 return size - fixed_size;
492 /* Shortcuts for returning results from the helper. */
494 #define mnsh_return_int(sock, result, error) \
495 mnsh_send_message (sock, MNSH_RET_INT, -1, result, error, NULL, 0)
497 #define mnsh_return_fd(sock, fd, error) \
498 mnsh_send_message (sock, MNSH_RET_FD, \
499 (fd) < 0 ? -1 : (fd), \
500 (fd) < 0 ? (fd) : 0, \
501 error, NULL, 0)
503 #define mnsh_return_intstr(sock, result, buf, bufsiz, error) \
504 mnsh_send_message (sock, MNSH_RET_INTSTR, -1, result, error, \
505 buf, bufsiz)
507 /* Handle a MNSH_REQ_SETNS message. Must be async-signal-safe. */
509 static ssize_t
510 mnsh_handle_setns (int sock, int fd, int nstype)
512 int result = do_setns (fd, nstype);
514 return mnsh_return_int (sock, result, errno);
517 /* Handle a MNSH_REQ_OPEN message. Must be async-signal-safe. */
519 static ssize_t
520 mnsh_handle_open (int sock, const char *filename,
521 int flags, mode_t mode)
523 scoped_fd fd = gdb_open_cloexec (filename, flags, mode);
524 return mnsh_return_fd (sock, fd.get (), errno);
527 /* Handle a MNSH_REQ_UNLINK message. Must be async-signal-safe. */
529 static ssize_t
530 mnsh_handle_unlink (int sock, const char *filename)
532 int result = unlink (filename);
534 return mnsh_return_int (sock, result, errno);
537 /* Handle a MNSH_REQ_READLINK message. Must be async-signal-safe. */
539 static ssize_t
540 mnsh_handle_readlink (int sock, const char *filename)
542 char buf[PATH_MAX];
543 int len = readlink (filename, buf, sizeof (buf));
545 return mnsh_return_intstr (sock, len,
546 buf, len < 0 ? 0 : len,
547 errno);
550 /* The helper process. Never returns. Must be async-signal-safe. */
552 static void mnsh_main (int sock) ATTRIBUTE_NORETURN;
554 static void
555 mnsh_main (int sock)
557 while (1)
559 enum mnsh_msg_type type;
560 int fd = -1, int1, int2;
561 char buf[PATH_MAX];
562 ssize_t size, response = -1;
564 size = mnsh_recv_message (sock, &type,
565 &fd, &int1, &int2,
566 buf, sizeof (buf));
568 if (size >= 0 && size < sizeof (buf))
570 switch (type)
572 case MNSH_REQ_SETNS:
573 if (fd > 0)
574 response = mnsh_handle_setns (sock, fd, int1);
575 break;
577 case MNSH_REQ_OPEN:
578 if (size > 0 && buf[size - 1] == '\0')
579 response = mnsh_handle_open (sock, buf, int1, int2);
580 break;
582 case MNSH_REQ_UNLINK:
583 if (size > 0 && buf[size - 1] == '\0')
584 response = mnsh_handle_unlink (sock, buf);
585 break;
587 case MNSH_REQ_READLINK:
588 if (size > 0 && buf[size - 1] == '\0')
589 response = mnsh_handle_readlink (sock, buf);
590 break;
592 default:
593 break; /* Handled below. */
597 /* Close any file descriptors we were passed. */
598 if (fd >= 0)
599 close (fd);
601 /* Can't handle this message, bounce it back. */
602 if (response < 0)
604 if (size < 0)
605 size = 0;
607 mnsh_send_message (sock, MNSH_MSG_ERROR,
608 -1, int1, int2, buf, size);
613 /* The mount namespace helper process. */
615 struct linux_mnsh
617 /* PID of helper. */
618 pid_t pid;
620 /* Socket for communication. */
621 int sock;
623 /* ID of the mount namespace the helper is currently in. */
624 ino_t nsid;
627 /* In the helper process this is set to the PID of the process that
628 created the helper (i.e. GDB or gdbserver). In the main process
629 this is set to zero. Used by mnsh_maybe_mourn_peer. */
630 static int mnsh_creator_pid = 0;
632 /* Return an object representing the mount namespace helper process.
633 If no mount namespace helper process has been started then start
634 one. Return NULL if no mount namespace helper process could be
635 started. */
637 static struct linux_mnsh *
638 linux_mntns_get_helper (void)
640 static struct linux_mnsh *helper = NULL;
642 if (helper == NULL)
644 static struct linux_mnsh h;
645 struct linux_ns *ns;
646 pid_t helper_creator = getpid ();
647 int sv[2];
649 ns = linux_ns_get_namespace (LINUX_NS_MNT);
650 if (ns == NULL)
651 return NULL;
653 if (gdb_socketpair_cloexec (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
654 return NULL;
656 h.pid = do_fork ();
657 if (h.pid < 0)
659 int saved_errno = errno;
661 close (sv[0]);
662 close (sv[1]);
664 errno = saved_errno;
665 return NULL;
668 if (h.pid == 0)
670 /* Child process. */
671 close (sv[0]);
673 mnsh_creator_pid = helper_creator;
675 /* Debug printing isn't async-signal-safe. */
676 debug_linux_namespaces = 0;
678 mnsh_main (sv[1]);
681 /* Parent process. */
682 close (sv[1]);
684 helper = &h;
685 helper->sock = sv[0];
686 helper->nsid = ns->id;
688 if (debug_linux_namespaces)
689 debug_printf ("Started mount namespace helper process %d\n",
690 helper->pid);
693 return helper;
696 /* Check whether the other process died and act accordingly. Called
697 whenever a socket error occurs, from both the main process and the
698 helper. Must be async-signal-safe when called from the helper. */
700 static void
701 mnsh_maybe_mourn_peer (void)
703 if (mnsh_creator_pid != 0)
705 /* We're in the helper. Check if our current parent is the
706 process that started us. If it isn't, then our original
707 parent died and we've been reparented. Exit immediately
708 if that's the case. */
709 if (getppid () != mnsh_creator_pid)
710 _exit (0);
712 else
714 /* We're in the main process. */
716 struct linux_mnsh *helper = linux_mntns_get_helper ();
717 int status;
718 pid_t pid;
720 if (helper->pid < 0)
722 /* We already mourned it. */
723 return;
726 pid = waitpid (helper->pid, &status, WNOHANG);
727 if (pid == 0)
729 /* The helper is still alive. */
730 return;
732 else if (pid == -1)
734 if (errno == ECHILD)
735 warning (_("mount namespace helper vanished?"));
736 else
737 internal_warning (_("unhandled error %d"), errno);
739 else if (pid == helper->pid)
741 if (WIFEXITED (status))
742 warning (_("mount namespace helper exited with status %d"),
743 WEXITSTATUS (status));
744 else if (WIFSIGNALED (status))
745 warning (_("mount namespace helper killed by signal %d"),
746 WTERMSIG (status));
747 else
748 internal_warning (_("unhandled status %d"), status);
750 else
751 internal_warning (_("unknown pid %d"), pid);
753 /* Something unrecoverable happened. */
754 helper->pid = -1;
758 /* Shortcuts for sending messages to the helper. */
760 #define mnsh_send_setns(helper, fd, nstype) \
761 mnsh_send_message (helper->sock, MNSH_REQ_SETNS, fd, nstype, 0, \
762 NULL, 0)
764 #define mnsh_send_open(helper, filename, flags, mode) \
765 mnsh_send_message (helper->sock, MNSH_REQ_OPEN, -1, flags, mode, \
766 filename, strlen (filename) + 1)
768 #define mnsh_send_unlink(helper, filename) \
769 mnsh_send_message (helper->sock, MNSH_REQ_UNLINK, -1, 0, 0, \
770 filename, strlen (filename) + 1)
772 #define mnsh_send_readlink(helper, filename) \
773 mnsh_send_message (helper->sock, MNSH_REQ_READLINK, -1, 0, 0, \
774 filename, strlen (filename) + 1)
776 /* Receive a message from the helper. Issue an assertion failure if
777 the message isn't a correctly-formatted MNSH_RET_INT. Set RESULT
778 and ERROR and return 0 on success. Set errno and return -1 on
779 failure. */
781 static int
782 mnsh_recv_int (struct linux_mnsh *helper, int *result, int *error)
784 enum mnsh_msg_type type;
785 char buf[PATH_MAX];
786 ssize_t size;
787 int fd;
789 size = mnsh_recv_message (helper->sock, &type, &fd,
790 result, error,
791 buf, sizeof (buf));
792 if (size < 0)
793 return -1;
795 gdb_assert (type == MNSH_RET_INT);
796 gdb_assert (fd == -1);
797 gdb_assert (size == 0);
799 return 0;
802 /* Receive a message from the helper. Issue an assertion failure if
803 the message isn't a correctly-formatted MNSH_RET_FD. Set FD and
804 ERROR and return 0 on success. Set errno and return -1 on
805 failure. */
807 static int
808 mnsh_recv_fd (struct linux_mnsh *helper, int *fd, int *error)
810 enum mnsh_msg_type type;
811 char buf[PATH_MAX];
812 ssize_t size;
813 int result;
815 size = mnsh_recv_message (helper->sock, &type, fd,
816 &result, error,
817 buf, sizeof (buf));
818 if (size < 0)
819 return -1;
821 gdb_assert (type == MNSH_RET_FD);
822 gdb_assert (size == 0);
824 if (*fd < 0)
826 gdb_assert (result < 0);
827 *fd = result;
830 return 0;
833 /* Receive a message from the helper. Issue an assertion failure if
834 the message isn't a correctly-formatted MNSH_RET_INTSTR. Set
835 RESULT and ERROR and optionally store data in BUF, then return
836 the number of bytes stored in BUF on success (this may be zero).
837 Set errno and return -1 on error. */
839 static ssize_t
840 mnsh_recv_intstr (struct linux_mnsh *helper,
841 int *result, int *error,
842 void *buf, int bufsiz)
844 enum mnsh_msg_type type;
845 ssize_t size;
846 int fd;
848 size = mnsh_recv_message (helper->sock, &type, &fd,
849 result, error,
850 buf, bufsiz);
852 if (size < 0)
853 return -1;
855 gdb_assert (type == MNSH_RET_INTSTR);
856 gdb_assert (fd == -1);
858 return size;
861 /* Return values for linux_mntns_access_fs. */
863 enum mnsh_fs_code
865 /* Something went wrong, errno is set. */
866 MNSH_FS_ERROR = -1,
868 /* The main process is in the correct mount namespace.
869 The caller should access the filesystem directly. */
870 MNSH_FS_DIRECT,
872 /* The helper is in the correct mount namespace.
873 The caller should access the filesystem via the helper. */
874 MNSH_FS_HELPER
877 /* Return a value indicating how the caller should access the
878 mount namespace of process PID. */
880 static enum mnsh_fs_code
881 linux_mntns_access_fs (pid_t pid)
883 struct linux_ns *ns;
884 struct stat sb;
885 struct linux_mnsh *helper;
886 ssize_t size;
887 int fd;
889 if (pid == getpid ())
890 return MNSH_FS_DIRECT;
892 ns = linux_ns_get_namespace (LINUX_NS_MNT);
893 if (ns == NULL)
894 return MNSH_FS_DIRECT;
896 fd = gdb_open_cloexec (linux_ns_filename (ns, pid), O_RDONLY, 0).release ();
897 if (fd < 0)
898 return MNSH_FS_ERROR;
900 SCOPE_EXIT
902 int save_errno = errno;
903 close (fd);
904 errno = save_errno;
907 if (fstat (fd, &sb) != 0)
908 return MNSH_FS_ERROR;
910 if (sb.st_ino == ns->id)
911 return MNSH_FS_DIRECT;
913 helper = linux_mntns_get_helper ();
914 if (helper == NULL)
915 return MNSH_FS_ERROR;
917 if (sb.st_ino != helper->nsid)
919 int result, error;
921 size = mnsh_send_setns (helper, fd, 0);
922 if (size < 0)
923 return MNSH_FS_ERROR;
925 if (mnsh_recv_int (helper, &result, &error) != 0)
926 return MNSH_FS_ERROR;
928 if (result != 0)
930 /* ENOSYS indicates that an entire function is unsupported
931 (it's not appropriate for our versions of open/unlink/
932 readlink to sometimes return with ENOSYS depending on how
933 they're called) so we convert ENOSYS to ENOTSUP if setns
934 fails. */
935 if (error == ENOSYS)
936 error = ENOTSUP;
938 errno = error;
939 return MNSH_FS_ERROR;
942 helper->nsid = sb.st_ino;
945 return MNSH_FS_HELPER;
948 /* See nat/linux-namespaces.h. */
951 linux_mntns_open_cloexec (pid_t pid, const char *filename,
952 int flags, mode_t mode)
954 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
955 struct linux_mnsh *helper;
956 int fd, error;
957 ssize_t size;
959 if (access == MNSH_FS_ERROR)
960 return -1;
962 if (access == MNSH_FS_DIRECT)
963 return gdb_open_cloexec (filename, flags, mode).release ();
965 gdb_assert (access == MNSH_FS_HELPER);
967 helper = linux_mntns_get_helper ();
969 size = mnsh_send_open (helper, filename, flags, mode);
970 if (size < 0)
971 return -1;
973 if (mnsh_recv_fd (helper, &fd, &error) != 0)
974 return -1;
976 if (fd < 0)
977 errno = error;
979 return fd;
982 /* See nat/linux-namespaces.h. */
985 linux_mntns_unlink (pid_t pid, const char *filename)
987 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
988 struct linux_mnsh *helper;
989 int ret, error;
990 ssize_t size;
992 if (access == MNSH_FS_ERROR)
993 return -1;
995 if (access == MNSH_FS_DIRECT)
996 return unlink (filename);
998 gdb_assert (access == MNSH_FS_HELPER);
1000 helper = linux_mntns_get_helper ();
1002 size = mnsh_send_unlink (helper, filename);
1003 if (size < 0)
1004 return -1;
1006 if (mnsh_recv_int (helper, &ret, &error) != 0)
1007 return -1;
1009 if (ret != 0)
1010 errno = error;
1012 return ret;
1015 /* See nat/linux-namespaces.h. */
1017 ssize_t
1018 linux_mntns_readlink (pid_t pid, const char *filename,
1019 char *buf, size_t bufsiz)
1021 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
1022 struct linux_mnsh *helper;
1023 int ret, error;
1024 ssize_t size;
1026 if (access == MNSH_FS_ERROR)
1027 return -1;
1029 if (access == MNSH_FS_DIRECT)
1030 return readlink (filename, buf, bufsiz);
1032 gdb_assert (access == MNSH_FS_HELPER);
1034 helper = linux_mntns_get_helper ();
1036 size = mnsh_send_readlink (helper, filename);
1037 if (size < 0)
1038 return -1;
1040 size = mnsh_recv_intstr (helper, &ret, &error, buf, bufsiz);
1042 if (size < 0)
1044 ret = -1;
1045 errno = error;
1047 else
1048 gdb_assert (size == ret);
1050 return ret;