From patchwork Tue Sep 12 16:27:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 75777 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0EF133856261 for ; Tue, 12 Sep 2023 16:28:55 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0EF133856261 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1694536135; bh=7jJg8GAQwPKI5U1qWViM5l3W9uVk2ufWkXyl67SOcO0=; h=Date:Subject:References:In-Reply-To:To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=SbHB8YlBA6PJgIR8GE9vUZnVXiKBsGELrtbXGuduL9iadikrpzZW/xamIDdfxZ49f ACA5iHfB8tgIFhPc97koXUUOiGHoBU1msLQV1n54KUdn3SGZZjJkNNyUM8duVYJ+PP rITabF7hnt4WAb84SMXIZ6he529tK6dcpCixuFBM= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-oi1-x229.google.com (mail-oi1-x229.google.com [IPv6:2607:f8b0:4864:20::229]) by sourceware.org (Postfix) with ESMTPS id AD7403858404 for ; Tue, 12 Sep 2023 16:27:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AD7403858404 Received: by mail-oi1-x229.google.com with SMTP id 5614622812f47-3aa14d8641cso4339192b6e.3 for ; Tue, 12 Sep 2023 09:27:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694536073; x=1695140873; h=to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7jJg8GAQwPKI5U1qWViM5l3W9uVk2ufWkXyl67SOcO0=; b=DWH7VKFkYxbMdSuSnmW6BvjyFZn7yDaFZQjk5olzjtYAq1j7ha8rT4Etk7hKBi5Rlu H38lmP0G355YHr1Kf99sdw+tHZho4nUBYvrKWYVlVwBJ/HuIoKMb1sEnvdIpWjOJlCJO fbKzPtQroa5qU+AhGug++fbl/4P8tmEcVgNtmyVGDKwVw4g+EMGDsl+JZogEZLYW1cj1 ErG97c4I2Xp+BWIlMaOIjFCTNaSsXRtwwVwKttbNvv9R6E5VhvwAzO39UTO3RJMZRVb7 aLf14MYGskWR3EWNeCXZRKmBhvOMDhWq9UZPZjnnaXH7lnk9PVThp96MdxL6wXqdhCtV kCGg== X-Gm-Message-State: AOJu0YxTY1OQ51QsYobvIg19tnYxQ1qTn6+kgBeIbAb3jiBBEAoaVbzB gN4nMe5aEyLzmmzS6IHjwD6P+MRVHTy2MrnHso3pcg== X-Google-Smtp-Source: AGHT+IFHgLwFEawTWRvCemltlLHoZrCqAOmbqAzOp4kFtWhLG6+i6zPAE/medE1lJtAyIZ/kAO+qHA== X-Received: by 2002:a05:6871:8a6:b0:1c0:fe16:90f9 with SMTP id r38-20020a05687108a600b001c0fe1690f9mr15323548oaq.51.1694536072897; Tue, 12 Sep 2023 09:27:52 -0700 (PDT) Received: from localhost.localdomain (71-211-130-31.hlrn.qwest.net. [71.211.130.31]) by smtp.gmail.com with ESMTPSA id l1-20020a02cd81000000b0042b91ec7e31sm2872324jap.3.2023.09.12.09.27.52 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Sep 2023 09:27:52 -0700 (PDT) Date: Tue, 12 Sep 2023 10:27:51 -0600 Subject: [PATCH 4/6] Change serial "open" functions to throw exception MIME-Version: 1.0 Message-Id: <20230912-serial-exceptions-v1-4-af5097485390@adacore.com> References: <20230912-serial-exceptions-v1-0-af5097485390@adacore.com> In-Reply-To: <20230912-serial-exceptions-v1-0-af5097485390@adacore.com> To: gdb-patches@sourceware.org X-Mailer: b4 0.12.3 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Tom Tromey via Gdb-patches From: Tom Tromey Reply-To: Tom Tromey Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" remote.c assumes that a failure to open the serial connection will set errno. This is somewhat true, because the Windows code tries to set errno appropriately -- but only somewhat, because it isn't clear that the "pex" code sets it, and the tcp code seems to do the wrong thing. It seems better to simply have the serial open functions throw on error. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30770 --- gdb/remote.c | 2 -- gdb/ser-event.c | 4 +-- gdb/ser-mingw.c | 47 ++++++++++++---------------------- gdb/ser-pipe.c | 12 ++++----- gdb/ser-tcp.c | 79 ++++++++++++++++++++++++++++++--------------------------- gdb/ser-tcp.h | 2 +- gdb/ser-uds.c | 26 ++++++++----------- gdb/ser-unix.c | 7 ++--- gdb/serial.c | 32 ++++++++--------------- gdb/serial.h | 2 +- 10 files changed, 90 insertions(+), 123 deletions(-) diff --git a/gdb/remote.c b/gdb/remote.c index 9346ae8b3a1..646f869ef3a 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -5954,8 +5954,6 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p) rs->wait_forever_enabled_p = true; rs->remote_desc = remote_serial_open (name); - if (!rs->remote_desc) - perror_with_name (name); if (baud_rate != -1) { diff --git a/gdb/ser-event.c b/gdb/ser-event.c index 5865e847bb5..fb02327492a 100644 --- a/gdb/ser-event.c +++ b/gdb/ser-event.c @@ -48,7 +48,7 @@ struct serial_event_state /* Open a new serial event. */ -static int +static void serial_event_open (struct serial *scb, const char *name) { struct serial_event_state *state; @@ -85,8 +85,6 @@ serial_event_open (struct serial *scb, const char *name) scb->fd = _open_osfhandle ((intptr_t) dummy_file, 0); } #endif - - return 0; } static void diff --git a/gdb/ser-mingw.c b/gdb/ser-mingw.c index 65ee1697331..30d908576da 100644 --- a/gdb/ser-mingw.c +++ b/gdb/ser-mingw.c @@ -48,7 +48,7 @@ static CancelIo_ftype *CancelIo; /* Open up a real live device for serial I/O. */ -static int +static void ser_windows_open (struct serial *scb, const char *name) { HANDLE h; @@ -59,22 +59,18 @@ ser_windows_open (struct serial *scb, const char *name) OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (h == INVALID_HANDLE_VALUE) { - errno = ENOENT; - return -1; + std::string msg = string_printf(_("could not open file: %s"), + name); + throw_winerror_with_name (msg.c_str (), GetLastError ()); } scb->fd = _open_osfhandle ((intptr_t) h, O_RDWR); if (scb->fd < 0) - { - errno = ENOENT; - return -1; - } + error (_("could not get underlying file descriptor")); if (!SetCommMask (h, EV_RXCHAR)) - { - errno = EINVAL; - return -1; - } + throw_winerror_with_name (_("error calling SetCommMask"), + GetLastError ()); timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutConstant = 0; @@ -82,10 +78,8 @@ ser_windows_open (struct serial *scb, const char *name) timeouts.WriteTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; if (!SetCommTimeouts (h, &timeouts)) - { - errno = EINVAL; - return -1; - } + throw_winerror_with_name (_("error calling SetCommTimeouts"), + GetLastError ()); state = XCNEW (struct ser_windows_state); scb->state = state; @@ -95,8 +89,6 @@ ser_windows_open (struct serial *scb, const char *name) /* Create a (currently unused) handle to record exceptions. */ state->except_event = CreateEvent (0, TRUE, FALSE, 0); - - return 0; } /* Wait for the output to drain away, as opposed to flushing (discarding) @@ -860,7 +852,7 @@ struct pipe_state_destroyer typedef std::unique_ptr pipe_state_up; -static int +static void pipe_windows_open (struct serial *scb, const char *name) { FILE *pex_stderr; @@ -883,10 +875,10 @@ pipe_windows_open (struct serial *scb, const char *name) ps->pex = pex_init (PEX_USE_PIPES, "target remote pipe", NULL); if (! ps->pex) - return -1; + error (_("could not start pipeline")); ps->input = pex_input_pipe (ps->pex, 1); if (! ps->input) - return -1; + error (_("could not find input pipe")); { int err; @@ -913,17 +905,15 @@ pipe_windows_open (struct serial *scb, const char *name) ps->output = pex_read_output (ps->pex, 1); if (! ps->output) - return -1; + error (_("could not find output pipe")); scb->fd = fileno (ps->output); pex_stderr = pex_read_err (ps->pex, 1); if (! pex_stderr) - return -1; + error (_("could not find error pipe")); scb->error_fd = fileno (pex_stderr); scb->state = ps.release (); - - return 0; } static int @@ -1191,15 +1181,12 @@ net_windows_done_wait_handle (struct serial *scb) stop_select_thread (&state->base); } -static int +static void net_windows_open (struct serial *scb, const char *name) { struct net_windows_state *state; - int ret; - ret = net_open (scb, name); - if (ret != 0) - return ret; + net_open (scb, name); state = XCNEW (struct net_windows_state); scb->state = state; @@ -1210,8 +1197,6 @@ net_windows_open (struct serial *scb, const char *name) /* Start the thread. */ create_select_thread (net_windows_select_thread, scb, &state->base); - - return 0; } diff --git a/gdb/ser-pipe.c b/gdb/ser-pipe.c index 47ccd33cece..7bdaaa071dc 100644 --- a/gdb/ser-pipe.c +++ b/gdb/ser-pipe.c @@ -34,7 +34,6 @@ #include -static int pipe_open (struct serial *scb, const char *name); static void pipe_close (struct serial *scb); struct pipe_state @@ -44,7 +43,7 @@ struct pipe_state /* Open up a raw pipe. */ -static int +static void pipe_open (struct serial *scb, const char *name) { #if !HAVE_SOCKETPAIR @@ -69,12 +68,13 @@ pipe_open (struct serial *scb, const char *name) } if (gdb_socketpair_cloexec (AF_UNIX, SOCK_STREAM, 0, pdes) < 0) - return -1; + perror_with_name (_("could not open socket pair")); if (gdb_socketpair_cloexec (AF_UNIX, SOCK_STREAM, 0, err_pdes) < 0) { + int save = errno; close (pdes[0]); close (pdes[1]); - return -1; + perror_with_name (_("could not open socket pair"), save); } /* Create the child process to run the command in. Note that the @@ -86,11 +86,12 @@ pipe_open (struct serial *scb, const char *name) /* Error. */ if (pid == -1) { + int save = errno; close (pdes[0]); close (pdes[1]); close (err_pdes[0]); close (err_pdes[1]); - return -1; + perror_with_name (_("could not vfork"), save); } if (fcntl (err_pdes[0], F_SETFL, O_NONBLOCK) == -1) @@ -148,7 +149,6 @@ pipe_open (struct serial *scb, const char *name) /* If we don't do this, GDB simply exits when the remote side dies. */ signal (SIGPIPE, SIG_IGN); - return 0; #endif } diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c index 6083bd61e62..75ea4c80051 100644 --- a/gdb/ser-tcp.c +++ b/gdb/ser-tcp.c @@ -84,11 +84,11 @@ static unsigned int tcp_retry_limit = 15; /* Helper function to wait a while. If SOCK is not -1, wait on its file descriptor. Otherwise just wait on a timeout, updating - *POLLS. Returns -1 on timeout or interrupt, otherwise the value of - select. */ + *POLLS. Returns -1 on timeout or interrupt and set OUT_ERROR, + otherwise the value of select. */ static int -wait_for_connect (int sock, unsigned int *polls) +wait_for_connect (int sock, unsigned int *polls, ULONGEST *out_error) { struct timeval t; int n; @@ -98,14 +98,14 @@ wait_for_connect (int sock, unsigned int *polls) interrupt. */ if (deprecated_ui_loop_hook && deprecated_ui_loop_hook (0)) { - errno = EINTR; + *out_error = EINTR; return -1; } /* Check for timeout. */ if (*polls > tcp_retry_limit * POLL_INTERVAL) { - errno = ETIMEDOUT; + *out_error = ETIMEDOUT; return -1; } @@ -155,19 +155,34 @@ wait_for_connect (int sock, unsigned int *polls) return n; } +/* A helper to get the error number for either Windows or POSIX. */ +static ULONGEST +get_error () +{ +#ifdef USE_WIN32API + return WSAGetLastError (); +#else + return errno; +#endif +} + /* Try to connect to the host represented by AINFO. If the connection - succeeds, return its socket. Otherwise, return -1 and set ERRNO + succeeds, return its socket. Otherwise, return -1 and set OUT_ERROR accordingly. POLLS is used when 'connect' returns EINPROGRESS, and we need to invoke 'wait_for_connect' to obtain the status. */ static int -try_connect (const struct addrinfo *ainfo, unsigned int *polls) +try_connect (const struct addrinfo *ainfo, unsigned int *polls, + ULONGEST *out_error) { int sock = gdb_socket_cloexec (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); if (sock < 0) - return -1; + { + *out_error = get_error (); + return -1; + } /* Set socket nonblocking. */ #ifdef USE_WIN32API @@ -182,11 +197,7 @@ try_connect (const struct addrinfo *ainfo, unsigned int *polls) already. */ if (connect (sock, ainfo->ai_addr, ainfo->ai_addrlen) < 0) { -#ifdef USE_WIN32API - int err = WSAGetLastError(); -#else - int err = errno; -#endif + ULONGEST err = get_error (); /* If we've got a "connection refused" error, just return -1. The caller will know what to do. */ @@ -199,7 +210,7 @@ try_connect (const struct addrinfo *ainfo, unsigned int *polls) ) { close (sock); - errno = err; + *out_error = err; return -1; } @@ -218,7 +229,7 @@ try_connect (const struct addrinfo *ainfo, unsigned int *polls) ) { close (sock); - errno = err; + *out_error = err; return -1; } @@ -226,17 +237,15 @@ try_connect (const struct addrinfo *ainfo, unsigned int *polls) int n; do - n = wait_for_connect (sock, polls); + n = wait_for_connect (sock, polls, out_error); while (n == 0); if (n < 0) { - int saved_errno = errno; - /* A negative value here means that we either timed out or got interrupted by the user. Just return. */ close (sock); - errno = saved_errno; + /* OUT_ERROR was set by wait_for_connect, above. */ return -1; } } @@ -253,16 +262,14 @@ try_connect (const struct addrinfo *ainfo, unsigned int *polls) if (ret < 0) { - int saved_errno = errno; - + *out_error = get_error (); close (sock); - errno = saved_errno; return -1; } else if (ret == 0 && err != 0) { + *out_error = err; close (sock); - errno = err; return -1; } @@ -272,7 +279,7 @@ try_connect (const struct addrinfo *ainfo, unsigned int *polls) /* Open a tcp socket. */ -int +void net_open (struct serial *scb, const char *name) { struct addrinfo hint; @@ -295,12 +302,7 @@ net_open (struct serial *scb, const char *name) &hint, &ainfo); if (r != 0) - { - gdb_printf (gdb_stderr, _("%s: cannot resolve name: %s\n"), - name, gai_strerror (r)); - errno = ENOENT; - return -1; - } + error (_("%s: cannot resolve name: %s\n"), name, gai_strerror (r)); scoped_free_addrinfo free_ainfo (ainfo); @@ -311,6 +313,7 @@ net_open (struct serial *scb, const char *name) 'struct addrinfo' that succeed. */ struct addrinfo *success_ainfo = NULL; unsigned int polls = 0; + ULONGEST last_error = 0; /* Assume the worst. */ scb->fd = -1; @@ -324,7 +327,7 @@ net_open (struct serial *scb, const char *name) /* Iterate over the list of possible addresses to connect to. For each, we'll try to connect and see if it succeeds. */ - int sock = try_connect (iter, &polls); + int sock = try_connect (iter, &polls, &last_error); if (sock >= 0) { @@ -336,9 +339,9 @@ net_open (struct serial *scb, const char *name) } else if ( #ifdef USE_WIN32API - errno == WSAECONNREFUSED + last_error == WSAECONNREFUSED #else - errno == ECONNREFUSED + last_error == ECONNREFUSED #endif ) got_connrefused = true; @@ -353,12 +356,16 @@ net_open (struct serial *scb, const char *name) while (tcp_auto_retry && success_ainfo == NULL && got_connrefused - && wait_for_connect (-1, &polls) >= 0); + && wait_for_connect (-1, &polls, &last_error) >= 0); if (success_ainfo == NULL) { net_close (scb); - return -1; +#ifdef USE_WIN32API + throw_winerror_with_name (_("could not connect"), last_error); +#else + perror_with_name (_("could not connect"), last_error); +#endif } /* Turn off nonblocking. */ @@ -384,8 +391,6 @@ net_open (struct serial *scb, const char *name) when the remote side dies. */ signal (SIGPIPE, SIG_IGN); #endif - - return 0; } void diff --git a/gdb/ser-tcp.h b/gdb/ser-tcp.h index aeb4de04a3b..444d77c0b74 100644 --- a/gdb/ser-tcp.h +++ b/gdb/ser-tcp.h @@ -22,7 +22,7 @@ struct serial; -extern int net_open (struct serial *scb, const char *name); +extern void net_open (struct serial *scb, const char *name); extern void net_close (struct serial *scb); extern int net_read_prim (struct serial *scb, size_t count); extern int net_write_prim (struct serial *scb, const void *buf, size_t count); diff --git a/gdb/ser-uds.c b/gdb/ser-uds.c index 665aab912da..e51058b534c 100644 --- a/gdb/ser-uds.c +++ b/gdb/ser-uds.c @@ -30,36 +30,30 @@ /* Open an AF_UNIX socket. */ -static int +static void uds_open (struct serial *scb, const char *name) { struct sockaddr_un addr; if (strlen (name) > UNIX_PATH_MAX - 1) - { - warning - (_("The socket name is too long. It may be no longer than %s bytes."), - pulongest (UNIX_PATH_MAX - 1L)); - return -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); - int sock = socket (AF_UNIX, SOCK_STREAM, 0); + scb->fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (scb->fd < 0) + perror_with_name (_("could not open socket")); - if (connect (sock, (struct sockaddr *) &addr, + if (connect (scb->fd, (struct sockaddr *) &addr, sizeof (struct sockaddr_un)) < 0) { - close (sock); - scb->fd = -1; - return -1; + int saved = errno; + close (scb->fd); + perror_with_name (_("could not connect to remote"), saved); } - - scb->fd = sock; - - return 0; } static void diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index 5bd15985d8c..020b41e563d 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -50,7 +50,6 @@ show_serial_hwflow (struct ui_file *file, int from_tty, } #endif -static int hardwire_open (struct serial *scb, const char *name); static void hardwire_raw (struct serial *scb); static int rate_to_code (int rate); static void hardwire_setbaudrate (struct serial *scb, int rate); @@ -72,14 +71,12 @@ static int hardwire_setstopbits (struct serial *, int); /* Open up a real live device for serial I/O. */ -static int +static void hardwire_open (struct serial *scb, const char *name) { scb->fd = gdb_open_cloexec (name, O_RDWR, 0).release (); if (scb->fd < 0) - return -1; - - return 0; + perror_with_name ("could not open device"); } static int diff --git a/gdb/serial.c b/gdb/serial.c index 122ab0bd10e..720af1a356d 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -173,12 +173,10 @@ serial_for_fd (int fd) /* Create a new serial for OPS. */ -static struct serial * +static gdb::unique_xmalloc_ptr new_serial (const struct serial_ops *ops) { - struct serial *scb; - - scb = XCNEW (struct serial); + gdb::unique_xmalloc_ptr scb (XCNEW (struct serial)); scb->ops = ops; @@ -221,7 +219,7 @@ serial_open (const char *name) } if (!ops) - return NULL; + error (_("could not find serial handler for '%s'"), name); return serial_open_ops_1 (ops, open_name); } @@ -231,20 +229,14 @@ serial_open (const char *name) static struct serial * serial_open_ops_1 (const struct serial_ops *ops, const char *open_name) { - struct serial *scb; - - scb = new_serial (ops); + gdb::unique_xmalloc_ptr scb = new_serial (ops); /* `...->open (...)' would get expanded by the open(2) syscall macro. */ - if ((*scb->ops->open) (scb, open_name)) - { - xfree (scb); - return NULL; - } + (*scb->ops->open) (scb.get (), open_name); scb->name = open_name != NULL ? xstrdup (open_name) : NULL; scb->next = scb_base; - scb_base = scb; + scb_base = scb.get (); if (!serial_logfile.empty ()) { @@ -256,7 +248,7 @@ serial_open_ops_1 (const struct serial_ops *ops, const char *open_name) serial_logfp = file.release (); } - return scb; + return scb.release (); } /* See serial.h. */ @@ -273,8 +265,6 @@ serial_open_ops (const struct serial_ops *ops) static struct serial * serial_fdopen_ops (const int fd, const struct serial_ops *ops) { - struct serial *scb; - if (!ops) { ops = serial_interface_lookup ("terminal"); @@ -285,18 +275,18 @@ serial_fdopen_ops (const int fd, const struct serial_ops *ops) if (!ops) return NULL; - scb = new_serial (ops); + gdb::unique_xmalloc_ptr scb = new_serial (ops); scb->name = NULL; scb->next = scb_base; - scb_base = scb; + scb_base = scb.get (); if ((ops->fdopen) != NULL) - (*ops->fdopen) (scb, fd); + (*ops->fdopen) (scb.get (), fd); else scb->fd = fd; - return scb; + return scb.release (); } struct serial * diff --git a/gdb/serial.h b/gdb/serial.h index 9a51fdf7816..9ae7f4f13f1 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -259,7 +259,7 @@ struct serial struct serial_ops { const char *name; - int (*open) (struct serial *, const char *name); + void (*open) (struct serial *, const char *name); void (*close) (struct serial *); int (*fdopen) (struct serial *, int fd); int (*readchar) (struct serial *, int timeout);