pkgsrc for FreeMiNT


The goal of this project is to port the pkgsrc infrastructure to FreeMiNT.

The project will be considered complete when the bootstrap process successfully creates the binary kit, which is the only way to get pkgsrc working on a clean system..

Status: 🔧️

Requirements

Download pkgsrc

Changes to be made to the default configuration

The bootstrap script

Script to call bootstrap

#!/bin/bash
# Custom launcher for bootstrap
if [ ! -f /bin/sh ]; then
  ln -s /bin/bash /bin/sh
fi
umask 0022
cd /usr/pkgsrc/bootstrap
env CONFIGURE_ENV='ac_cv_func_lchmod=no ac_cv_func_lchflags=no ac_cv_func_getopt=yes' ./bootstrap --prefix /c/usr/pkg --workdir /c/usr/pkgsrc/bootstrap/work --compiler gcc --unprivileged --cwrappers no --prefer-native yes

Source: go.sh on Forgejo

Details

  • Environment: disable lchmod and lchflags
  • prefix
  • workdir
  • compiler
  • unprivileged mode because the emulator does not have root privileges
  • no wrappers
  • prefer native tools

Results

Partial bootstrap

  • bmake is usable
  • The pkgtools are usable in minimal versions (except for delete, which is missing)
  • pkg_info displays the packages installed from source (bmake, libnbcompat, ...)

bootstrap successful

  • Most calls to libfetch had to be disabled
  • Available for download

success

Building pax

  • cd /usr/pkgsrc/archivers/pax; bmake install

pax-1-start pax-2-error

  • Failure with duplicate symbols: to fix this bug, remove char *chdname; from extern.h and add it to options.c (extern.h is included by both options.c and ar_io.c hence the duplicate).
  • Next bug: default value of umask :

pax-3-error

  • Run umask 0022 ; bmake clean install (diff crashes again)

pax-4-success

  • Note the binary is nbpax

pax-5-nbpax

The problems encountered

Problem solving

./bootstrap does not start

  • Cause: the binary sh does not exist sh
  • Resolution: create a symlink : cd bin; ln -s bash sh
  • Explanation: the script is looking for sh, which is not present by default

./bootstrap indicates that the default paths are not suitable

  • Cause: bootstrap prohibits the use of links in file paths symlinks
  • Resolution: use /c/usr/pkg instead of /usr/pkg.
  • Explanation: /usr is a link to c:/usr (sln directive in mint.cnf)

./bootstrap cannot be restarted without deleting everything

  • Cause: bootstrap wants to start from a clean base each time workexists
  • Resolution: skip the test in the script bootstrap
  • Explanation: no need to delete anything since we're restarting under the same conditions to find the bugs
--- bootstrap.orig  2025-11-15 15:47:59.722597455 +0100
+++ bootstrap   2025-11-15 15:49:55.875815746 +0100
@@ -962,15 +962,18 @@
 check_prog whoamiprog whoami

 if [ -d "${wrkdir}" ] || [ -f "${wrkdir}" ]; then
-   die "\"${wrkdir}\" already exists, please remove it or use --workdir"
+#  die "\"${wrkdir}\" already exists, please remove it or use --workdir"
+   echo "\"${wrkdir}\" already exists, continue..."
 fi

 if [ -f "${prefix}/share/mk/sys.mk" ]; then
-   die "\"${prefix}\" already in use, remove it or use a different --prefix"
+#  die "\"${prefix}\" already in use, remove it or use a different --prefix"
+   echo "\"${prefix}\" already in use, continue..."
 fi

 if [ -d "${pkgdbdir}/bootstrap-mk-files-"* ]; then
-   die "\"${pkgdbdir}\" already in use, remove it or use a different --pkgdbdir"
+#  die "\"${pkgdbdir}\" already in use, remove it or use a different --pkgdbdir"
+   echo "\"${pkgdbdir}\" already in use, continue..."
 fi

 mkdir_p_early ${wrkdir}

chflags() does not exist

  • Cause: despite the options, the code still uses chflags chflags
  • Resolution: add an exception, as you would for Linux
  • Explanation: The code does not depend on the options passed
  • Details: file pkgtools/libnbcompat/files/lchflags.c
    --- lchflags.c.orig 2025-10-28 19:57:28.979683563 +0100
    +++ lchflags.c  2025-10-28 19:45:30.725554587 +0100
    @@ -48,7 +48,7 @@
    if (S_ISLNK(psb.st_mode)) {
        return 0;
    }
    -#if defined(__illumos__) || defined(__linux__)
    +#if defined(__illumos__) || defined(__linux__) || defined(__MINT__)
    errno = (path == NULL ? EINVAL : ENOSYS);
    return -1;
    #else

Incompatibility between off_t and la_int64_t

  • Cause: a function declares an offset of type off_t (32-bit), but the libarchive function expects a 64-bit value la_int64_t
  • Resolution: specify the correct type in the code
  • Explanation: on 64-bit architectures, off_t is promoted to 64 bits, but remains 32 bits on 32-bit architectures.
  • Details: file pkg_install/add/perform.c
--- perform.c.orig  2025-04-17 23:29:34.000000000 +0200
+++ perform.c   2025-11-15 17:15:00.116495241 +0100
@@ -654,7 +654,7 @@
    int r;
    const void *buff;
    size_t size;
-   off_t offset;
+   la_int64_t offset;

    for (;;) {
        r = archive_read_data_block(reader, &buff, &size, &offset);

getopt is defined multiple times

  • Cause: the use of the function does not seem to depend on the options getopt
  • Resolution: skip the test in the configure script (see below) and put "CONFIGURE_ARGS+= --enable-db" in /usr/pkgsrc/pkgtools/libnbcompat/Makefile. Delete in /usr/pkgsrc/bootstrap/work/libnbcompat all files libnbcompat.a, .o, config.status, config.log, then, in nbcompat, files config.h and nbconfig.h
  • Explanation: by entering 'no', the following test becomes false and the BSD version is no longer used
  • Details: in usr/pkgsrc/pkgtools/libnbcompat/files/configure, add l.5913: "enable_bsd_getopt=no" and delete the line 720
--- configure.orig  2025-03-05 12:54:23.000000000 +0100
+++ configure   2025-11-15 18:13:26.849578264 +0100
@@ -717,7 +717,6 @@
 ac_user_opts='
 enable_option_checking
 enable_db
-enable_bsd_getopt
 '
       ac_precious_vars='build_alias
 host_alias
@@ -5910,7 +5909,7 @@
 fi

 done
-
+enable_bsd_getopt=no
 if test "$enable_bsd_getopt" = yes; then
    if test "$ac_cv_have_decl_optreset" = no; then
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using included getopt and getopt_long" >&5

awk not found

  • Cause: /bin/awk is not installed on the base system awk
  • Resolution: add awk from the available archive, but is in /usr/bin. Update tools.FreeMiNT.mk
  • Explanation: awk, like other tools, is necessary. The NetBSD base system already includes many commands, including awk
--- tools.FreeMiNT.mk.orig  2023-03-05 00:29:24.000000000 +0100
+++ tools.FreeMiNT.mk   2025-11-15 19:54:09.123705473 +0100
@@ -3,7 +3,7 @@
 # System-supplied tools for the FreeMiNT operating system.

 TOOLS_PLATFORM.[?=     [           # shell builtin
-TOOLS_PLATFORM.awk?=       /bin/awk
+TOOLS_PLATFORM.awk?=       /usr/bin/awk
 TOOLS_PLATFORM.basename?=  /bin/basename
 TOOLS_PLATFORM.byacc?=     /usr/bin/yacc
 TOOLS_PLATFORM.bzcat?=     /usr/bin/bzcat

Error: dlopen() is required

  • Cause: TODO dlopen
  • Resolution: TODO
  • Explanation: TODO

Error accessing folder libnbcompat/work/.destdir/pkg

  • Cause: a pkg folder is created with the permissions ̀d---------` operation_not_permitted
  • Resolution: not yet found. A workaround is to modify WRKOBJDIR directly in the bootstrap script. Use WRKOBJDIR= /ram
  • Explanation: not yet found
--- bootstrap.old   2025-11-15 15:49:55.875815746 +0100
+++ bootstrap   2025-11-15 22:05:25.508120615 +0100
@@ -1414,7 +1414,7 @@
 # opsys specific fiddling
 opsys_finish

-echo "WRKOBJDIR=       ${wrkdir}/wrk" >> ${BOOTSTRAP_MKCONF}
+echo "WRKOBJDIR=       /ram" >> ${BOOTSTRAP_MKCONF}

 echo "" >> ${TARGET_MKCONF}
 echo "" >> ${BOOTSTRAP_MKCONF}

Files not found

  • Cause: the cp -r function fails
  • Resolution: needs further investigation. Works correctly with mintelf tools but not with mint type tools
  • Explanation: memory exhausted error. Probably a recursion problem

umask error

  • Cause: default value is 0000 umask
  • Resolution: run 'umask 0022' before launching the bootstrap script
  • Explanation: 0022 is the minimum expected value. In theory, it should be set by the script, but the correct value seems necessary before calling umask

diff crash

  • Cause: unknown diff
  • Resolution: unknown
  • Explanation: none
  • Details :
    • diff f1 f2 works
    • diff -u f1 f2 works if the files are identical
    • diff -u f1 f2 crashes if the files are different

sed crash

  • Cause: unknown sed
  • Resolution: unknown
  • Explanation: none

wc crash

  • Cause: mbrtowc() and iswspace() dont work wc
  • Resolution: replace these two functions with functions that do not use wchar_t
  • Explanation: likely a bug in the MiNTLib
    • Get the source code here
    • Replace iswspace(*WC) with isspace(*WC)
    • Replace r = mbrtowc(wc, p, len, st); with r = fake_mbrtowc(wc, p, len, st);
    • Add:
      size_t fake_mbrtowc(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) {
          if (s == NULL)
              return 0;
          if (n == 0)
              return (size_t)-2;
          if (pwc)
              *pwc = (unsigned char)*s;
          return (*s != '\0') ? 1 : 0;
      }
    • Recompile gcc wc.c -o wc

Failure with mman.h (netpgpverify)

  • Cause: the files libverify.c and pgpsum.c include mman.h mman
  • Resolution: replace the mmap()/munmap() calls with malloc()/free()
  • Explanation: mmap() is not available on FreeMiNT
  • pkgsrc/security/netpgpverify/files/libverify.c
--- libverify.c.orig    2020-11-01 12:28:35.000000000 +0100
+++ libverify.c 2025-11-16 06:56:37.670741897 +0100
@@ -27,7 +27,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
+#if 0
 #include <sys/mman.h>
+#endif

 #include <arpa/inet.h>

@@ -473,9 +475,27 @@
    }
    fstat(fileno(mem->fp), &st);
    mem->size = (size_t)st.st_size;
+#if 0  
    mem->mem = mmap(NULL, mem->size, PROT_READ, MAP_SHARED, fileno(mem->fp), 0);
    mem->dealloc = UNMAP_MEM;
    return 1;
+#endif
+#if 1
+   mem->mem = malloc(mem->size);
+   if (mem->mem == NULL) {
+       fprintf(stderr, "malloc failed for '%s'\n", f);
+       fclose(mem->fp);
+       return 0;
+   }
+   if (fread(mem->mem, 1, mem->size, mem->fp) != mem->size) {
+       fprintf(stderr, "short read on '%s'\n", f);
+       free(mem->mem);
+       fclose(mem->fp);
+       return 0;
+   }
+    mem->dealloc = FREE_MEM;
+    return 1;
+#endif 
 }

 /* DTRT and free resources */
@@ -488,7 +508,9 @@
        mem->size = 0;
        break;
    case UNMAP_MEM:
+#if 0  
        munmap(mem->mem, mem->size);
+#endif     
        fclose(mem->fp);
        break;
    }
  • pkgsrc/security/netpgpverify/files/pgpsum.c
--- pgpsum.c.orig   2020-05-04 03:37:28.000000000 +0200
+++ pgpsum.c    2025-11-16 07:01:19.621761352 +0100
@@ -26,7 +26,9 @@

 #include <sys/types.h>
 #include <sys/stat.h>
+#if 0
 #include <sys/mman.h>
+#endif

 #include <inttypes.h>
 #include <stdio.h>
@@ -225,14 +227,35 @@
        goto done;
    }
    cc = (size_t)(st.st_size);
+#if 0
    if ((mem = mmap(NULL, cc, PROT_READ, MAP_SHARED, fileno(fp), 0)) == MAP_FAILED) {
        fprintf(stderr, "%s - can't mmap", name);
        goto done;
    }
+#endif
+#if 1
+    mem = malloc(cc);
+    if (mem == NULL) {
+        fprintf(stderr, "%s - can't allocate %zu bytes\n", name, cc);
+        goto done;
+    }
+    if (fread(mem, 1, cc, fp) != cc) {
+        fprintf(stderr, "%s - short read or read error\n", name);
+        free(mem);
+        mem = NULL;
+        goto done;
+    }
+#endif 
    ret = calcsum(data, size, mem, cc, hashed, hashsize, doarmor);
 done:
    if (data) {
+#if 0
        munmap(mem, cc);
+#endif
+#if 1
+        if (mem)
+            free(mem);
+#endif     
    }
    fclose(fp);
    return ret;

The /usr/pkg directory already exists

  • Cause: the bootstrap script checks for the existence of the folder
  • Resolution: remove the check from the bootstrap script
  • Explanation: same reason as for workdir

The hostname command returns (null)

  • Cause: hostname is not defined hostname
  • Resolution: create a file /etc/hostname and put the computer name in it
  • Explanation: the command returns the content of this file

Stuck while searching for files newer than the configure file

  • Cause: configure checks if there are any files newer than itself, in which case it needs to be restarted, but this test fails
  • Resolution: run 'find . -name configure -exec touch {} \;' in the directory.
  • Explanation: due to modifications made to the .c files during attempts to apply patches to get bootstrap working, these files have updated dates and are therefore newer than the configure script that uses them. By giving all the configure files the current date, no other file can be newer, and the test passes. The cause of the blockage is unknown (slowness of the file date checks?)

Command not found --modversion

  • Cause: the pkg-config command was not found or returned an empty string command_not_found
  • Resolution: install pkg-config if it is missing, or copy it to .tools/bin/ if there is a script with the same name but which returns nothing
  • Explanation: either pkg-config is missing, or it is a script that returns nothing (in which case the test for a version greater than 0.9.0 fails, even though the existing version returns 0.15.0)
cp /usr/bin/pkg-config /ram/pkgtools/libnbcompat/work/.tools/bin/
cp /usr/bin/pkg-config /ram/pkgtools/boostrap-mk-files/work/.tools/bin/
cp /usr/bin/pkg-config /ram/pkgtools/pkg_install/work/.tools/bin/

tsort input contains an odd number of tokens

  • Cause: unknown

tsort

  • Resolution: unknown
  • Explanation: unknown

Command not found ac_fn_c_try_link

  • Cause: unknown

ac_fn_c_try_link

  • Resolution: unknown
  • Explanation: unknown

Failure linking pkg_install with libfetch

  • Cause: the libfetch.a file is created correctly, but it contains no symbols! undefined_ref

  • Resolution: remove the function calls to this library from all programs that use libfetch. Note, all affected files (parse-config.c, pkg_io.c, audit.c and main.c) must be copied from their location in /usr/pkgsrc/pkgtools/pkg_install/files to the same location in /ram/pkgtools/pkg_install/work/pkg_install-20250417/.

  • Explanation: tsort fails

  • File /usr/pkgsrc/pkgtools/pkg_install/files/lib/parse-config.c

--- parse-config.c.orig 2020-12-11 11:06:53.000000000 +0100
+++ parse-config.c  2025-11-16 09:36:36.580951685 +0100
@@ -46,9 +46,11 @@
 #include <string.h>
 #endif

+#if 0
 #ifndef BOOTSTRAP
 #include <fetch.h>
 #endif
+#endif

 #include "lib.h"

@@ -240,9 +242,11 @@
    }
    config_cache_connections_host = xasprintf("%d", cache_connections_host);

+#if 0
 #ifndef BOOTSTRAP
    fetchConnectionCacheInit(cache_connections, cache_connections_host);
 #endif
+#endif

    snprintf(fetch_flags, sizeof(fetch_flags), "%s%s%s%s",
        (do_cache_index) ? "c" : "",
  • File /usr/pkgsrc/pkgtools/pkg_install/files/lib/pkg_io.c
--- pkg_io.c.orig   2023-11-08 02:24:29.000000000 +0100
+++ pkg_io.c    2025-11-16 09:43:49.598979501 +0100
@@ -79,7 +79,10 @@
 {
    struct fetch_archive *f = client_data;
    struct url_stat us;
-
+#if 1
+    return ENOENT;
+#endif 
+#if 0
    f->fetch = fetchXGet(f->url, &us, fetch_flags);
    if (f->fetch == NULL)
        return ENOENT;
@@ -87,8 +90,10 @@
    f->restart = 1;
    f->url->offset = 0;
    return 0;
+#endif 
 }

+#if 0
 static ssize_t
 fetch_archive_read(struct archive *a, void *client_data,
     const void **buffer)
@@ -140,13 +145,14 @@
    free(f);
    return 0;
 }
+#endif

 static struct archive *
 open_archive_by_url(struct url *url, char **archive_name)
 {
    struct fetch_archive *f;
    struct archive *a;
-
+#if 0
    f = xmalloc(sizeof(*f));
    f->url = fetchCopyURL(url);

@@ -162,6 +168,11 @@
    }

    return a;
+#endif
+#if 1
+    *archive_name = NULL;
+    return NULL;
+#endif 
 }
 #endif /* !BOOTSTRAP */

@@ -201,6 +212,7 @@
 #ifdef BOOTSTRAP
    return NULL;
 #else
+#if 0
    if ((u = fetchParseURL(url)) == NULL)
        return NULL;

@@ -209,9 +221,14 @@
    fetchFreeURL(u);
    return a;
 #endif
+#if 1
+    return NULL;
+#endif
+#endif
 }

 #ifndef BOOTSTRAP
+#if 0
 static int
 strip_suffix(char *filename)
 {
@@ -227,6 +244,7 @@
    } else
        return 0;
 }
+#endif

 static int
 find_best_package_int(struct url *url, const char *pattern,
@@ -235,7 +253,10 @@
    char *cur_match, *url_pattern, *best_match = NULL;
    struct url_list ue;
    size_t i;
-
+#if 1
+    return -1;
+#endif
+#if 0
    if (*best_url) {
        if ((best_match = fetchUnquoteFilename(*best_url)) == NULL)
            return -1;
@@ -296,6 +317,7 @@
    free(best_match);
    fetchFreeURLList(&ue);
    return 0;
+#endif
 }

 void
@@ -334,7 +356,7 @@
 {
    struct url *url, *best_match = NULL;
    struct pkg_path *pl;
-
+#if 0
    if (toplevel) {
        url = fetchParseURL(last_toplevel);
        if (url != NULL) {
@@ -354,7 +376,7 @@
            fetchFreeURL(url);
        }
    }
-
+#endif
    return best_match;
 }
 #endif /* !BOOTSTRAP */
@@ -392,7 +414,7 @@
 #ifndef BOOTSTRAP
    fname = last_slash + 1;
    *last_slash = '\0';
-
+#if 0
    best_match = find_best_package(full_fname, fname, 0);

    if (search_path && best_match == NULL)
@@ -404,6 +426,10 @@
        return NULL;
    a = open_archive_by_url(best_match, archive_name);
    fetchFreeURL(best_match);
+#endif
+#if 1
+   return NULL;
+#endif
 #endif /* !BOOTSTRAP */
    return a;
 }
  • File /usr/pkgsrc/pkgtools/pkg_install/files/admin/audit.c
--- audit.c.orig    2018-02-27 00:45:02.000000000 +0100
+++ audit.c 2025-11-16 09:54:00.974240159 +0100
@@ -86,8 +86,9 @@
 parse_options(int argc, char **argv, const char *options)
 {
    int ch;
-
+#if 0
    optreset = 1;
+#endif 
    /*
     * optind == 0 is interpreted as partial reset request
     * by GNU getopt, so compensate against this and cleanup
@@ -298,7 +299,9 @@
    ssize_t cur_fetched;
    struct url *url;
    struct url_stat st;
+#if 0  
    fetchIO *f;
+#endif 
    int fd;
    struct stat sb;
    char my_flags[20];
@@ -310,7 +313,11 @@

    if (verbose >= 2)
        fprintf(stderr, "Fetching %s\n", pkg_vulnerabilities_url);
-
+#if 1
+    errx(EXIT_FAILURE,
+           "Could not parse location of pkg_vulnerabilities: no support for MiNT");
+#endif
+#if 0
    url = fetchParseURL(pkg_vulnerabilities_url);
    if (url == NULL)
        errx(EXIT_FAILURE,
@@ -382,6 +389,7 @@
    free(buf);

    exit(EXIT_SUCCESS);
+#endif 
 }

 static int
  • File /usr/pkgsrc/pkgtools/pkg_install/files/admin/main.c
--- main.c.orig 2025-02-18 13:04:31.000000000 +0100
+++ main.c  2025-11-16 09:55:26.829210996 +0100
@@ -734,6 +734,7 @@
            errx(EXIT_FAILURE, "invalid license");
        }
    }
+#if 0
 #ifndef BOOTSTRAP
    else if (strcasecmp(argv[0], "findbest") == 0) {
        struct url *url;
@@ -806,6 +807,7 @@
        pkg_sign_gpg(argv[0], argv[1]);
    }
 #endif
+#endif
    else {
        usage();
    }

Undefined reference to optreset

  • Cause: extern optreset is not found optreset
  • Resolution: unknown
  • Explanation: optreset is not available in the MiNTLib

The bmake and pkg_xxx commands are not found

  • Cause: the PATH variable needs to be modified manually pkgtools_not_found
  • Resolution: edit the mint.cnf file and change the PATH to setenv PATH /usr/pkg/sbin;/usr/pkg/bin;/sbin;/bin;/usr/sbin;/usr/bin
  • Explanation: normal behavior, RTFM

License denied

  • Cause: non-free licenses are rejected by default license
  • Resolution: add the relevant license to the /usr/pkg/etc/mk.conf file
  • Explanation: normal behavior, RTFM

fetch fails when calling bmake

  • Cause: the package source files are missing and there is no network connection distfiles
  • Resolution: download the required archive and copy it to the /usr/pkgsrc/distfiles folder
  • Explanation: normal behavior, RTFM

Error on strerror_r: int and char * types do not match

  • Cause: the return value of type char * is being compared to an int strerror
  • Resolution: to be determined
  • Explanation: POSIX expects a return value of type int, while GNU returns char *

Unable to write the archive due to access rights

  • Cause: destdir includes links from /ram to /c cannot_write_archive
  • Resolution: delete links and copy regular file, then run bmake package again
  • Explanation: TODO

Previous Next