|  | /* Serial interface for local domain connections on Un*x like systems. | 
|  |  | 
|  | Copyright (C) 1992-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "serial.h" | 
|  | #include "ser-base.h" | 
|  |  | 
|  | #include <sys/socket.h> | 
|  | #include <sys/un.h> | 
|  |  | 
|  | #ifndef UNIX_PATH_MAX | 
|  | #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) | 
|  | #endif | 
|  |  | 
|  | /* Open an AF_UNIX socket.  */ | 
|  |  | 
|  | static void | 
|  | uds_open (struct serial *scb, const char *name) | 
|  | { | 
|  | struct sockaddr_un addr; | 
|  |  | 
|  | if (strlen (name) > UNIX_PATH_MAX - 1) | 
|  | error (_("The socket name is too long.  It may be no longer than %s bytes."), | 
|  | pulongest (UNIX_PATH_MAX - 1L)); | 
|  |  | 
|  | memset (&addr, 0, sizeof addr); | 
|  | addr.sun_family = AF_UNIX; | 
|  | strncpy (addr.sun_path, name, UNIX_PATH_MAX - 1); | 
|  |  | 
|  | scb->fd = socket (AF_UNIX, SOCK_STREAM, 0); | 
|  | if (scb->fd < 0) | 
|  | perror_with_name (_("could not open socket")); | 
|  |  | 
|  | if (connect (scb->fd, (struct sockaddr *) &addr, | 
|  | sizeof (struct sockaddr_un)) < 0) | 
|  | { | 
|  | int saved = errno; | 
|  | close (scb->fd); | 
|  | perror_with_name (_("could not connect to remote"), saved); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | uds_close (struct serial *scb) | 
|  | { | 
|  | if (scb->fd == -1) | 
|  | return; | 
|  |  | 
|  | close (scb->fd); | 
|  | scb->fd = -1; | 
|  | } | 
|  |  | 
|  | static int | 
|  | uds_read_prim (struct serial *scb, size_t count) | 
|  | { | 
|  | int result = recv (scb->fd, scb->buf, count, 0); | 
|  | if (result == -1 && errno != EINTR) | 
|  | perror_with_name ("error while reading"); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static int | 
|  | uds_write_prim (struct serial *scb, const void *buf, size_t count) | 
|  | { | 
|  | int result = send (scb->fd, buf, count, 0); | 
|  | if (result == -1 && errno != EINTR) | 
|  | perror_with_name ("error while writing"); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* The local socket ops.  */ | 
|  |  | 
|  | static const struct serial_ops uds_ops = | 
|  | { | 
|  | "local", | 
|  | uds_open, | 
|  | uds_close, | 
|  | NULL, | 
|  | ser_base_readchar, | 
|  | ser_base_write, | 
|  | ser_base_flush_output, | 
|  | ser_base_flush_input, | 
|  | ser_base_send_break, | 
|  | ser_base_raw, | 
|  | ser_base_get_tty_state, | 
|  | ser_base_copy_tty_state, | 
|  | ser_base_set_tty_state, | 
|  | ser_base_print_tty_state, | 
|  | ser_base_setbaudrate, | 
|  | ser_base_setstopbits, | 
|  | ser_base_setparity, | 
|  | ser_base_drain_output, | 
|  | ser_base_async, | 
|  | uds_read_prim, | 
|  | uds_write_prim | 
|  | }; | 
|  |  | 
|  | void _initialize_ser_socket (); | 
|  | void | 
|  | _initialize_ser_socket () | 
|  | { | 
|  | serial_add_interface (&uds_ops); | 
|  | } |