Делаем pkgsrc для WebDAV-сервера WebDAV-Daemon

Содержание

Введение

На этот раз не буду описывать весь процесс подготовки pkgsrc, поскольку для сборки этого пакета понадобилось внести большое количество исправлений в исходные тексты: добавить пропущенные заголовочные файлы, переписать Makefile для сборки программы из исходных текстов и добавить реализацию функции clearenv, отсутствующей в стандартах POSIX и библиотеке libc из NetBSD. Я просто приведу получившиеся значимые файлы.

net/webdavd/Makefile

Сначала приведу содержимое файла net/webdavd/Makefile:

# $NetBSD$

DISTNAME=               webdavd
PKGNAME=                ${DISTNAME}-1.1
CATEGORIES=             net
MASTER_SITES=           ${MASTER_SITE_GITHUB:=couling/}
GITHUB_PROJECT=         WebDAV-Daemon
#PKGREVISION=           1
GITHUB_TAG=             bb317905fbbb640a88276d451ac1852190d68807

MAINTAINER=             vladimir@stupin.su
HOMEPAGE=               https://github.com/couling/WebDAV-Daemon
COMMENT=                webdavd is a WebDAV server designed to be a replace for SAMBA
LICENSE=                mit

USE_LANGUAGES=          c
USE_TOOLS+=             gmake

CFLAGS+=                -I${BUILDLINK_PREFIX.libxml2}/include/libxml2/

post-extract:
        ${CP} ${FILESDIR}/Makefile ${WRKSRC}/

post-install:
        ${INSTALL} -c ${FILESDIR}/mime.types ${DESTDIR}${LOCALBASE}/share/examples/webdavd/

.include "../../devel/libuuid/buildlink3.mk"
.include "../../www/libmicrohttpd/buildlink3.mk"
.include "../../security/gnutls/buildlink3.mk"
.include "../../textproc/icu/buildlink3.mk"
.include "../../textproc/libxml2/buildlink3.mk"
.include "../../mk/bsd.pkg.mk"

Исходные тексты скачиваются из репозитория на github. Используется самая свежая на момент подготовки этого файла фиксация из репозитория, сделанная после метки версии 1.1. Поэтому пакет будет иметь версию 1.1, но собираться будет из чуть более поздних исходных текстов. При необходимости собрать новую версию надо будет только указать хэш новой фиксации из репозитория в переменной GITHUB_TAG и, раскомментировать переменную PKGREVISION и указать в ней номер ревизии в переменной.

В процессе сборки используются зависимости - библиотеки libxml2, icu, gnutls, libmicrohttpd и libuuid. Для того, чтобы компилятор смог найти заголовочные файлы библиотеки libxml2, в Makefile к переменной CFLAGS добавляется путь к этим заголовочным файлам, описанный в Makefile pkgsrc textproc/libxml2.

Для сборки используется компилятор языка Си и утилита GMake.

Кроме файлов, имевшихся в исходных текстах, для запуска демона мне понадобился файл mime.types, который я взял из пакета nginx. Он добавляется к пакету уже после окончания сборки и установки файлов в промежуточный каталог net/webdavd/work/.destdir.

net/webdavd/files/Makefile

Для сборки используется собственный Makefile, который копируется в исходные тексты программы сразу после их распаковки из архива. Приведу содержимое этого файла net/webdavd/files/Makefile:

all: rap webdavd

install: rap webdavd
        install -d $(DESTDIR)$(LOCALBASE)/libexec/
        install -c rap $(DESTDIR)$(LOCALBASE)/libexec/
        install -d $(DESTDIR)$(LOCALBASE)/sbin/
        install -c webdavd $(DESTDIR)$(LOCALBASE)/sbin/
        install -d $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_BAD_REQUEST.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_CONFLICT.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_FORBIDDEN.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_INSUFFICIENT_STORAGE.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_INTERNAL_SERVER_ERROR.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_METHOD_NOT_SUPPORTED.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_NOT_FOUND.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_OK.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_UNAUTHORIZED.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/HTTP_UPLOAD_COMPLETE.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -c package-with/share/OPTIONS.html $(DESTDIR)$(LOCALBASE)/share/webdavd/
        install -d $(DESTDIR)$(LOCALBASE)/share/doc/webdavd/
        install -c README.md $(DESTDIR)$(LOCALBASE)/share/doc/webdavd/
        install -c LICENCE.md $(DESTDIR)$(LOCALBASE)/share/doc/webdavd/LICENSE.md
        install -c Configuration.md $(DESTDIR)$(LOCALBASE)/share/doc/webdavd/CONFIG.md
        install -d $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/
        install -c useful/conf.xml $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/webdavd.xml.sample
        install -c package-with/conf.xml $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/webdavd.xml.full
        install -c package-with/logrotate.conf $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/
        install -c package-with/pam-rhel.conf $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/
        install -c package-with/pam.conf $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/
        install -c package-with/systemd.service $(DESTDIR)$(LOCALBASE)/share/examples/webdavd/

webdavd: webdavd.o shared.o configuration.o xml.o
        $(CC) $(LDFLAGS) -lmicrohttpd -lxml2 -lgnutls -luuid $^ -o $@

rap: rap.o shared.o xml.o
        $(CC) $(LDFLAGS) -lxml2 -lpam $^ -o $@

.c.o:
        $(CC) $(CFLAGS) -c $< -o $@

clean:
        rm -rf rap webdavd *.o

.PHONY: all install clean

В этом Makefile я предусмотрел установку двоичных файлов и всех дополнительных файлов в каталоги, которые принято использовать в NetBSD. Возможно этот Makefile не соответствует правилам других операционных систем. В таком случае часть команд установки стоит перенести в Makefile pkgsrc.

net/webdavd/DESCR

Файл net/webdavd/DESCR имеет следующий вид:

webdavd is a WebDAV server designed to be a replace for SAMBA providing access
to a system's files without taking ownership of them. It aims to differ from
most WebDAV servers on a number of points:

* Users are authenticated through PAM and are always operating system users.
* The webserver switches OS user to match the authenticated user before
  accessing any files.
* The daemon operates without any prior knowledge of the files it's serving.
* The daemon does NOT take ownership of the files it modifies and serves. It
  does not take ownership of any files in any way. Even locking operations are
  implemented using the native OS flock() function.

net/webdavd/patches

Теперь приведу заплатки, в которых к исходным текстам добавлены пропущенные заголовочные файлы и внесены доработки.

net/webdavd/patches/patch-configuration.c

Первая заплатка находится в файле net/webdavd/patches/patch-configuration.c:

$NetBSD$

--- configuration.c.orig        2024-05-02 21:51:32.315470624 +0000
+++ configuration.c
@@ -4,6 +4,7 @@

 #include "xml.h"

+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 WebdavdConfiguration config;

Как видно, тут добавлен только заголовочный файл stdlib.h.

net/webdavd/patches/patch-webdavd.c

Вторая заплатка находится в файле net/webdavd/patches/patch-webdavd.c:

$NetBSD$

--- webdavd.c.orig      2024-05-02 21:41:33.881119264 +0000
+++ webdavd.c
@@ -10,12 +10,14 @@
 #include <pthread.h>
 #include <search.h>
 #include <semaphore.h>
+#include <signal.h>
 #include <string.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <netdb.h>
+#include <netinet/in.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <uuid/uuid.h>

Тут добавлены заголовочные файлы signal.h и netinet/in.h.

net/webdavd/patches/patch-rap.c

Третья заплатка находится в файле net/webdavd/patches/patch-rap.c:

$NetBSD$

--- rap.c.orig  2023-10-14 21:54:29.000000000 +0000
+++ rap.c
@@ -1481,6 +1481,47 @@ static void pamCleanup() {
        pam_end(pamh, pamResult);
 }

+#ifndef clearenv
+extern char **environ;
+
+// Simple implementation, but may be incorrect
+static void _clearenv() {
+       if (environ != NULL) {
+               environ[0] = NULL;
+       }
+}
+
+// More complex, but more correct implementation
+static void clearenv() {
+        char *name = NULL;
+        size_t name_max_len = 0;
+        while (environ[0] != NULL) {
+                char *p = strchr(environ[0], '=');
+                if (p == NULL) {
+                        unsetenv(environ[0]);
+                        continue;
+                }
+
+                size_t name_len = p - environ[0];
+                if (name_len > name_max_len) {
+                        p = realloc(name, name_len + 1);
+                        if (p == NULL) {
+                                // infinite loop may occured when low memory
+                                continue;
+                        }
+                        name_max_len = name_len;
+                        name = p;
+                }
+
+                strncpy(name, environ[0], name_len);
+                name[name_len] = '\0';
+
+                unsetenv(name);
+        }
+        free(name);
+}
+#endif
+
 static int pamAuthenticate(const char * user, const char * password, const char * hostname) {
        static struct pam_conv pamc = { .conv = (int (*)(int num_msg, const struct pam_message **msg,
                        struct pam_response **resp, void *appdata_ptr)) &pamConverse };

Дело в том, что в стандартной библиотеке libc NetBSD нет функции clearenv, которая доступна только в GNU libc и не описана в принятых стандартах POSIX. Я написал две реализации этой функции - простую и быструю, которая просто присваивает первому элементу массива с переменными окружения значение NULL, таким образом очищая его.

Но я не знаю деталей реализации, каким образом распределяется память для элементов массива. На всякий случай, чтобы исключить утечки памяти, я написал второй вариант этой же функции с использованием функции unsetenv, которая умеет удалять из массива переменных окружения только одну переменную. Я надеюсь, что она корректно освобождает оперативную память, занятую элементами массива. Для удаления всех элементов в массиве функция вызывается в цикле для очистки первой переменной окружения до тех пор, пока первая переменная окружения не станет пустой.

net/webdavd/distinfo

Для формирования содержимого файла net/webdavd/distinfo можно воспользоваться командой:

# make distinfo

net/webdavd/PLIST

Для формирования содержимого файла net/webdavd/PLIST после успешной сборки двоичных файлов из исходных текстов можно воспользоваться командой:

# make print-PLIST > PLIST