/* * Copyright (C) 2002-2003, 2009 Red Hat, Inc. * * License: GPLv2+ * * Written by Lon Hohberger * * Serial client for fence_virt (incomplete, but * a good start) * * Based on: * Ubersimpledumbterminal "ser" version 1.0.3 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int char_to_speed(const char *speed) { if (!speed || !strlen(speed)) return B9600; if (!strcmp(speed,"2400")) return B2400; if (!strcmp(speed,"9600")) return B9600; if (!strcmp(speed,"19200")) return B19200; if (!strcmp(speed,"38400")) return B38400; if (!strcmp(speed,"57600")) return B57600; if (!strcmp(speed,"115200")) return B115200; return -1; } static int char_to_flags(const char *param) { int db_f = CS8, par_f = 0, sb_f = 0, x; if (!param || !strlen(param)) return (db_f | par_f | sb_f); if (strlen(param) < 3) { errno = EINVAL; return -1; } for (x = 0; x < 3; x++) { switch (param[x]) { case '5': db_f = CS5; break; case '6': db_f = CS6; break; case '7': db_f = CS7; break; case '8': db_f = CS8; break; case 'n': case 'N': par_f = 0; break; case 'e': case 'E': par_f = PARENB; break; case 'o': case 'O': par_f = PARENB | PARODD; break; case '1': sb_f = 0; break; case '2': sb_f = CSTOPB; break; default: printf("Fail: %c\n", param[x]); errno = EINVAL; return -1; } } return (db_f | par_f | sb_f); } static int open_port(char *file, char *cspeed, char *cparam) { struct termios ti; int fd, speed = B115200, flags = 0; struct flock lock; if ((speed = char_to_speed(cspeed)) == -1) { errno = EINVAL; return -1; } if ((flags = char_to_flags(cparam)) == -1) { errno = EINVAL; return -1; } if ((fd = open(file, O_RDWR | O_EXCL)) == -1) { perror("open"); return -1; } memset(&lock,0,sizeof(lock)); lock.l_type = F_WRLCK; if (fcntl(fd, F_SETLK, &lock) == -1) { perror("Failed to lock serial port"); close(fd); return -1; } memset(&ti, 0, sizeof(ti)); ti.c_cflag = (speed | CLOCAL | CRTSCTS | CREAD | flags); if (tcsetattr(fd, TCSANOW, &ti) < 0) { perror("tcsetattr"); close(fd); return -1; } (void) tcflush(fd, TCIOFLUSH); return fd; } static void hangup(int fd, int delay) { unsigned int bits; if (ioctl(fd, TIOCMGET, &bits)) { perror("ioctl1"); return; } bits &= ~(TIOCM_DTR | TIOCM_CTS | TIOCM_RTS | TIOCM_DSR | TIOCM_CD); if (ioctl(fd, TIOCMSET, &bits)) { perror("ioctl2"); return; } usleep(delay); bits |= (TIOCM_DTR | TIOCM_CTS | TIOCM_RTS | TIOCM_DSR | TIOCM_CD); if (ioctl(fd, TIOCMSET, &bits)) { perror("ioctl3"); return; } } void do_read_hostlist(int fd, int timeout); int wait_for(int fd, const char *pattern, size_t size, struct timeval *tout) { char *pos = (char *)pattern; char c; int n; struct timeval tv; size_t remain = size; if (tout) { memcpy(&tv, tout, sizeof(tv)); tout = &tv; } while (remain) { n = _read_retry(fd, &c, 1, &tv); if (n < 1) return -1; if (c == *pos) { ++pos; --remain; } else { pos = (char *)pattern; remain = size; } } return 0; } int serial_fence_virt(fence_virt_args_t *args) { struct in_addr ina; struct in6_addr in6a; serial_req_t req; int fd, ret; char speed[32], *flags = NULL; struct timeval tv; serial_resp_t resp; if (args->serial.device) { strncpy(speed, args->serial.speed, sizeof(speed)); //printf("Port: %s Speed: %s\n", args->serial.device, speed); if ((flags = strchr(speed, ','))) { *flags = 0; flags++; } fd = open_port(args->serial.device, speed, flags); if (fd == -1) { perror("open_port"); return -1; } hangup(fd, 300000); } else { fd = -1; if (inet_pton(PF_INET, args->serial.address, &ina)) { fd = ipv4_connect(&ina, args->net.port, 3); } else if (inet_pton(PF_INET6, args->serial.address, &in6a)) { fd = ipv6_connect(&in6a, args->net.port, 3); } if (fd < 0) { perror("vmchannel connect"); printf("Failed to connect to %s:%d\n", args->serial.address, args->net.port); return -1; } } memset(&req, 0, sizeof(req)); req.magic = SERIAL_MAGIC; req.request = (uint8_t)args->op; gettimeofday(&tv, NULL); req.seqno = (int)tv.tv_usec; if (args->domain) strncpy((char *)req.domain, args->domain, sizeof(req.domain)); tv.tv_sec = 3; tv.tv_usec = 0; swab_serial_req_t(&req); ret = _write_retry(fd, &req, sizeof(req), &tv); if (ret < sizeof(req)) { if (ret < 0) { close(fd); return ret; } printf("Failed to send request\n"); } tv.tv_sec = args->timeout; tv.tv_usec = 0; resp.magic = SERIAL_MAGIC; do { if (wait_for(fd, (const char *)&resp.magic, sizeof(resp.magic), &tv) == 0) { ret = _read_retry(fd, &resp.response, sizeof(resp.response), &tv); } else { /* The other end died or closed the connection */ close(fd); return -1; } swab_serial_resp_t(&resp); } while(resp.magic != SERIAL_MAGIC && (tv.tv_sec || tv.tv_usec)); if (resp.magic != SERIAL_MAGIC) { close(fd); return -1; } ret = resp.response; if (resp.response == RESP_HOSTLIST) /* hostlist */ { /* ok read hostlist */ do_read_hostlist(fd, args->timeout); ret = 0; } close(fd); return ret; }