summaryrefslogtreecommitdiff
path: root/stacks/max25-bcpr/src/bcpr_kiss.c
diff options
context:
space:
mode:
authorinfo@mode42.com <info@mode42.com>2026-08-07 18:23:28 +0000
committerinfo@mode42.com <info@mode42.com>2026-08-07 18:23:28 +0000
commitfa05a5f8238e9e1417235711656e5062ccc843a7 (patch)
tree46fbbd18de54492b59307c16efcc7f3152723238 /stacks/max25-bcpr/src/bcpr_kiss.c
Initial push
Diffstat (limited to 'stacks/max25-bcpr/src/bcpr_kiss.c')
-rw-r--r--stacks/max25-bcpr/src/bcpr_kiss.c127
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);
+ }
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com