aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMr. Goblin <mrgoblin@mrgoblin.net>2026-10-02 22:47:33 +0300
committerMr. Goblin <mrgoblin@mrgoblin.net>2026-10-02 22:47:33 +0300
commitb6db5f69f96501aaa21e7aa9c4b6ba40548956f9 (patch)
tree53fb9ca8d136f3ad3e6bb043fc0ef44cf383d3b8
parentec49f04faa8a4f643eb8bb4a8c75ac2bff92a8f8 (diff)
logger library and flag to run as daemon
-rw-r--r--Makefile23
-rw-r--r--README28
-rw-r--r--btasktd.16
-rw-r--r--btasktd.c96
-rw-r--r--lib/logger/Makefile54
-rw-r--r--lib/logger/logger.c78
-rw-r--r--lib/logger/logger.h21
7 files changed, 280 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index f4ec5b6..21e82a8 100644
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,11 @@
#
# SPDX-License-Identifier: BSD-2-Clause
+# all 3 values commented, using make's default or export CC
# CC = cc -fno-caret-diagnostics -fno-color-diagnostics
-CC = gcc -fno-diagnostics-show-caret -fdiagnostics-color=never
+# CC = gcc -fno-diagnostics-show-caret -fdiagnostics-color=never
# CC = gcc
+
CFLAGS = -Wall -Wextra -pedantic -std=c99
# DEBUG = -g
@@ -36,17 +38,24 @@ dist:
bzip2 > $(DIST_NAME).tar.bz2
clean:
- rm -f $(MAINBINARIES) *.o *.test tags
+ $(MAKE) -C $(LIBSDIR)/logger clean
+ rm -f $(MAINBINARIES) *.o *.test tags $(DIST_NAME)
rebuild: clean all
.c.o:
- $(CC) $(DEBUG) $(CFLAGS) -c $< -o $@
+ $(CC) $(DEBUG) $(CFLAGS) -I$(LIBSDIR) -c $< -o $@
+
+LIBSDIR = ./lib
+LDFLAGS = -L$(LIBSDIR)/logger
+$(LIBSDIR)/logger/liblogger.a:
+ $(MAKE) -C $(LIBSDIR)/logger
BTASKTD_OBJECTS = btasktd.o cliflags.o codes.o
-BTASKTD_LIBS = -lc
+BTASKTD_LIBDEPS = $(LIBSDIR)/logger/liblogger.a
+BTASKTD_LIBS = -lc -llogger
-btasktd: $(BTASKTD_OBJECTS)
- $(CC) $(DEBUG) $(CFLAGS) $(STATIC) $(BTASKTD_OBJECTS) -o $@ \
- $(BTASKTD_LIBS)
+btasktd: $(BTASKTD_OBJECTS) $(BTASKTD_LIBDEPS)
+ $(CC) $(DEBUG) $(CFLAGS) $(STATIC) $(LDFLAGS) \
+ $(BTASKTD_OBJECTS) -o $@ $(BTASKTD_LIBS)
diff --git a/README b/README
index fe86d3c..d3a0710 100644
--- a/README
+++ b/README
@@ -19,3 +19,31 @@ BUILD DEPENDENCIES
RUNTIME DEPENDENCIES
-------------------------------------------------------------------------
* OS Kernel
+
+-------------------------------------------------------------------------
+QUICK START
+-------------------------------------------------------------------------
+There is no even MVP yet, just an echo server.
+
+Try:
+
+ $ make
+ $ ./btasktd -u 2 -p 5500 -b
+
+Then:
+
+ $ telnet 127.0.0.1 5500
+
+If can open two more terminals, in them also:
+
+ $ telnet 127.0.0.1 5500
+
+There should be error response for last and working echo server for
+2 others. To stop:
+
+ $ pkill -2 btasktd
+
+To allow more users change ``2'' after ``-u'' to other number, to
+change port change ``5500'' to your port.
+
+For more info please read the program's man page.
diff --git a/btasktd.1 b/btasktd.1
index d7ee07c..1287e62 100644
--- a/btasktd.1
+++ b/btasktd.1
@@ -1,4 +1,4 @@
-.Dd September 19, 2026
+.Dd October 1, 2026
.Dt BTASKTD 1
.Os
.
@@ -9,7 +9,7 @@
.Sh SYNOPSIS
.Nm
.BK -words
-.Op Fl \&Vh
+.Op Fl \&Vhb
.Op Fl p Ar port
.Op Fl u Ar users
.Ek
@@ -24,6 +24,8 @@ The options are as follows:
Show version
.It Fl h
Show help message
+.It Fl b
+Run server as daemon (in background)
.It Fl p Ar port
Set port for server to listen to
.It Fl u Ar users
diff --git a/btasktd.c b/btasktd.c
index b8b9fd9..388d655 100644
--- a/btasktd.c
+++ b/btasktd.c
@@ -40,13 +40,14 @@
#include <unistd.h>
#include <errno.h>
#include <signal.h>
+#include <logger/logger.h>
#include "cliflags.h"
#include "codes.h"
#define BTASKTD_HELP_STR \
"Copyright (c) 2026, Mr. Goblin\n" \
"btasktd - task tracking TCP-server\n" \
- "Usage: btasktd [-Vh] [-p port] [-u users]\n" \
+ "Usage: btasktd [-Vhb] [-p port] [-u users]\n" \
"For more info read the program's man page\n"
#define BTASKTD_VERSION_STR \
@@ -132,7 +133,7 @@ send_to_client(int fd, const char *s)
int len = strlen(s);
int code = send(fd, s, len, 0);
if (-1 == code)
- perror("send");
+ logger_perror("send");
}
static void
@@ -162,16 +163,21 @@ handle_accept(struct btasktd *this)
socklen_t addrlen = sizeof(user_addr);
int fd = accept(this->fd, (struct sockaddr*)&user_addr, &addrlen);
if (-1 == fd) {
- perror("accept");
+ logger_perror("accept");
return;
}
set_nonblock(fd);
idx = find_free_user(this->users, this->users_cnt);
if (-1 == idx) {
+ logger_log(log_lvl_warning,
+ "rejected user connection because "
+ "working at users limit\n");
send_response_code(fd, CODE_503_SERVICE_UNAVAILABLE);
close(fd);
return;
}
+ logger_log(log_lvl_info,
+ "new connection successfully accepted\n");
this->users[idx].fd = fd;
this->users[idx].bi = 0;
}
@@ -217,7 +223,7 @@ handle_user(struct btasktd *this, int id)
reset_user(pu);
return;
} else if (-1 == valread) {
- perror("recv");
+ logger_perror("recv");
close(pu->fd);
reset_user(pu);
return;
@@ -239,22 +245,54 @@ bye_all_clients(struct btasktd *this)
}
}
-static volatile int last_sig = 0;
+static volatile sig_atomic_t last_sig = 0;
static void
handle_sigint(int sig)
{
signal(sig, handle_sigint);
- fprintf(stderr, "Caught signal %d, shutting down...\n", sig);
+ logger_log(log_lvl_info,
+ "Caught signal %d, shutting down...\n", sig);
last_sig = SIGINT;
}
+static void
+make_me_daemon(void)
+{
+ int fd = open("/dev/null", O_RDWR), pid;
+ if (fd < 0) {
+ logger_perror("open");
+ exit(1);
+ }
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ chdir("/");
+ if (fd > 2)
+ close(fd);
+ pid = fork();
+ if (pid < 0) {
+ logger_perror("fork");
+ exit(1);
+ } else if (pid > 0) {
+ exit(0);
+ }
+ setsid();
+ pid = fork();
+ if (pid < 0) {
+ logger_perror("fork");
+ exit(1);
+ } else if (pid > 0) {
+ exit(0);
+ }
+}
+
int
main(int argc, char **argv)
{
struct btasktd server;
int server_fd, opt = 1, res, port, passed_flags = 1, users_cnt;
- int max_fd;
+ int is_daemon = 0, max_fd;
struct user *users = NULL;
int i;
struct sockaddr_in addr = {0};
@@ -262,6 +300,7 @@ main(int argc, char **argv)
struct bool_flag_val bool_res;
fd_set readfds;
+
bool_res = extract_bool_flag('V', argc, argv);
if (fvr_ok == bool_res.code && bool_res.data) {
printf("btasktd version %s\n", BTASKTD_VERSION_STR);
@@ -274,6 +313,13 @@ main(int argc, char **argv)
return 0;
}
+ bool_res = extract_bool_flag('b', argc, argv);
+ if (fvr_ok == bool_res.code && bool_res.data) {
+ is_daemon = 1;
+ }
+
+ logger_init("btasktd", is_daemon);
+
int_res = extract_int_flag('p', argc, argv);
switch (int_res.code) {
case fvr_not_found:
@@ -301,7 +347,8 @@ main(int argc, char **argv)
# ifdef BTASKTD_DEFAULT_USERS_CNT
users_cnt = BTASKTD_DEFAULT_USERS_CNT;
# else
- fprintf(stderr, "No users count specified!\n");
+ fprintf(stderr,
+ "No users count specified!\n");
passed_flags = 0;
# endif
break;
@@ -313,18 +360,23 @@ main(int argc, char **argv)
case fvr_invalid:
fprintf(stderr, "Invalid users count!\n");
return 1;
- break;
}
+ logger_init("btasktd", is_daemon);
+
if (!passed_flags) {
+ logger_log(log_lvl_err,
+ "FATAL: didn't passed flags check\n");
fprintf(stderr, "-\n");
fprint_help(stderr);
+ logger_close();
return 1;
}
users = (struct user*)calloc(users_cnt, sizeof(struct user));
if (NULL == users) {
- fprintf(stderr, "No memory!\n");
+ logger_log(log_lvl_err, "No memory!\n");
+ logger_close();
return 1;
}
for (i = 0; i < users_cnt; i++) {
@@ -333,8 +385,9 @@ main(int argc, char **argv)
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
+ logger_perror("socket");
free(users);
- perror("socket");
+ logger_close();
return 1;
}
addr.sin_family = AF_INET;
@@ -345,21 +398,24 @@ main(int argc, char **argv)
if (0 != res) {
close(server_fd);
free(users);
- perror("setsockopt");
+ logger_perror("setsockopt");
+ logger_close();
return 1;
}
res = bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
if (0 != res) {
close(server_fd);
free(users);
- perror("bind");
+ logger_perror("bind");
+ logger_close();
return 1;
}
res = listen(server_fd, BTASKTD_QUEUE_LEN);
if (0 != res) {
close(server_fd);
free(users);
- perror("listen");
+ logger_perror("listen");
+ logger_close();
return 1;
}
@@ -368,7 +424,12 @@ main(int argc, char **argv)
server.fd = server_fd;
server.users_cnt = users_cnt;
server.users = users;
- printf("btaskt server btasktd started on port %d\n", port);
+
+ if (is_daemon)
+ make_me_daemon();
+ logger_log(log_lvl_info,
+ "btaskt server btasktd started on port %d. pid - %d\n",
+ port, getpid());
signal(SIGINT, handle_sigint);
@@ -393,7 +454,7 @@ main(int argc, char **argv)
break;
}
} else {
- perror("select");
+ logger_perror("select");
}
continue;
} else if (0 == res) {
@@ -410,7 +471,8 @@ main(int argc, char **argv)
}
}
- printf("btaskt server btasktd stopped\n");
+ logger_log(log_lvl_info, "btaskt server btasktd stopped\n");
+ logger_close();
close(server_fd);
free(users);
return 0;
diff --git a/lib/logger/Makefile b/lib/logger/Makefile
new file mode 100644
index 0000000..e5e7682
--- /dev/null
+++ b/lib/logger/Makefile
@@ -0,0 +1,54 @@
+# Copyright (c) 2026, Mr. Goblin
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+# all 3 values commented, using make's default or export CC
+# CC = cc -fno-caret-diagnostics -fno-color-diagnostics
+# CC = gcc -fno-diagnostics-show-caret -fdiagnostics-color=never
+# CC = gcc
+
+CFLAGS = -Wall -Wextra -pedantic -std=gnu89
+ARFLAGS = rcs
+
+# DEBUG = -g
+# DEBUG = -ggdb
+DEBUG =
+
+# STATIC = -static
+STATIC = -static -s
+# STATIC =
+
+PROG_NAME=liblogger
+VER=0.0.0
+DIST_NAME=$(PROG_NAME)-$(VER)
+
+
+MAINBINARIES = liblogger.a
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.PHONY: all clean dist ctags rebuild
+
+all: $(MAINBINARIES)
+
+ctags:
+ ctags *.c *.h *.cpp *.hpp
+
+dist:
+ git archive --format=tar --prefix=$(DIST_NAME)/ HEAD | \
+ bzip2 > $(DIST_NAME).tar.bz2
+
+clean:
+ rm -f $(MAINBINARIES) *.o *.test tags $(DIST_NAME)
+
+rebuild: clean all
+
+.c.o:
+ $(CC) $(DEBUG) $(CFLAGS) -c $< -o $@
+
+
+LIBLOGGER_OBJECTS = logger.o
+LIBLOGGER_LIBS = -lc
+
+liblogger.a: $(LIBLOGGER_OBJECTS)
+ $(AR) $(ARFLAGS) $@ $(LIBLOGGER_OBJECTS)
diff --git a/lib/logger/logger.c b/lib/logger/logger.c
new file mode 100644
index 0000000..64a6754
--- /dev/null
+++ b/lib/logger/logger.c
@@ -0,0 +1,78 @@
+#include <syslog.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "logger.h"
+
+static int use_syslog = 0;
+
+void
+logger_init(const char *name, int daemon_flag)
+{
+ use_syslog = daemon_flag;
+ if (use_syslog)
+ openlog(name, LOG_PID, LOG_DAEMON);
+}
+
+void
+logger_close(void)
+{
+ if (use_syslog)
+ closelog();
+}
+
+void
+logger_log(enum logger_lvl level, const char *format, ...)
+{
+ int saved_errno = errno;
+ va_list vargs;
+ va_start(vargs, format);
+ if (use_syslog) {
+ switch (level) {
+ case log_lvl_info:
+ vsyslog(LOG_INFO, format, vargs);
+ break;
+ case log_lvl_warning:
+ vsyslog(LOG_WARNING, format, vargs);
+ break;
+ case log_lvl_err:
+ vsyslog(LOG_ERR, format, vargs);
+ break;
+ }
+ } else {
+ FILE *f = NULL;
+ switch (level) {
+ case log_lvl_info:
+ f = stdout;
+ fprintf(f, "[INFO] ");
+ break;
+ case log_lvl_warning:
+ f = stderr;
+ fprintf(f, "[WARNING] ");
+ break;
+ case log_lvl_err:
+ f = stderr;
+ fprintf(f, "[ERROR] ");
+ break;
+ default:
+ f = stderr;
+ fprintf(f, "[UNKNOWN] ");
+ break;
+ }
+ vfprintf(f, format, vargs);
+ }
+ errno = saved_errno;
+}
+
+void
+logger_perror(const char *s)
+{
+ int saved_errno = errno;
+ if (use_syslog) {
+ syslog(LOG_ERR, "%s: %s\n", s, strerror(errno));
+ } else {
+ perror(s);
+ }
+ errno = saved_errno;
+}
diff --git a/lib/logger/logger.h b/lib/logger/logger.h
new file mode 100644
index 0000000..6c9ed7d
--- /dev/null
+++ b/lib/logger/logger.h
@@ -0,0 +1,21 @@
+#ifndef LIB_LOGGER_H_SENTRY
+#define LIB_LOGGER_H_SENTRY
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum logger_lvl {
+ log_lvl_info,
+ log_lvl_warning,
+ log_lvl_err
+};
+
+void logger_init(const char *name, int daemon_flag);
+void logger_close(void);
+void logger_log(enum logger_lvl, const char *format, ...);
+void logger_perror(const char *s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIB_LOGGER_H_SENTRY */