diff options
Diffstat (limited to 'stacks/max25-bcpr/src/bcpr_kiss.c')
| -rw-r--r-- | stacks/max25-bcpr/src/bcpr_kiss.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/stacks/max25-bcpr/src/bcpr_kiss.c b/stacks/max25-bcpr/src/bcpr_kiss.c new file mode 100644 index 0000000..495f4d1 --- /dev/null +++ b/stacks/max25-bcpr/src/bcpr_kiss.c @@ -0,0 +1,127 @@ +/* + * KISS PTY bridge for max25-bcpr (HyBBX attach via kiss_link symlink). + */ +#define _GNU_SOURCE +#include "bcpr/bcpr_kiss.h" + +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#if defined(__linux__) +#include <pty.h> +#elif defined(__FreeBSD__) +#include <libutil.h> +#else +#include <util.h> +#endif + +static int ensure_dir(const char *path) +{ + char tmp[256]; + char *p; + size_t len; + + if (!path || !path[0]) { + return -1; + } + snprintf(tmp, sizeof(tmp), "%s", path); + len = strlen(tmp); + if (len == 0) { + return -1; + } + if (tmp[len - 1] == '/') { + tmp[len - 1] = '\0'; + } + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + (void)mkdir(tmp, 0755); + *p = '/'; + } + } + return mkdir(tmp, 0755) == 0 || errno == EEXIST ? 0 : -1; +} + +int bcpr_kiss_pty_open(bcpr_kiss_pty_t *kp, int idx, const char *link_path, + const char *state_dir) +{ + int master = -1, slave = -1; + char slave_name[128]; + char dir[128]; + const char *slash; + + memset(kp, 0, sizeof(*kp)); + kp->idx = idx; + kp->master_fd = -1; + kp->slave_fd = -1; + snprintf(kp->link_path, sizeof(kp->link_path), "%s", link_path); + + slash = strrchr(link_path, '/'); + if (slash && slash > link_path) { + size_t n = (size_t)(slash - link_path); + if (n >= sizeof(dir)) { + n = sizeof(dir) - 1; + } + memcpy(dir, link_path, n); + dir[n] = '\0'; + (void)ensure_dir(dir); + } else { + (void)ensure_dir(state_dir); + } + + if (openpty(&master, &slave, slave_name, NULL, NULL) != 0) { + perror("max25-bcpr openpty"); + return -1; + } + if (fchmod(slave, 0660) != 0) { + perror("max25-bcpr fchmod kiss slave"); + } else { + struct group *gr = getgrnam("dialout"); + if (gr == NULL) { + gr = getgrnam("uucp"); + } + if (gr == NULL) { + gr = getgrnam("tty"); + } + if (gr != NULL && fchown(slave, (uid_t)-1, gr->gr_gid) != 0) { + perror("max25-bcpr fchown kiss slave"); + } + } + unlink(link_path); + if (symlink(slave_name, link_path) != 0) { + perror("max25-bcpr symlink kiss_link"); + close(slave); + close(master); + return -1; + } + fcntl(master, F_SETFL, O_NONBLOCK); + kp->master_fd = master; + close(slave); + kp->slave_fd = -1; + fprintf(stderr, "max25-bcpr: max25e0:bc%d KISS → %s -> %s\n", idx, link_path, + slave_name); + return 0; +} + +void bcpr_kiss_pty_close(bcpr_kiss_pty_t *kp) +{ + if (!kp) { + return; + } + if (kp->slave_fd >= 0) { + close(kp->slave_fd); + kp->slave_fd = -1; + } + if (kp->master_fd >= 0) { + close(kp->master_fd); + kp->master_fd = -1; + } + if (kp->link_path[0]) { + unlink(kp->link_path); + } +} |
