Fix another giant batch of resource leaks. (Mostly memory, but there's
[u/mdw/putty] / unix / uxser.c
index d647108..e45f3ae 100644 (file)
@@ -60,10 +60,10 @@ static int serial_select_result(int fd, int event);
 static void serial_uxsel_setup(Serial serial);
 static void serial_try_write(Serial serial);
 
-static const char *serial_configure(Serial serial, Config *cfg)
+static const char *serial_configure(Serial serial, Conf *conf)
 {
     struct termios options;
-    int bflag, bval;
+    int bflag, bval, speed, flow, parity;
     const char *str;
     char *msg;
 
@@ -75,8 +75,9 @@ static const char *serial_configure(Serial serial, Config *cfg)
     /*
      * Find the appropriate baud rate flag.
      */
+    speed = conf_get_int(conf, CONF_serspeed);
 #define SETBAUD(x) (bflag = B ## x, bval = x)
-#define CHECKBAUD(x) do { if (cfg->serspeed >= x) SETBAUD(x); } while (0)
+#define CHECKBAUD(x) do { if (speed >= x) SETBAUD(x); } while (0)
     SETBAUD(50);
 #ifdef B75
     CHECKBAUD(75);
@@ -129,9 +130,51 @@ static const char *serial_configure(Serial serial, Config *cfg)
 #ifdef B115200
     CHECKBAUD(115200);
 #endif
+#ifdef B153600
+    CHECKBAUD(153600);
+#endif
 #ifdef B230400
     CHECKBAUD(230400);
 #endif
+#ifdef B307200
+    CHECKBAUD(307200);
+#endif
+#ifdef B460800
+    CHECKBAUD(460800);
+#endif
+#ifdef B500000
+    CHECKBAUD(500000);
+#endif
+#ifdef B576000
+    CHECKBAUD(576000);
+#endif
+#ifdef B921600
+    CHECKBAUD(921600);
+#endif
+#ifdef B1000000
+    CHECKBAUD(1000000);
+#endif
+#ifdef B1152000
+    CHECKBAUD(1152000);
+#endif
+#ifdef B1500000
+    CHECKBAUD(1500000);
+#endif
+#ifdef B2000000
+    CHECKBAUD(2000000);
+#endif
+#ifdef B2500000
+    CHECKBAUD(2500000);
+#endif
+#ifdef B3000000
+    CHECKBAUD(3000000);
+#endif
+#ifdef B3500000
+    CHECKBAUD(3500000);
+#endif
+#ifdef B4000000
+    CHECKBAUD(4000000);
+#endif
 #undef CHECKBAUD
 #undef SETBAUD
     cfsetispeed(&options, bflag);
@@ -141,18 +184,19 @@ static const char *serial_configure(Serial serial, Config *cfg)
     sfree(msg);
 
     options.c_cflag &= ~CSIZE;
-    switch (cfg->serdatabits) {
+    switch (conf_get_int(conf, CONF_serdatabits)) {
       case 5: options.c_cflag |= CS5; break;
       case 6: options.c_cflag |= CS6; break;
       case 7: options.c_cflag |= CS7; break;
       case 8: options.c_cflag |= CS8; break;
       default: return "Invalid number of data bits (need 5, 6, 7 or 8)";
     }
-    msg = dupprintf("Configuring %d data bits", cfg->serdatabits);
+    msg = dupprintf("Configuring %d data bits",
+                   conf_get_int(conf, CONF_serdatabits));
     logevent(serial->frontend, msg);
     sfree(msg);
 
-    if (cfg->serstopbits >= 4) {
+    if (conf_get_int(conf, CONF_serstopbits) >= 4) {
        options.c_cflag |= CSTOPB;
     } else {
        options.c_cflag &= ~CSTOPB;
@@ -169,10 +213,11 @@ static const char *serial_configure(Serial serial, Config *cfg)
 #ifdef CNEW_RTSCTS
     options.c_cflag &= ~CNEW_RTSCTS;
 #endif
-    if (cfg->serflow == SER_FLOW_XONXOFF) {
+    flow = conf_get_int(conf, CONF_serflow);
+    if (flow == SER_FLOW_XONXOFF) {
        options.c_iflag |= IXON | IXOFF;
        str = "XON/XOFF";
-    } else if (cfg->serflow == SER_FLOW_RTSCTS) {
+    } else if (flow == SER_FLOW_RTSCTS) {
 #ifdef CRTSCTS
        options.c_cflag |= CRTSCTS;
 #endif
@@ -187,11 +232,12 @@ static const char *serial_configure(Serial serial, Config *cfg)
     sfree(msg);
 
     /* Parity */
-    if (cfg->serparity == SER_PAR_ODD) {
+    parity = conf_get_int(conf, CONF_serparity);
+    if (parity == SER_PAR_ODD) {
        options.c_cflag |= PARENB;
        options.c_cflag |= PARODD;
        str = "odd";
-    } else if (cfg->serparity == SER_PAR_EVEN) {
+    } else if (parity == SER_PAR_EVEN) {
        options.c_cflag |= PARENB;
        options.c_cflag &= ~PARODD;
        str = "even";
@@ -214,7 +260,16 @@ static const char *serial_configure(Serial serial, Config *cfg)
 #ifdef ONLCR
                         | ONLCR
 #endif
-                        | OCRNL | ONOCR | ONLRET);
+#ifdef OCRNL
+                        | OCRNL
+#endif
+#ifdef ONOCR
+                        | ONOCR
+#endif
+#ifdef ONLRET
+                        | ONLRET
+#endif
+                        );
     options.c_cc[VMIN] = 1;
     options.c_cc[VTIME] = 0;
 
@@ -233,12 +288,13 @@ static const char *serial_configure(Serial serial, Config *cfg)
  * freed by the caller.
  */
 static const char *serial_init(void *frontend_handle, void **backend_handle,
-                              Config *cfg,
+                              Conf *conf,
                               char *host, int port, char **realhost, int nodelay,
                               int keepalive)
 {
     Serial serial;
     const char *err;
+    char *line;
 
     serial = snew(struct serial_backend_data);
     *backend_handle = serial;
@@ -248,20 +304,24 @@ static const char *serial_init(void *frontend_handle, void **backend_handle,
     serial->inbufsize = 0;
     bufchain_init(&serial->output_data);
 
+    line = conf_get_str(conf, CONF_serline);
     {
-       char *msg = dupprintf("Opening serial device %s", cfg->serline);
+       char *msg = dupprintf("Opening serial device %s", line);
        logevent(serial->frontend, msg);
+        sfree(msg);
     }
 
-    serial->fd = open(cfg->serline, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
+    serial->fd = open(line, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
     if (serial->fd < 0)
        return "Unable to open serial port";
 
-    err = serial_configure(serial, cfg);
+    cloexec(serial->fd);
+
+    err = serial_configure(serial, conf);
     if (err)
        return err;
 
-    *realhost = dupstr(cfg->serline);
+    *realhost = dupstr(line);
 
     if (!serial_by_fd)
        serial_by_fd = newtree234(serial_compare_by_fd);
@@ -296,16 +356,14 @@ static void serial_free(void *handle)
     sfree(serial);
 }
 
-static void serial_reconfig(void *handle, Config *cfg)
+static void serial_reconfig(void *handle, Conf *conf)
 {
     Serial serial = (Serial) handle;
-    const char *err;
-
-    err = serial_configure(serial, cfg);
 
     /*
-     * FIXME: what should we do if err returns something?
+     * FIXME: what should we do if this returns an error?
      */
+    serial_configure(serial, conf);
 }
 
 static int serial_select_result(int fd, int event)
@@ -331,6 +389,14 @@ static int serial_select_result(int fd, int event)
             */
            finished = TRUE;
        } else if (ret < 0) {
+#ifdef EAGAIN
+           if (errno == EAGAIN)
+               return 1;              /* spurious */
+#endif
+#ifdef EWOULDBLOCK
+           if (errno == EWOULDBLOCK)
+               return 1;              /* spurious */
+#endif
            perror("read serial port");
            exit(1);
        } else if (ret > 0) {
@@ -525,5 +591,7 @@ Backend serial_backend = {
     serial_provide_logctx,
     serial_unthrottle,
     serial_cfg_info,
-    1
+    "serial",
+    PROT_SERIAL,
+    0
 };