summaryrefslogtreecommitdiffstats
path: root/helpers
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 /helpers
parent2622c8a1e2c1cabfd0f0c6f504325b9ae21672fa (diff)
mknod: New helper utility
Diffstat (limited to 'helpers')
-rw-r--r--helpers/local.mk1
-rw-r--r--helpers/mknod.c299
2 files changed, 300 insertions, 0 deletions
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;
+}