summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McDermott <patrick.mcdermott@libiquity.com>2023-06-26 11:47:00 (EDT)
committer Patrick McDermott <patrick.mcdermott@libiquity.com>2023-06-26 16:47:07 (EDT)
commit2c6e02bf1b6bbd374310f458b184ab1c26717cd6 (patch)
treea8c3425606fc38520bf6fa43ef6afdcd28c2a99d
parent2622c8a1e2c1cabfd0f0c6f504325b9ae21672fa (diff)
mknod: New helper utility
-rw-r--r--Makefile.am12
-rw-r--r--helpers/local.mk1
-rw-r--r--helpers/mknod.c299
-rw-r--r--po/POTFILES.in1
4 files changed, 312 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index b7655fd..9e6d12c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,7 +40,7 @@ endif
# * Our release target
PACKAGE_STRING = $(PACKAGE_NAME) $(PACKAGE_VERSION)$(PACKAGE_VERSION_GIT)
-bin_PROGRAMS = opkg-opk
+bin_PROGRAMS = opkg-opk mknod
opkg_opk_SOURCES =
opkg_opk_CFLAGS = \
@@ -54,6 +54,15 @@ opkg_opk_LDADD = \
$(ZLIB_LIBS)
opkg_opk_LINK = $(LINK) version.c
EXTRA_opkg_opk_DEPENDENCIES = version.c
+
+mknod_CFLAGS = \
+ $(WARN_CFLAGS) \
+ $(ASAN_CFLAGS)
+mknod_CPPFLAGS = \
+ -DLOCALEDIR=\"$(localedir)\"
+mknod_LDADD = \
+ $(ASAN_CFLAGS)
+
CLEANFILES = version.c
CONFIG_CLEAN_FILES =
EXTRA_DIST = build-aux/config.rpath autogen.sh
@@ -104,6 +113,7 @@ release:
$(PACKAGE) $(VERSION) '$(PACKAGE_NAME)'
include $(top_srcdir)/src/local.mk
+include $(top_srcdir)/helpers/local.mk
include $(top_srcdir)/tests/local.mk
SUBDIRS = . po
diff --git a/helpers/local.mk b/helpers/local.mk
new file mode 100644
index 0000000..ce5ecc7
--- /dev/null
+++ b/helpers/local.mk
@@ -0,0 +1 @@
+mknod_SOURCES = %reldir%/mknod.c
diff --git a/helpers/mknod.c b/helpers/mknod.c
new file mode 100644
index 0000000..93ef974
--- /dev/null
+++ b/helpers/mknod.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2023 Patrick McDermott
+ *
+ * This file is part of opkg-opk.
+ *
+ * opkg-opk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * opkg-opk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with opkg-opk. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef ENABLE_NLS
+#include <locale.h>
+#include <libintl.h>
+#define _(msgid) gettext(msgid)
+#else
+#define _(msgid) (msgid)
+#endif
+
+#ifdef HAVE_GETOPT_LONG
+#include <getopt.h>
+#endif
+
+static const char *_OPTSTRING = "m:";
+#ifdef HAVE_GETOPT_LONG
+static const struct option _LONGOPTS[] = {
+ {
+ .name = "mode",
+ .has_arg = 1,
+ .flag = NULL,
+ .val = 'm',
+ },
+};
+#endif
+
+static const unsigned int _TIMEOUT = 10U;
+
+int
+main(int argc, char *argv[])
+{
+ char *program_name;
+ char *work_area;
+ char **exec_argv;
+ int arg;
+ mode_t mode;
+ int opt;
+ char *name;
+ char type;
+ char *end;
+ long int major;
+ long int minor;
+ char *specials_file_name;
+ char *specials_lock_name;
+ int fd;
+ unsigned int timeout;
+ int specials_fd;
+ FILE *specials_file;
+ struct stat stat_buf;
+
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset(PACKAGE, "UTF-8");
+#endif
+ textdomain(PACKAGE);
+ setlocale(LC_ALL, "");
+#endif
+
+ program_name = argv[0];
+
+ work_area = getenv("OPK_WORK_AREA");
+ if (work_area == NULL || work_area[0] == '\0') {
+ fprintf(stderr, _("%s: OPK_WORK_AREA environment variable not "
+ "set\n"), program_name);
+ fprintf(stderr, _("%s: Possibly building package dependent on "
+ "opkg-opk with opkbuild too old to use "
+ "it\n"), program_name);
+ fprintf(stderr, _("%s: Executing system mknod instead\n"),
+ program_name);
+ exec_argv = calloc(argc + 1, sizeof(*exec_argv));
+ if (exec_argv == NULL) {
+ fprintf(stderr, _("%s: Failed to allocate memory\n"),
+ program_name);
+ return EXIT_FAILURE;
+ }
+ exec_argv[0] = malloc(strlen(MKNOD) + 1);
+ if (exec_argv[0] == NULL) {
+ fprintf(stderr, _("%s: Failed to allocate memory\n"),
+ program_name);
+ free(exec_argv);
+ return EXIT_FAILURE;
+ }
+ strcpy(exec_argv[0], MKNOD);
+ for (arg = 1; arg < argc; ++arg) {
+ exec_argv[arg] = argv[arg];
+ }
+ exec_argv[argc] = NULL;
+ execve(MKNOD, exec_argv, NULL); /* Shouldn't return */
+ fprintf(stderr, _("%s: Failed to execute system mknod\n"),
+ program_name);
+ free(exec_argv[0]);
+ free(exec_argv);
+ return EXIT_FAILURE;
+ }
+
+ mode = 0;
+#ifdef HAVE_GETOPT_LONG
+ while ((opt = getopt_long(argc, argv, _OPTSTRING, _LONGOPTS, NULL))
+ != -1) {
+#else
+ while ((opt = getopt(argc, argv, _OPTSTRING)) != -1) {
+#endif
+ switch(opt) {
+ case 'm':
+ /* TODO: Parse mode. */
+ break;
+ default:
+ fprintf(stderr, _("%s: Warning: Unknown option:"
+ " \"%c\"\n"),
+ program_name, optopt);
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ fprintf(stderr, _("%s: Wrong number of operands\n"),
+ program_name);
+ return EXIT_FAILURE;
+ }
+ name = argv[0];
+ switch (argv[1][0]) {
+ case 'c':
+ case 'u':
+ type = 'c';
+ break;
+ case 'b':
+ type = 'b';
+ break;
+ case 'p':
+ if (argc != 2) {
+ fprintf(stderr, _("%s: Wrong number of "
+ "operands\n"),
+ program_name);
+ return EXIT_FAILURE;
+ }
+ if (mkfifo(name, mode) != 0) {
+ fprintf(stderr, _("%s: Failed to create link "
+ "\"%s\"\n"),
+ program_name, name);
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ default:
+ fprintf(stderr, _("%s: Invalid node type \"%c\"\n"),
+ program_name, argv[1][0]);
+ return EXIT_FAILURE;
+ }
+
+ if (argc != 4) {
+ fprintf(stderr, _("%s: Wrong number of operands\n"),
+ program_name);
+ return EXIT_FAILURE;
+ }
+ major = strtol(argv[2], &end, 10);
+ if (*end != '\0') {
+ fprintf(stderr, _("%s: Invalid number \"%s\"\n"),
+ program_name, argv[2]);
+ return EXIT_FAILURE;
+ }
+ minor = strtol(argv[3], &end, 10);
+ if (*end != '\0') {
+ fprintf(stderr, _("%s: Invalid number \"%s\"\n"),
+ program_name, argv[3]);
+ return EXIT_FAILURE;
+ }
+
+ specials_file_name = malloc(strlen(work_area) + strlen("/specials")
+ + 1 /* "\0" */);
+ if (specials_file_name == NULL) {
+ fprintf(stderr, _("%s: Failed to allocate memory\n"),
+ program_name);
+ return EXIT_FAILURE;
+ }
+ specials_lock_name = malloc(strlen(work_area) + strlen("/specials~")
+ + 1 /* "\0" */);
+ if (specials_lock_name == NULL) {
+ fprintf(stderr, _("%s: Failed to allocate memory\n"),
+ program_name);
+ free(specials_file_name);
+ return EXIT_FAILURE;
+ }
+ sprintf(specials_file_name, "%s/specials", work_area);
+ sprintf(specials_lock_name, "%s/specials~", work_area);
+
+ /* Create the named node. This should be done before appending to the
+ * specials file, in case a file by the specified name already exists.
+ */
+ fd = open(name, O_CREAT | O_EXCL, mode);
+ if (fd < 0 || close(fd) < 0) {
+ fprintf(stderr, _("%s: Failed to create node\n"), program_name);
+ free(specials_file_name);
+ free(specials_lock_name);
+ return EXIT_FAILURE;
+ }
+
+ /* Acquire lock ("specials~"). */
+ for (timeout = _TIMEOUT; timeout > 0; --timeout) {
+ specials_fd = open(specials_lock_name, O_CREAT | O_EXCL, 0644);
+ if (specials_fd >= 0) {
+ goto opened;
+ }
+ }
+ fprintf(stderr, _("%s: Failed to lock specials file\n"), program_name);
+ free(specials_file_name);
+ free(specials_lock_name);
+ unlink(name);
+ return EXIT_FAILURE;
+
+ opened:
+ specials_file = fdopen(specials_fd, "a");
+ if (specials_file == NULL) {
+ fprintf(stderr, _("%s: Failed to open specials file stream\n"),
+ program_name);
+ close(specials_fd);
+ free(specials_file_name);
+ free(specials_lock_name);
+ unlink(name);
+ return EXIT_FAILURE;
+ }
+
+ /* If "specials" doesn't exist, write header. */
+ if (stat(specials_file_name, &stat_buf) != 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, _("%s: Failed to stat specials file\n"),
+ program_name);
+ fclose(specials_file);
+ free(specials_file_name);
+ free(specials_lock_name);
+ unlink(name);
+ return EXIT_FAILURE;
+ }
+ if (fputs("version=1\n", specials_file) < 0 ||
+ fputs("type major minor name\n",
+ specials_file) < 0) {
+ fprintf(stderr, _("%s: Failed to write specials file\n")
+ , program_name);
+ fclose(specials_file);
+ free(specials_file_name);
+ free(specials_lock_name);
+ unlink(name);
+ return EXIT_FAILURE;
+ }
+ }
+ if (fprintf(specials_file, "%c %8ld %8ld %s\n", type, major, minor,
+ name) < 0) {
+ fprintf(stderr, _("%s: Failed to write specials file\n"),
+ program_name);
+ fclose(specials_file);
+ free(specials_file_name);
+ free(specials_lock_name);
+ unlink(name);
+ return EXIT_FAILURE;
+ }
+ fclose(specials_file);
+
+ if (rename(specials_lock_name, specials_file_name) != 0) {
+ fprintf(stderr, _("%s: Failed to move specials file\n"),
+ program_name);
+ free(specials_file_name);
+ free(specials_lock_name);
+ unlink(name);
+ return EXIT_FAILURE;
+ }
+
+ free(specials_file_name);
+ free(specials_lock_name);
+
+ return EXIT_SUCCESS;
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c1b37bb..27225de 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,2 +1,3 @@
src/main.c
src/opk.c
+helpers/mknod.c