commit 863dc7f
shrub
·
2026-06-04 11:22:40 +0000 UTC
parent 44ae0f1
add makefs
64 files changed,
+17218,
-129
M
Makefile
M
Makefile
+1,
-1
1@@ -1,7 +1,7 @@
2 .POSIX:
3
4 #RECURSIVE MAKE CONSIDERED USEFUL?
5-SUBDIRS = apply col ctags finger jot look pr rs script shar
6+SUBDIRS = compat apply col ctags finger jot look makefs pr rs script shar
7 all:
8 @set -e; \
9 for dir in $(SUBDIRS); do \
+11,
-0
1@@ -3,6 +3,17 @@ netmisc
2
3 misc programs from netbsd with some compatibilty shim and portability bits.
4
5+- apply
6+- col
7+- ctags
8+- finger
9+- look
10+- makefs
11+- pr
12+- rs
13+- script
14+- shar
15+
16 the shar implementation is not from netbsd, but a slightly improved version in C by me
17
18 you need cc, make, yacc, etc to build, and a reasonably posix-compliant system.
+7,
-3
1@@ -1,7 +1,8 @@
2 .POSIX:
3
4 PROG = apply
5-SRCS = apply.c ../compat/getprogname.c ../compat/setprogname.c
6+SRCS = apply.c
7+COMPATLIB = ../compat/libnetcompat.a
8 MAN = apply.1
9
10 CC = cc
11@@ -13,8 +14,11 @@ MANDIR = /usr/local/share/man
12
13 all: $(PROG)
14
15-$(PROG): $(SRCS)
16- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
17+$(PROG): $(SRCS) $(COMPATLIB)
18+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
19+
20+$(COMPATLIB):
21+ (cd ../compat && $(MAKE) all)
22
23 install: $(PROG)
24 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+7,
-5
1@@ -1,9 +1,8 @@
2 .POSIX:
3
4 PROG = col
5-SRCS = col.c ../compat/getprogname.c ../compat/strtoi.c \
6- ../compat/errc.c ../compat/verrc.c ../compat/warnc.c \
7- ../compat/vwarnc.c
8+SRCS = col.c
9+COMPATLIB = ../compat/libnetcompat.a
10 MAN = col.1
11
12 CC = cc
13@@ -15,8 +14,11 @@ MANDIR = /usr/local/share/man
14
15 all: $(PROG)
16
17-$(PROG): $(SRCS)
18- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
19+$(PROG): $(SRCS) $(COMPATLIB)
20+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
21+
22+$(COMPATLIB):
23+ (cd ../compat && $(MAKE) all)
24
25 install: $(PROG)
26 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+36,
-0
1@@ -0,0 +1,36 @@
2+.POSIX:
3+
4+LIB = libnetcompat.a
5+SRCS = \
6+ db.c efun.c errc.c fgetln.c fparseln.c getmode.c getprogname.c \
7+ pwcache.c reallocarr.c raise_default_signal.c setgroupent.c \
8+ setpassent.c setprogname.c shquote.c strlcat.c strlcpy.c \
9+ strsuftoll.c strtoi.c strtou.c unvis.c verrc.c vis.c vwarnc.c \
10+ warnc.c
11+OBJS = \
12+ db.o efun.o errc.o fgetln.o fparseln.o getmode.o getprogname.o \
13+ pwcache.o reallocarr.o raise_default_signal.o setgroupent.o \
14+ setpassent.o setprogname.o shquote.o strlcat.o strlcpy.o \
15+ strsuftoll.o strtoi.o strtou.o unvis.o verrc.o vis.o vwarnc.o \
16+ warnc.o
17+
18+CC = cc
19+AR = ar
20+RANLIB = ranlib
21+CFLAGS = -O2
22+CPPFLAGS = -DHAVE_NBTOOL_CONFIG_H=1 -I. -include netcompat.h
23+
24+all: $(LIB)
25+
26+.c.o:
27+ $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
28+
29+$(LIB): $(OBJS)
30+ rm -f $(LIB)
31+ $(AR) -rc $(LIB) $(OBJS)
32+ $(RANLIB) $(LIB)
33+
34+install:
35+
36+clean:
37+ rm -f $(LIB) $(OBJS)
+203,
-0
1@@ -0,0 +1,203 @@
2+/* $NetBSD: efun.c,v 1.12 2019/10/03 20:29:19 tnn Exp $ */
3+
4+/*-
5+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
6+ * All rights reserved.
7+ *
8+ * This code is derived from software contributed to The NetBSD Foundation
9+ * by Christos Zoulas.
10+ *
11+ * Redistribution and use in source and binary forms, with or without
12+ * modification, are permitted provided that the following conditions
13+ * are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above copyright
17+ * notice, this list of conditions and the following disclaimer in the
18+ * documentation and/or other materials provided with the distribution.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+ * POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if HAVE_NBTOOL_CONFIG_H
34+#include "nbtool_config.h"
35+#endif
36+
37+#include <sys/cdefs.h>
38+#ifdef __RCSID
39+__RCSID("$NetBSD: efun.c,v 1.12 2019/10/03 20:29:19 tnn Exp $");
40+#endif
41+
42+#include <err.h>
43+#include <errno.h>
44+#include <inttypes.h>
45+#include <string.h>
46+#include <stdlib.h>
47+#include <stdio.h>
48+#include <stdarg.h>
49+#include <util.h>
50+
51+static void (*efunc)(int, const char *, ...) = err;
52+
53+static void __dead
54+eexit(int e, const char *fmt NETCOMPAT_UNUSED, ...)
55+{
56+ exit(e);
57+}
58+
59+void (*
60+esetfunc(void (*ef)(int, const char *, ...)))(int, const char *, ...)
61+{
62+ void (*of)(int, const char *, ...) = efunc;
63+ efunc = ef == NULL ? eexit : ef;
64+ return of;
65+}
66+
67+size_t
68+estrlcpy(char *dst, const char *src, size_t len)
69+{
70+ size_t rv;
71+ if ((rv = strlcpy(dst, src, len)) >= len) {
72+ errno = ENAMETOOLONG;
73+ (*efunc)(1,
74+ "Cannot copy string; %zu chars needed %zu provided",
75+ rv, len);
76+ }
77+ return rv;
78+}
79+
80+size_t
81+estrlcat(char *dst, const char *src, size_t len)
82+{
83+ size_t rv;
84+ if ((rv = strlcat(dst, src, len)) >= len) {
85+ errno = ENAMETOOLONG;
86+ (*efunc)(1,
87+ "Cannot append to string; %zu chars needed %zu provided",
88+ rv, len);
89+ }
90+ return rv;
91+}
92+
93+char *
94+estrdup(const char *s)
95+{
96+ char *d = strdup(s);
97+ if (d == NULL)
98+ (*efunc)(1, "Cannot copy string");
99+ return d;
100+}
101+
102+char *
103+estrndup(const char *s, size_t len)
104+{
105+ char *d = strndup(s, len);
106+ if (d == NULL)
107+ (*efunc)(1, "Cannot copy string");
108+ return d;
109+}
110+
111+void *
112+emalloc(size_t n)
113+{
114+ void *p = malloc(n);
115+ if (p == NULL && n != 0)
116+ (*efunc)(1, "Cannot allocate %zu bytes", n);
117+ return p;
118+}
119+
120+void *
121+ecalloc(size_t n, size_t s)
122+{
123+ void *p = calloc(n, s);
124+ if (p == NULL && n != 0 && s != 0)
125+ (*efunc)(1, "Cannot allocate %zu blocks of size %zu", n, s);
126+ return p;
127+}
128+
129+void *
130+erealloc(void *p, size_t n)
131+{
132+ void *q = realloc(p, n);
133+ if (q == NULL && n != 0)
134+ (*efunc)(1, "Cannot re-allocate %zu bytes", n);
135+ return q;
136+}
137+
138+void
139+ereallocarr(void *p, size_t n, size_t s)
140+{
141+ int rv = reallocarr(p, n, s);
142+ if (rv != 0) {
143+ errno = rv;
144+ (*efunc)(1, "Cannot re-allocate %zu * %zu bytes", n, s);
145+ }
146+}
147+
148+FILE *
149+efopen(const char *p, const char *m)
150+{
151+ FILE *fp = fopen(p, m);
152+ if (fp == NULL)
153+ (*efunc)(1, "Cannot open `%s'", p);
154+ return fp;
155+}
156+
157+int
158+easprintf(char ** __restrict ret, const char * __restrict format, ...)
159+{
160+ int rv;
161+ va_list ap;
162+ va_start(ap, format);
163+ if ((rv = vasprintf(ret, format, ap)) == -1)
164+ (*efunc)(1, "Cannot format string");
165+ va_end(ap);
166+ return rv;
167+}
168+
169+int
170+evasprintf(char ** __restrict ret, const char * __restrict format, va_list ap)
171+{
172+ int rv;
173+ if ((rv = vasprintf(ret, format, ap)) == -1)
174+ (*efunc)(1, "Cannot format string");
175+ return rv;
176+}
177+
178+intmax_t
179+estrtoi(const char * nptr, int base, intmax_t lo, intmax_t hi)
180+{
181+ int e;
182+ intmax_t rv = strtoi(nptr, NULL, base, lo, hi, &e);
183+ if (e != 0) {
184+ errno = e;
185+ (*efunc)(1,
186+ "Cannot convert string value '%s' with base %d to a number in range [%jd .. %jd]",
187+ nptr, base, lo, hi);
188+ }
189+ return rv;
190+}
191+
192+uintmax_t
193+estrtou(const char * nptr, int base, uintmax_t lo, uintmax_t hi)
194+{
195+ int e;
196+ uintmax_t rv = strtou(nptr, NULL, base, lo, hi, &e);
197+ if (e != 0) {
198+ errno = e;
199+ (*efunc)(1,
200+ "Cannot convert string value '%s' with base %d to a number in range [%ju .. %ju]",
201+ nptr, base, lo, hi);
202+ }
203+ return rv;
204+}
+78,
-0
1@@ -0,0 +1,78 @@
2+/* $NetBSD: fgetln.c,v 1.5 2003/10/27 00:12:43 lukem Exp $ */
3+
4+/*
5+ * Copyright 1999 Luke Mewburn <lukem@NetBSD.org>.
6+ * All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. The name of the author may not be used to endorse or promote products
17+ * derived from this software without specific prior written permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
28+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+ */
30+
31+#include "nbtool_config.h"
32+
33+#if !HAVE_FGETLN
34+#include <err.h>
35+#include <stdio.h>
36+#include <stdlib.h>
37+#include <string.h>
38+
39+#define BUFCHUNKS BUFSIZ
40+
41+char *
42+fgetln(FILE *fp, size_t *len)
43+{
44+ static char *buf;
45+ static size_t bufsize;
46+ size_t buflen;
47+ char curbuf[BUFCHUNKS];
48+ char *p;
49+
50+ if (buf == NULL) {
51+ bufsize = BUFCHUNKS;
52+ buf = (char *)malloc(bufsize);
53+ if (buf == NULL)
54+ err(1, "Unable to allocate buffer for fgetln()");
55+ }
56+
57+ *buf = '\0';
58+ buflen = 0;
59+ while ((p = fgets(curbuf, sizeof(curbuf), fp)) != NULL) {
60+ size_t l;
61+
62+ l = strlen(p);
63+ if (bufsize < buflen + l) {
64+ bufsize += BUFCHUNKS;
65+ if ((buf = (char *)realloc(buf, bufsize)) == NULL)
66+ err(1, "Unable to allocate %ld bytes of memory",
67+ (long)bufsize);
68+ }
69+ strcpy(buf + buflen, p);
70+ buflen += l;
71+ if (p[l - 1] == '\n')
72+ break;
73+ }
74+ if (p == NULL && *buf == '\0')
75+ return (NULL);
76+ *len = strlen(buf);
77+ return (buf);
78+}
79+#endif
+250,
-0
1@@ -0,0 +1,250 @@
2+/* $NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp $ */
3+
4+/*
5+ * Copyright (c) 1997 Christos Zoulas. All rights reserved.
6+ *
7+ * Redistribution and use in source and binary forms, with or without
8+ * modification, are permitted provided that the following conditions
9+ * are met:
10+ * 1. Redistributions of source code must retain the above copyright
11+ * notice, this list of conditions and the following disclaimer.
12+ * 2. Redistributions in binary form must reproduce the above copyright
13+ * notice, this list of conditions and the following disclaimer in the
14+ * documentation and/or other materials provided with the distribution.
15+ * 3. All advertising materials mentioning features or use of this software
16+ * must display the following acknowledgement:
17+ * This product includes software developed by Christos Zoulas.
18+ * 4. The name of the author may not be used to endorse or promote products
19+ * derived from this software without specific prior written permission.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#include <sys/cdefs.h>
34+#if defined(LIBC_SCCS) && !defined(lint)
35+__RCSID("$NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp $");
36+#endif /* LIBC_SCCS and not lint */
37+
38+#include "namespace.h"
39+
40+#include <assert.h>
41+#include <errno.h>
42+#include <stdio.h>
43+#include <string.h>
44+#include <stdlib.h>
45+
46+#include "util.h"
47+
48+#ifdef __weak_alias
49+__weak_alias(fparseln,_fparseln)
50+#endif
51+
52+#if ! HAVE_FPARSELN
53+
54+#ifndef HAVE_NBTOOL_CONFIG_H
55+#include "reentrant.h"
56+#include "local.h"
57+#else
58+#define FLOCKFILE(fp)
59+#define FUNLOCKFILE(fp)
60+#endif
61+
62+#if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H
63+#define __fgetln(f, l) __fgetstr(f, l, '\n')
64+#else
65+#define __fgetln(f, l) fgetln(f, l)
66+#endif
67+
68+static int isescaped(const char *, const char *, int);
69+
70+/* isescaped():
71+ * Return true if the character in *p that belongs to a string
72+ * that starts in *sp, is escaped by the escape character esc.
73+ */
74+static int
75+isescaped(const char *sp, const char *p, int esc)
76+{
77+ const char *cp;
78+ size_t ne;
79+
80+ _DIAGASSERT(sp != NULL);
81+ _DIAGASSERT(p != NULL);
82+
83+ /* No escape character */
84+ if (esc == '\0')
85+ return 1;
86+
87+ /* Count the number of escape characters that precede ours */
88+ for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
89+ continue;
90+
91+ /* Return true if odd number of escape characters */
92+ return (ne & 1) != 0;
93+}
94+
95+
96+/* fparseln():
97+ * Read a line from a file parsing continuations ending in \
98+ * and eliminating trailing newlines, or comments starting with
99+ * the comment char.
100+ */
101+char *
102+fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
103+{
104+ static const char dstr[3] = { '\\', '\\', '#' };
105+
106+ size_t s, len;
107+ char *buf;
108+ char *ptr, *cp;
109+ int cnt;
110+ char esc, con, nl, com;
111+
112+ _DIAGASSERT(fp != NULL);
113+
114+ len = 0;
115+ buf = NULL;
116+ cnt = 1;
117+
118+ if (str == NULL)
119+ str = dstr;
120+
121+ esc = str[0];
122+ con = str[1];
123+ com = str[2];
124+ /*
125+ * XXX: it would be cool to be able to specify the newline character,
126+ * but unfortunately, fgetln does not let us
127+ */
128+ nl = '\n';
129+
130+ FLOCKFILE(fp);
131+
132+ while (cnt) {
133+ cnt = 0;
134+
135+ if (lineno)
136+ (*lineno)++;
137+
138+ if ((ptr = __fgetln(fp, &s)) == NULL)
139+ break;
140+
141+ if (s && com) { /* Check and eliminate comments */
142+ for (cp = ptr; cp < ptr + s; cp++)
143+ if (*cp == com && !isescaped(ptr, cp, esc)) {
144+ s = cp - ptr;
145+ cnt = s == 0 && buf == NULL;
146+ break;
147+ }
148+ }
149+
150+ if (s && nl) { /* Check and eliminate newlines */
151+ cp = &ptr[s - 1];
152+
153+ if (*cp == nl)
154+ s--; /* forget newline */
155+ }
156+
157+ if (s && con) { /* Check and eliminate continuations */
158+ cp = &ptr[s - 1];
159+
160+ if (*cp == con && !isescaped(ptr, cp, esc)) {
161+ s--; /* forget escape */
162+ cnt = 1;
163+ }
164+ }
165+
166+ if (s == 0 && buf != NULL)
167+ continue;
168+
169+ if ((cp = realloc(buf, len + s + 1)) == NULL) {
170+ FUNLOCKFILE(fp);
171+ free(buf);
172+ return NULL;
173+ }
174+ buf = cp;
175+
176+ (void) memcpy(buf + len, ptr, s);
177+ len += s;
178+ buf[len] = '\0';
179+ }
180+
181+ FUNLOCKFILE(fp);
182+
183+ if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
184+ strchr(buf, esc) != NULL) {
185+ ptr = cp = buf;
186+ while (cp[0] != '\0') {
187+ int skipesc;
188+
189+ while (cp[0] != '\0' && cp[0] != esc)
190+ *ptr++ = *cp++;
191+ if (cp[0] == '\0' || cp[1] == '\0')
192+ break;
193+
194+ skipesc = 0;
195+ if (cp[1] == com)
196+ skipesc += (flags & FPARSELN_UNESCCOMM);
197+ if (cp[1] == con)
198+ skipesc += (flags & FPARSELN_UNESCCONT);
199+ if (cp[1] == esc)
200+ skipesc += (flags & FPARSELN_UNESCESC);
201+ if (cp[1] != com && cp[1] != con && cp[1] != esc)
202+ skipesc = (flags & FPARSELN_UNESCREST);
203+
204+ if (skipesc)
205+ cp++;
206+ else
207+ *ptr++ = *cp++;
208+ *ptr++ = *cp++;
209+ }
210+ *ptr = '\0';
211+ len = strlen(buf);
212+ }
213+
214+ if (size)
215+ *size = len;
216+ return buf;
217+}
218+
219+#ifdef TEST
220+
221+int main(int, char **);
222+
223+int
224+main(int argc, char **argv)
225+{
226+ char *ptr;
227+ size_t size, line;
228+
229+ line = 0;
230+ while ((ptr = fparseln(stdin, &size, &line, NULL,
231+ FPARSELN_UNESCALL)) != NULL)
232+ printf("line %d (%d) |%s|\n", line, size, ptr);
233+ return 0;
234+}
235+
236+/*
237+
238+# This is a test
239+line 1
240+line 2 \
241+line 3 # Comment
242+line 4 \# Not comment \\\\
243+
244+# And a comment \
245+line 5 \\\
246+line 6
247+
248+*/
249+
250+#endif /* TEST */
251+#endif /* ! HAVE_FPARSELN */
+64,
-0
1@@ -0,0 +1,64 @@
2+/* $NetBSD: getmode.c,v 1.6 2004/01/13 00:53:06 simonb Exp $ */
3+
4+/*-
5+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
6+ * All rights reserved.
7+ *
8+ * This code is derived from software contributed to The NetBSD Foundation
9+ * by Todd Vierling.
10+ *
11+ * Redistribution and use in source and binary forms, with or without
12+ * modification, are permitted provided that the following conditions
13+ * are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above copyright
17+ * notice, this list of conditions and the following disclaimer in the
18+ * documentation and/or other materials provided with the distribution.
19+ * 3. All advertising materials mentioning features or use of this software
20+ * must display the following acknowledgement:
21+ * This product includes software developed by the NetBSD
22+ * Foundation, Inc. and its contributors.
23+ * 4. Neither the name of The NetBSD Foundation nor the names of its
24+ * contributors may be used to endorse or promote products derived
25+ * from this software without specific prior written permission.
26+ *
27+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37+ * POSSIBILITY OF SUCH DAMAGE.
38+ */
39+
40+#include "nbtool_config.h"
41+#include "netcompat.h"
42+#include <stdlib.h>
43+
44+void *
45+setmode(const char *str)
46+{
47+ mode_t *mp = malloc(sizeof(mode_t));
48+
49+ *mp = strtoul(str, NULL, 8);
50+
51+ return mp;
52+}
53+
54+mode_t
55+getmode(const void *mp, mode_t mode)
56+{
57+ mode_t m;
58+
59+ m = *((const mode_t *)mp);
60+
61+ mode &= ~ALLPERMS; /* input mode less RWX permissions */
62+ m &= ALLPERMS; /* new RWX permissions */
63+
64+ return m | mode;
65+}
+14,
-0
1@@ -0,0 +1,14 @@
2+/* $NetBSD: namespace.h,v 1.3 2003/10/27 00:12:43 lukem Exp $ */
3+
4+/*
5+ * Mainly empty header to make reachover bits of libc happy.
6+ *
7+ * Since all reachover bits will include this, it's a good place to pull
8+ * in nbtool_config.h.
9+ */
10+#include "nbtool_config.h"
11+
12+/* No aliases in reachover-based libc sources. */
13+#undef __indr_reference
14+#undef __weak_alias
15+#undef __warn_references
+31,
-0
1@@ -0,0 +1,31 @@
2+#ifndef __NETBSD_NBTOOL_CONFIG_H__
3+#define __NETBSD_NBTOOL_CONFIG_H__
4+
5+#define HAVE_NBTOOL_CONFIG_H 1
6+
7+#define PATH_BSHELL "/bin/sh"
8+
9+#define HAVE_FGETLN 0
10+#define HAVE_FPARSELN 0
11+#define HAVE_PWCACHE_USERDB 0
12+#define HAVE_SETPASSENT 0
13+#define HAVE_SETGROUPENT 0
14+#define HAVE_DECL_SETPASSENT 0
15+#define HAVE_DECL_SETGROUPENT 0
16+#define HAVE_SETPROGNAME 0
17+#define HAVE_STRSUFTOLL 0
18+#define HAVE_VIS 0
19+#define HAVE_SVIS 0
20+
21+#define HAVE_STRUCT_STAT_ST_FLAGS 0
22+#define HAVE_STRUCT_STAT_ST_GEN 0
23+#define HAVE_STRUCT_STAT_BIRTHTIME 0
24+#define HAVE_STRUCT_STAT_ST_MTIMENSEC 0
25+#define HAVE_STRUCT_STATVFS_F_IOSIZE 0
26+#define HAVE_FSTATVFS 1
27+#define HAVE_STRUCT_TM_TM_GMTOFF 1
28+
29+#define HAVE_SYS_ENDIAN_H 1
30+#define HAVE_STRTOLL 1
31+
32+#endif
+76,
-2
1@@ -22,9 +22,15 @@
2 #include <inttypes.h>
3 #include <stdint.h>
4 #include <stdarg.h>
5+#include <limits.h>
6 #include <time.h>
7+#include <sys/time.h>
8+#include <sys/types.h>
9+#include <grp.h>
10 #include <pwd.h>
11 #include <byteswap.h>
12+#include <sys/stat.h>
13+#include <sys/sysmacros.h>
14
15 #ifndef __RCSID
16 #define __RCSID(x)
17@@ -67,14 +73,58 @@
18 #define __weak_alias(sym, alias)
19 #endif
20
21+#ifndef NETCOMPAT_UNUSED
22+#if defined(__GNUC__) || defined(__clang__)
23+#define NETCOMPAT_UNUSED __attribute__((__unused__))
24+#else
25+#define NETCOMPAT_UNUSED
26+#endif
27+#endif
28+
29 #ifndef __UNCONST
30 #define __UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
31 #endif
32
33+#ifndef __CAST
34+#define __CAST(dt, st) ((dt)(st))
35+#endif
36+
37+#ifndef __arraycount
38+#define __arraycount(__x) (sizeof(__x) / sizeof((__x)[0]))
39+#endif
40+
41+#ifndef __USE
42+#define __USE(a) ((void)(a))
43+#endif
44+
45 #ifndef sig_t
46 typedef void (*sig_t)(int);
47 #endif
48
49+#ifndef u_int
50+typedef unsigned int u_int;
51+#endif
52+
53+#ifndef u_long
54+typedef unsigned long u_long;
55+#endif
56+
57+#ifndef daddr_t
58+typedef int64_t daddr_t;
59+#endif
60+
61+#ifndef UID_MAX
62+#define UID_MAX UINT_MAX
63+#endif
64+
65+#ifndef GID_MAX
66+#define GID_MAX UINT_MAX
67+#endif
68+
69+#ifndef ALLPERMS
70+#define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
71+#endif
72+
73 #ifndef timespeccmp
74 #define timespeccmp(a, b, cmp) \
75 (((a)->tv_sec == (b)->tv_sec) ? \
76@@ -90,18 +140,40 @@ typedef void (*sig_t)(int);
77 } while (0)
78 #endif
79
80-#ifndef setpassent
81-#define setpassent(stayopen) ((void)(stayopen), setpwent())
82+#ifndef timersub
83+#define timersub(tvp, uvp, vvp) \
84+ do { \
85+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
86+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
87+ if ((vvp)->tv_usec < 0) { \
88+ (vvp)->tv_sec--; \
89+ (vvp)->tv_usec += 1000000; \
90+ } \
91+ } while (0)
92 #endif
93
94 #ifndef bswap32
95 #define bswap32 bswap_32
96 #endif
97
98+#ifndef bswap16
99+#define bswap16 bswap_16
100+#endif
101+
102 #ifndef bswap64
103 #define bswap64 bswap_64
104 #endif
105
106+#ifndef UF_APPEND
107+#define UF_APPEND 0
108+#define UF_IMMUTABLE 0
109+#define UF_NODUMP 0
110+#define UF_OPAQUE 0
111+#define SF_APPEND 0
112+#define SF_ARCHIVED 0
113+#define SF_IMMUTABLE 0
114+#endif
115+
116 extern const char *netcompat_progname;
117
118 const char *getprogname(void);
119@@ -116,5 +188,7 @@ void warnc(int, const char *, ...);
120 __dead void verrc(int, int, const char *, va_list);
121 __dead void errc(int, int, const char *, ...);
122 int raise_default_signal(int);
123+int setgroupent(int);
124+int setpassent(int);
125
126 #endif
+646,
-0
1@@ -0,0 +1,646 @@
2+/* $NetBSD: pwcache.c,v 1.29 2004/06/20 22:20:14 jmc Exp $ */
3+
4+/*-
5+ * Copyright (c) 1992 Keith Muller.
6+ * Copyright (c) 1992, 1993
7+ * The Regents of the University of California. All rights reserved.
8+ *
9+ * This code is derived from software contributed to Berkeley by
10+ * Keith Muller of the University of California, San Diego.
11+ *
12+ * Redistribution and use in source and binary forms, with or without
13+ * modification, are permitted provided that the following conditions
14+ * are met:
15+ * 1. Redistributions of source code must retain the above copyright
16+ * notice, this list of conditions and the following disclaimer.
17+ * 2. Redistributions in binary form must reproduce the above copyright
18+ * notice, this list of conditions and the following disclaimer in the
19+ * documentation and/or other materials provided with the distribution.
20+ * 3. Neither the name of the University nor the names of its contributors
21+ * may be used to endorse or promote products derived from this software
22+ * without specific prior written permission.
23+ *
24+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34+ * SUCH DAMAGE.
35+ */
36+
37+/*-
38+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
39+ * All rights reserved.
40+ *
41+ * Redistribution and use in source and binary forms, with or without
42+ * modification, are permitted provided that the following conditions
43+ * are met:
44+ * 1. Redistributions of source code must retain the above copyright
45+ * notice, this list of conditions and the following disclaimer.
46+ * 2. Redistributions in binary form must reproduce the above copyright
47+ * notice, this list of conditions and the following disclaimer in the
48+ * documentation and/or other materials provided with the distribution.
49+ * 3. All advertising materials mentioning features or use of this software
50+ * must display the following acknowledgement:
51+ * This product includes software developed by the NetBSD
52+ * Foundation, Inc. and its contributors.
53+ * 4. Neither the name of The NetBSD Foundation nor the names of its
54+ * contributors may be used to endorse or promote products derived
55+ * from this software without specific prior written permission.
56+ *
57+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67+ * POSSIBILITY OF SUCH DAMAGE.
68+ */
69+
70+#if HAVE_NBTOOL_CONFIG_H
71+#include "nbtool_config.h"
72+/*
73+ * XXX Undefine the renames of these functions so that we don't
74+ * XXX rename the versions found in the host's <pwd.h> by mistake!
75+ */
76+#undef group_from_gid
77+#undef user_from_uid
78+#endif
79+
80+#include <sys/cdefs.h>
81+#if defined(LIBC_SCCS) && !defined(lint)
82+#if 0
83+static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
84+#else
85+__RCSID("$NetBSD: pwcache.c,v 1.29 2004/06/20 22:20:14 jmc Exp $");
86+#endif
87+#endif /* LIBC_SCCS and not lint */
88+
89+#include "netcompat.h"
90+#include "namespace.h"
91+
92+#include <sys/types.h>
93+#include <sys/param.h>
94+
95+#include <assert.h>
96+#include <grp.h>
97+#include <pwd.h>
98+#include <stdio.h>
99+#include <stdlib.h>
100+#include <string.h>
101+#include <unistd.h>
102+
103+#ifdef __weak_alias
104+__weak_alias(user_from_uid,_user_from_uid)
105+__weak_alias(group_from_gid,_group_from_gid)
106+__weak_alias(pwcache_userdb,_pwcache_userdb)
107+__weak_alias(pwcache_groupdb,_pwcache_groupdb)
108+#endif
109+
110+#if !HAVE_PWCACHE_USERDB || HAVE_NBTOOL_CONFIG_H
111+#include "pwcache.h"
112+
113+/*
114+ * routines that control user, group, uid and gid caches (for the archive
115+ * member print routine).
116+ * IMPORTANT:
117+ * these routines cache BOTH hits and misses, a major performance improvement
118+ */
119+
120+/*
121+ * function pointers to various name lookup routines.
122+ * these may be changed as necessary.
123+ */
124+static int (*_pwcache_setgroupent)(int) = setgroupent;
125+static void (*_pwcache_endgrent)(void) = endgrent;
126+static struct group * (*_pwcache_getgrnam)(const char *) = getgrnam;
127+static struct group * (*_pwcache_getgrgid)(gid_t) = getgrgid;
128+static int (*_pwcache_setpassent)(int) = setpassent;
129+static void (*_pwcache_endpwent)(void) = endpwent;
130+static struct passwd * (*_pwcache_getpwnam)(const char *) = getpwnam;
131+static struct passwd * (*_pwcache_getpwuid)(uid_t) = getpwuid;
132+
133+/*
134+ * internal state
135+ */
136+static int pwopn; /* is password file open */
137+static int gropn; /* is group file open */
138+static UIDC **uidtb; /* uid to name cache */
139+static GIDC **gidtb; /* gid to name cache */
140+static UIDC **usrtb; /* user name to uid cache */
141+static GIDC **grptb; /* group name to gid cache */
142+
143+static int uidtb_fail; /* uidtb_start() failed ? */
144+static int gidtb_fail; /* gidtb_start() failed ? */
145+static int usrtb_fail; /* usrtb_start() failed ? */
146+static int grptb_fail; /* grptb_start() failed ? */
147+
148+
149+static u_int st_hash(const char *, size_t, int);
150+static int uidtb_start(void);
151+static int gidtb_start(void);
152+static int usrtb_start(void);
153+static int grptb_start(void);
154+
155+
156+static u_int
157+st_hash(const char *name, size_t len, int tabsz)
158+{
159+ u_int key = 0;
160+
161+ _DIAGASSERT(name != NULL);
162+
163+ while (len--) {
164+ key += *name++;
165+ key = (key << 8) | (key >> 24);
166+ }
167+
168+ return (key % tabsz);
169+}
170+
171+/*
172+ * uidtb_start
173+ * creates an an empty uidtb
174+ * Return:
175+ * 0 if ok, -1 otherwise
176+ */
177+static int
178+uidtb_start(void)
179+{
180+
181+ if (uidtb != NULL)
182+ return (0);
183+ if (uidtb_fail)
184+ return (-1);
185+ if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
186+ ++uidtb_fail;
187+ return (-1);
188+ }
189+ return (0);
190+}
191+
192+/*
193+ * gidtb_start
194+ * creates an an empty gidtb
195+ * Return:
196+ * 0 if ok, -1 otherwise
197+ */
198+static int
199+gidtb_start(void)
200+{
201+
202+ if (gidtb != NULL)
203+ return (0);
204+ if (gidtb_fail)
205+ return (-1);
206+ if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
207+ ++gidtb_fail;
208+ return (-1);
209+ }
210+ return (0);
211+}
212+
213+/*
214+ * usrtb_start
215+ * creates an an empty usrtb
216+ * Return:
217+ * 0 if ok, -1 otherwise
218+ */
219+static int
220+usrtb_start(void)
221+{
222+
223+ if (usrtb != NULL)
224+ return (0);
225+ if (usrtb_fail)
226+ return (-1);
227+ if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
228+ ++usrtb_fail;
229+ return (-1);
230+ }
231+ return (0);
232+}
233+
234+/*
235+ * grptb_start
236+ * creates an an empty grptb
237+ * Return:
238+ * 0 if ok, -1 otherwise
239+ */
240+static int
241+grptb_start(void)
242+{
243+
244+ if (grptb != NULL)
245+ return (0);
246+ if (grptb_fail)
247+ return (-1);
248+ if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
249+ ++grptb_fail;
250+ return (-1);
251+ }
252+ return (0);
253+}
254+
255+/*
256+ * user_from_uid()
257+ * caches the name (if any) for the uid. If noname clear, we always
258+ * return the stored name (if valid or invalid match).
259+ * We use a simple hash table.
260+ * Return
261+ * Pointer to stored name (or a empty string)
262+ */
263+const char *
264+user_from_uid(uid_t uid, int noname)
265+{
266+ struct passwd *pw;
267+ UIDC *ptr, **pptr;
268+
269+ if ((uidtb == NULL) && (uidtb_start() < 0))
270+ return (NULL);
271+
272+ /*
273+ * see if we have this uid cached
274+ */
275+ pptr = uidtb + (uid % UID_SZ);
276+ ptr = *pptr;
277+
278+ if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
279+ /*
280+ * have an entry for this uid
281+ */
282+ if (!noname || (ptr->valid == VALID))
283+ return (ptr->name);
284+ return (NULL);
285+ }
286+
287+ /*
288+ * No entry for this uid, we will add it
289+ */
290+ if (!pwopn) {
291+ if (_pwcache_setpassent != NULL)
292+ (*_pwcache_setpassent)(1);
293+ ++pwopn;
294+ }
295+
296+ if (ptr == NULL)
297+ *pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
298+
299+ if ((pw = (*_pwcache_getpwuid)(uid)) == NULL) {
300+ /*
301+ * no match for this uid in the local password file
302+ * a string that is the uid in numeric format
303+ */
304+ if (ptr == NULL)
305+ return (NULL);
306+ ptr->uid = uid;
307+ (void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid);
308+ ptr->valid = INVALID;
309+ if (noname)
310+ return (NULL);
311+ } else {
312+ /*
313+ * there is an entry for this uid in the password file
314+ */
315+ if (ptr == NULL)
316+ return (pw->pw_name);
317+ ptr->uid = uid;
318+ (void)strlcpy(ptr->name, pw->pw_name, UNMLEN);
319+ ptr->valid = VALID;
320+ }
321+ return (ptr->name);
322+}
323+
324+/*
325+ * group_from_gid()
326+ * caches the name (if any) for the gid. If noname clear, we always
327+ * return the stored name (if valid or invalid match).
328+ * We use a simple hash table.
329+ * Return
330+ * Pointer to stored name (or a empty string)
331+ */
332+const char *
333+group_from_gid(gid_t gid, int noname)
334+{
335+ struct group *gr;
336+ GIDC *ptr, **pptr;
337+
338+ if ((gidtb == NULL) && (gidtb_start() < 0))
339+ return (NULL);
340+
341+ /*
342+ * see if we have this gid cached
343+ */
344+ pptr = gidtb + (gid % GID_SZ);
345+ ptr = *pptr;
346+
347+ if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
348+ /*
349+ * have an entry for this gid
350+ */
351+ if (!noname || (ptr->valid == VALID))
352+ return (ptr->name);
353+ return (NULL);
354+ }
355+
356+ /*
357+ * No entry for this gid, we will add it
358+ */
359+ if (!gropn) {
360+ if (_pwcache_setgroupent != NULL)
361+ (*_pwcache_setgroupent)(1);
362+ ++gropn;
363+ }
364+
365+ if (ptr == NULL)
366+ *pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
367+
368+ if ((gr = (*_pwcache_getgrgid)(gid)) == NULL) {
369+ /*
370+ * no match for this gid in the local group file, put in
371+ * a string that is the gid in numberic format
372+ */
373+ if (ptr == NULL)
374+ return (NULL);
375+ ptr->gid = gid;
376+ (void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid);
377+ ptr->valid = INVALID;
378+ if (noname)
379+ return (NULL);
380+ } else {
381+ /*
382+ * there is an entry for this group in the group file
383+ */
384+ if (ptr == NULL)
385+ return (gr->gr_name);
386+ ptr->gid = gid;
387+ (void)strlcpy(ptr->name, gr->gr_name, GNMLEN);
388+ ptr->valid = VALID;
389+ }
390+ return (ptr->name);
391+}
392+
393+/*
394+ * uid_from_user()
395+ * caches the uid for a given user name. We use a simple hash table.
396+ * Return
397+ * the uid (if any) for a user name, or a -1 if no match can be found
398+ */
399+int
400+uid_from_user(const char *name, uid_t *uid)
401+{
402+ struct passwd *pw;
403+ UIDC *ptr, **pptr;
404+ size_t namelen;
405+
406+ /*
407+ * return -1 for mangled names
408+ */
409+ if (name == NULL || ((namelen = strlen(name)) == 0))
410+ return (-1);
411+ if ((usrtb == NULL) && (usrtb_start() < 0))
412+ return (-1);
413+
414+ /*
415+ * look up in hash table, if found and valid return the uid,
416+ * if found and invalid, return a -1
417+ */
418+ pptr = usrtb + st_hash(name, namelen, UNM_SZ);
419+ ptr = *pptr;
420+
421+ if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
422+ if (ptr->valid == INVALID)
423+ return (-1);
424+ *uid = ptr->uid;
425+ return (0);
426+ }
427+
428+ if (!pwopn) {
429+ if (_pwcache_setpassent != NULL)
430+ (*_pwcache_setpassent)(1);
431+ ++pwopn;
432+ }
433+
434+ if (ptr == NULL)
435+ *pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
436+
437+ /*
438+ * no match, look it up, if no match store it as an invalid entry,
439+ * or store the matching uid
440+ */
441+ if (ptr == NULL) {
442+ if ((pw = (*_pwcache_getpwnam)(name)) == NULL)
443+ return (-1);
444+ *uid = pw->pw_uid;
445+ return (0);
446+ }
447+ (void)strlcpy(ptr->name, name, UNMLEN);
448+ if ((pw = (*_pwcache_getpwnam)(name)) == NULL) {
449+ ptr->valid = INVALID;
450+ return (-1);
451+ }
452+ ptr->valid = VALID;
453+ *uid = ptr->uid = pw->pw_uid;
454+ return (0);
455+}
456+
457+/*
458+ * gid_from_group()
459+ * caches the gid for a given group name. We use a simple hash table.
460+ * Return
461+ * the gid (if any) for a group name, or a -1 if no match can be found
462+ */
463+int
464+gid_from_group(const char *name, gid_t *gid)
465+{
466+ struct group *gr;
467+ GIDC *ptr, **pptr;
468+ size_t namelen;
469+
470+ /*
471+ * return -1 for mangled names
472+ */
473+ if (name == NULL || ((namelen = strlen(name)) == 0))
474+ return (-1);
475+ if ((grptb == NULL) && (grptb_start() < 0))
476+ return (-1);
477+
478+ /*
479+ * look up in hash table, if found and valid return the uid,
480+ * if found and invalid, return a -1
481+ */
482+ pptr = grptb + st_hash(name, namelen, GID_SZ);
483+ ptr = *pptr;
484+
485+ if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
486+ if (ptr->valid == INVALID)
487+ return (-1);
488+ *gid = ptr->gid;
489+ return (0);
490+ }
491+
492+ if (!gropn) {
493+ if (_pwcache_setgroupent != NULL)
494+ (*_pwcache_setgroupent)(1);
495+ ++gropn;
496+ }
497+
498+ if (ptr == NULL)
499+ *pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
500+
501+ /*
502+ * no match, look it up, if no match store it as an invalid entry,
503+ * or store the matching gid
504+ */
505+ if (ptr == NULL) {
506+ if ((gr = (*_pwcache_getgrnam)(name)) == NULL)
507+ return (-1);
508+ *gid = gr->gr_gid;
509+ return (0);
510+ }
511+
512+ (void)strlcpy(ptr->name, name, GNMLEN);
513+ if ((gr = (*_pwcache_getgrnam)(name)) == NULL) {
514+ ptr->valid = INVALID;
515+ return (-1);
516+ }
517+ ptr->valid = VALID;
518+ *gid = ptr->gid = gr->gr_gid;
519+ return (0);
520+}
521+
522+#define FLUSHTB(arr, len, fail) \
523+ do { \
524+ if (arr != NULL) { \
525+ for (i = 0; i < len; i++) \
526+ if (arr[i] != NULL) \
527+ free(arr[i]); \
528+ arr = NULL; \
529+ } \
530+ fail = 0; \
531+ } while (/* CONSTCOND */0);
532+
533+int
534+pwcache_userdb(
535+ int (*a_setpassent)(int),
536+ void (*a_endpwent)(void),
537+ struct passwd * (*a_getpwnam)(const char *),
538+ struct passwd * (*a_getpwuid)(uid_t))
539+{
540+ int i;
541+
542+ /* a_setpassent and a_endpwent may be NULL */
543+ if (a_getpwnam == NULL || a_getpwuid == NULL)
544+ return (-1);
545+
546+ if (_pwcache_endpwent != NULL)
547+ (*_pwcache_endpwent)();
548+ FLUSHTB(uidtb, UID_SZ, uidtb_fail);
549+ FLUSHTB(usrtb, UNM_SZ, usrtb_fail);
550+ pwopn = 0;
551+ _pwcache_setpassent = a_setpassent;
552+ _pwcache_endpwent = a_endpwent;
553+ _pwcache_getpwnam = a_getpwnam;
554+ _pwcache_getpwuid = a_getpwuid;
555+
556+ return (0);
557+}
558+
559+int
560+pwcache_groupdb(
561+ int (*a_setgroupent)(int),
562+ void (*a_endgrent)(void),
563+ struct group * (*a_getgrnam)(const char *),
564+ struct group * (*a_getgrgid)(gid_t))
565+{
566+ int i;
567+
568+ /* a_setgroupent and a_endgrent may be NULL */
569+ if (a_getgrnam == NULL || a_getgrgid == NULL)
570+ return (-1);
571+
572+ if (_pwcache_endgrent != NULL)
573+ (*_pwcache_endgrent)();
574+ FLUSHTB(gidtb, GID_SZ, gidtb_fail);
575+ FLUSHTB(grptb, GNM_SZ, grptb_fail);
576+ gropn = 0;
577+ _pwcache_setgroupent = a_setgroupent;
578+ _pwcache_endgrent = a_endgrent;
579+ _pwcache_getgrnam = a_getgrnam;
580+ _pwcache_getgrgid = a_getgrgid;
581+
582+ return (0);
583+}
584+
585+
586+#ifdef TEST_PWCACHE
587+
588+struct passwd *
589+test_getpwnam(const char *name)
590+{
591+ static struct passwd foo;
592+
593+ memset(&foo, 0, sizeof(foo));
594+ if (strcmp(name, "toor") == 0) {
595+ foo.pw_uid = 666;
596+ return &foo;
597+ }
598+ return (getpwnam(name));
599+}
600+
601+int
602+main(int argc, char *argv[])
603+{
604+ uid_t u;
605+ int r, i;
606+
607+ printf("pass 1 (default userdb)\n");
608+ for (i = 1; i < argc; i++) {
609+ printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
610+ i, pwopn, usrtb_fail, usrtb);
611+ r = uid_from_user(argv[i], &u);
612+ if (r == -1)
613+ printf(" uid_from_user %s: failed\n", argv[i]);
614+ else
615+ printf(" uid_from_user %s: %d\n", argv[i], u);
616+ }
617+ printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n",
618+ pwopn, usrtb_fail, usrtb);
619+
620+ puts("");
621+ printf("pass 2 (replacement userdb)\n");
622+ printf("pwcache_userdb returned %d\n",
623+ pwcache_userdb(setpassent, test_getpwnam, getpwuid));
624+ printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn, usrtb_fail, usrtb);
625+
626+ for (i = 1; i < argc; i++) {
627+ printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
628+ i, pwopn, usrtb_fail, usrtb);
629+ u = -1;
630+ r = uid_from_user(argv[i], &u);
631+ if (r == -1)
632+ printf(" uid_from_user %s: failed\n", argv[i]);
633+ else
634+ printf(" uid_from_user %s: %d\n", argv[i], u);
635+ }
636+ printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n",
637+ pwopn, usrtb_fail, usrtb);
638+
639+ puts("");
640+ printf("pass 3 (null pointers)\n");
641+ printf("pwcache_userdb returned %d\n",
642+ pwcache_userdb(NULL, NULL, NULL));
643+
644+ return (0);
645+}
646+#endif /* TEST_PWCACHE */
647+#endif /* !HAVE_PWCACHE_USERDB */
+72,
-0
1@@ -0,0 +1,72 @@
2+/* $NetBSD: pwcache.h,v 1.5 2003/11/10 08:51:51 wiz Exp $ */
3+
4+/*-
5+ * Copyright (c) 1992 Keith Muller.
6+ * Copyright (c) 1992, 1993
7+ * The Regents of the University of California. All rights reserved.
8+ *
9+ * This code is derived from software contributed to Berkeley by
10+ * Keith Muller of the University of California, San Diego.
11+ *
12+ * Redistribution and use in source and binary forms, with or without
13+ * modification, are permitted provided that the following conditions
14+ * are met:
15+ * 1. Redistributions of source code must retain the above copyright
16+ * notice, this list of conditions and the following disclaimer.
17+ * 2. Redistributions in binary form must reproduce the above copyright
18+ * notice, this list of conditions and the following disclaimer in the
19+ * documentation and/or other materials provided with the distribution.
20+ * 3. Neither the name of the University nor the names of its contributors
21+ * may be used to endorse or promote products derived from this software
22+ * without specific prior written permission.
23+ *
24+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34+ * SUCH DAMAGE.
35+ *
36+ * @(#)cache.h 8.1 (Berkeley) 5/31/93
37+ */
38+
39+/*
40+ * Constants and data structures used to implement group and password file
41+ * caches. Traditional passwd/group cache routines perform quite poorly with
42+ * archives. The chances of hitting a valid lookup with an archive is quite a
43+ * bit worse than with files already resident on the file system. These misses
44+ * create a MAJOR performance cost. To address this problem, these routines
45+ * cache both hits and misses.
46+ *
47+ * NOTE: name lengths must be as large as those stored in ANY PROTOCOL and
48+ * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME
49+ */
50+#define UNMLEN 32 /* >= user name found in any protocol */
51+#define GNMLEN 32 /* >= group name found in any protocol */
52+#define UID_SZ 317 /* size of uid to user_name cache */
53+#define UNM_SZ 317 /* size of user_name to uid cache */
54+#define GID_SZ 251 /* size of gid to group_name cache */
55+#define GNM_SZ 251 /* size of group_name to gid cache */
56+#define VALID 1 /* entry and name are valid */
57+#define INVALID 2 /* entry valid, name NOT valid */
58+
59+/*
60+ * Node structures used in the user, group, uid, and gid caches.
61+ */
62+
63+typedef struct uidc {
64+ int valid; /* is this a valid or a miss entry */
65+ char name[UNMLEN]; /* uid name */
66+ uid_t uid; /* cached uid */
67+} UIDC;
68+
69+typedef struct gidc {
70+ int valid; /* is this a valid or a miss entry */
71+ char name[GNMLEN]; /* gid name */
72+ gid_t gid; /* cached gid */
73+} GIDC;
+12,
-0
1@@ -0,0 +1,12 @@
2+/* $NetBSD: setgroupent.c,v 1.4 2003/10/27 00:12:43 lukem Exp $ */
3+
4+#include "nbtool_config.h"
5+
6+#if !HAVE_SETGROUPENT || !HAVE_DECL_SETGROUPENT
7+#include <grp.h>
8+
9+int setgroupent(int stayopen) {
10+ setgrent();
11+ return 1;
12+}
13+#endif
+12,
-0
1@@ -0,0 +1,12 @@
2+/* $NetBSD: setpassent.c,v 1.4 2003/10/27 00:12:43 lukem Exp $ */
3+
4+#include "nbtool_config.h"
5+
6+#if !HAVE_SETPASSENT || !HAVE_DECL_SETPASSENT
7+#include <pwd.h>
8+
9+int setpassent(int stayopen) {
10+ setpwent();
11+ return 1;
12+}
13+#endif
+101,
-0
1@@ -0,0 +1,101 @@
2+/* $NetBSD: strlcat.c,v 1.5 2024/11/01 21:11:37 riastradh Exp $ */
3+/* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */
4+
5+/*
6+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
7+ *
8+ * Permission to use, copy, modify, and distribute this software for any
9+ * purpose with or without fee is hereby granted, provided that the above
10+ * copyright notice and this permission notice appear in all copies.
11+ *
12+ * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL
13+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
14+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE
15+ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
17+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19+ */
20+
21+#if !defined(_KERNEL) && !defined(_STANDALONE)
22+#if HAVE_NBTOOL_CONFIG_H
23+#include "nbtool_config.h"
24+#endif
25+
26+#include <sys/cdefs.h>
27+#if defined(LIBC_SCCS) && !defined(lint)
28+__RCSID("$NetBSD: strlcat.c,v 1.5 2024/11/01 21:11:37 riastradh Exp $");
29+#endif /* LIBC_SCCS and not lint */
30+
31+#ifdef _LIBC
32+#include "namespace.h"
33+#endif
34+#include <sys/types.h>
35+#include <assert.h>
36+#include <string.h>
37+
38+#ifdef _LIBC
39+# ifdef __weak_alias
40+__weak_alias(strlcat, _strlcat)
41+# endif
42+#endif
43+
44+#else
45+#include <lib/libkern/libkern.h>
46+#endif /* !_KERNEL && !_STANDALONE */
47+
48+#if !HAVE_STRLCAT
49+/*
50+ * Appends src to string dst of size siz (unlike strncat, siz is the
51+ * full size of dst, not space left). At most siz-1 characters
52+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
53+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
54+ * If retval >= siz, truncation occurred.
55+ */
56+size_t
57+strlcat(char *__restrict dst, const char *__restrict src, size_t siz)
58+{
59+#if 1
60+ char *d = dst;
61+ const char *s = src;
62+ size_t n = siz;
63+ size_t dlen;
64+
65+ _DIAGASSERT(dst != NULL);
66+ _DIAGASSERT(src != NULL);
67+
68+ /* Find the end of dst and adjust bytes left but don't go past end */
69+ while (n-- != 0 && *d != '\0')
70+ d++;
71+ dlen = d - dst;
72+ n = siz - dlen;
73+
74+ if (n == 0)
75+ return(dlen + strlen(s));
76+ while (*s != '\0') {
77+ if (n != 1) {
78+ *d++ = *s;
79+ n--;
80+ }
81+ s++;
82+ }
83+ *d = '\0';
84+
85+ return(dlen + (s - src)); /* count does not include NUL */
86+#else
87+ _DIAGASSERT(dst != NULL);
88+ _DIAGASSERT(src != NULL);
89+
90+ /*
91+ * Find length of string in dst (maxing out at siz).
92+ */
93+ size_t dlen = strnlen(dst, siz);
94+
95+ /*
96+ * Copy src into any remaining space in dst (truncating if needed).
97+ * Note strlcpy(dst, src, 0) returns strlen(src).
98+ */
99+ return dlen + strlcpy(dst + dlen, src, siz - dlen);
100+#endif
101+}
102+#endif
+250,
-0
1@@ -0,0 +1,250 @@
2+/* $NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $ */
3+/*-
4+ * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
5+ * All rights reserved.
6+ *
7+ * This code is derived from software contributed to The NetBSD Foundation
8+ * by Luke Mewburn.
9+ *
10+ * Redistribution and use in source and binary forms, with or without
11+ * modification, are permitted provided that the following conditions
12+ * are met:
13+ * 1. Redistributions of source code must retain the above copyright
14+ * notice, this list of conditions and the following disclaimer.
15+ * 2. Redistributions in binary form must reproduce the above copyright
16+ * notice, this list of conditions and the following disclaimer in the
17+ * documentation and/or other materials provided with the distribution.
18+ * 3. All advertising materials mentioning features or use of this software
19+ * must display the following acknowledgement:
20+ * This product includes software developed by the NetBSD
21+ * Foundation, Inc. and its contributors.
22+ * 4. Neither the name of The NetBSD Foundation nor the names of its
23+ * contributors may be used to endorse or promote products derived
24+ * from this software without specific prior written permission.
25+ *
26+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36+ * POSSIBILITY OF SUCH DAMAGE.
37+ */
38+/*-
39+ * Copyright (c) 1991, 1993, 1994
40+ * The Regents of the University of California. All rights reserved.
41+ *
42+ * This code is derived from software contributed to Berkeley by
43+ * Keith Muller of the University of California, San Diego and Lance
44+ * Visser of Convex Computer Corporation.
45+ *
46+ * Redistribution and use in source and binary forms, with or without
47+ * modification, are permitted provided that the following conditions
48+ * are met:
49+ * 1. Redistributions of source code must retain the above copyright
50+ * notice, this list of conditions and the following disclaimer.
51+ * 2. Redistributions in binary form must reproduce the above copyright
52+ * notice, this list of conditions and the following disclaimer in the
53+ * documentation and/or other materials provided with the distribution.
54+ * 3. Neither the name of the University nor the names of its contributors
55+ * may be used to endorse or promote products derived from this software
56+ * without specific prior written permission.
57+ *
58+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68+ * SUCH DAMAGE.
69+ */
70+
71+#if HAVE_NBTOOL_CONFIG_H
72+#include "nbtool_config.h"
73+#endif
74+
75+#include <sys/cdefs.h>
76+
77+#if defined(LIBC_SCCS) && !defined(lint)
78+__RCSID("$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $");
79+#endif /* LIBC_SCCS and not lint */
80+
81+#ifdef _LIBC
82+#include "namespace.h"
83+#endif
84+
85+#if !HAVE_STRSUFTOLL
86+
87+#include <sys/types.h>
88+#include <sys/time.h>
89+
90+#include <assert.h>
91+#include <ctype.h>
92+#include <err.h>
93+#include <errno.h>
94+#include <limits.h>
95+#include <stdio.h>
96+#include <stdlib.h>
97+#include <string.h>
98+
99+#ifdef _LIBC
100+# ifdef __weak_alias
101+__weak_alias(strsuftoll, _strsuftoll)
102+__weak_alias(strsuftollx, _strsuftollx)
103+# endif
104+#endif /* LIBC */
105+
106+long long strsuftollx(const char *, const char *, long long, long long,
107+ char *, size_t);
108+
109+/*
110+ * Convert an expression of the following forms to a (u)int64_t.
111+ * 1) A positive decimal number.
112+ * 2) A positive decimal number followed by a b (mult by 512).
113+ * 3) A positive decimal number followed by a k (mult by 1024).
114+ * 4) A positive decimal number followed by a m (mult by 1048576).
115+ * 5) A positive decimal number followed by a g (mult by 1073741824).
116+ * 6) A positive decimal number followed by a t (mult by 1099511627776).
117+ * 7) A positive decimal number followed by a w (mult by sizeof int)
118+ * 8) Two or more positive decimal numbers (with/without k,b or w).
119+ * separated by x (also * for backwards compatibility), specifying
120+ * the product of the indicated values.
121+ * Returns the result upon successful conversion, or exits with an
122+ * appropriate error.
123+ *
124+ */
125+/* LONGLONG */
126+long long
127+strsuftoll(const char *desc, const char *val,
128+ long long min, long long max)
129+{
130+ long long result;
131+ char errbuf[100];
132+
133+ result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
134+ if (*errbuf != '\0')
135+ errx(1, "%s", errbuf);
136+ return (result);
137+}
138+
139+/*
140+ * As strsuftoll(), but returns the error message into the provided buffer
141+ * rather than exiting with it.
142+ */
143+/* LONGLONG */
144+long long
145+strsuftollx(const char *desc, const char *val,
146+ long long min, long long max, char *ebuf, size_t ebuflen)
147+{
148+ long long num, t;
149+ char *expr;
150+
151+ _DIAGASSERT(desc != NULL);
152+ _DIAGASSERT(val != NULL);
153+ _DIAGASSERT(ebuf != NULL);
154+
155+ errno = 0;
156+ ebuf[0] = '\0';
157+
158+ while (isspace((unsigned char)*val)) /* Skip leading space */
159+ val++;
160+
161+ num = strtoll(val, &expr, 10);
162+ if (errno == ERANGE)
163+ goto erange; /* Overflow */
164+
165+ if (expr == val) /* No digits */
166+ goto badnum;
167+
168+ switch (*expr) {
169+ case 'b':
170+ t = num;
171+ num *= 512; /* 1 block */
172+ if (t > num)
173+ goto erange;
174+ ++expr;
175+ break;
176+ case 'k':
177+ t = num;
178+ num *= 1024; /* 1 kilobyte */
179+ if (t > num)
180+ goto erange;
181+ ++expr;
182+ break;
183+ case 'm':
184+ t = num;
185+ num *= 1048576; /* 1 megabyte */
186+ if (t > num)
187+ goto erange;
188+ ++expr;
189+ break;
190+ case 'g':
191+ t = num;
192+ num *= 1073741824; /* 1 gigabyte */
193+ if (t > num)
194+ goto erange;
195+ ++expr;
196+ break;
197+ case 't':
198+ t = num;
199+ num *= 1099511627776LL; /* 1 terabyte */
200+ if (t > num)
201+ goto erange;
202+ ++expr;
203+ break;
204+ case 'w':
205+ t = num;
206+ num *= sizeof(int); /* 1 word */
207+ if (t > num)
208+ goto erange;
209+ ++expr;
210+ break;
211+ }
212+
213+ switch (*expr) {
214+ case '\0':
215+ break;
216+ case '*': /* Backward compatible */
217+ case 'x':
218+ t = num;
219+ num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
220+ if (*ebuf != '\0')
221+ return (0);
222+ if (t > num) {
223+ erange:
224+ snprintf(ebuf, ebuflen,
225+ "%s: %s", desc, strerror(ERANGE));
226+ return (0);
227+ }
228+ break;
229+ default:
230+ badnum: snprintf(ebuf, ebuflen,
231+ "%s `%s': illegal number", desc, val);
232+ return (0);
233+ }
234+ if (num < min) {
235+ /* LONGLONG */
236+ snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
237+ desc, (long long)num, (long long)min);
238+ return (0);
239+ }
240+ if (num > max) {
241+ /* LONGLONG */
242+ snprintf(ebuf, ebuflen,
243+ "%s %lld is greater than %lld.",
244+ desc, (long long)num, (long long)max);
245+ return (0);
246+ }
247+ *ebuf = '\0';
248+ return (num);
249+}
250+
251+#endif /* !HAVE_STRSUFTOLL */
+69,
-0
1@@ -0,0 +1,69 @@
2+/* $NetBSD: strtou.c,v 1.3 2019/11/28 12:33:23 roy Exp $ */
3+
4+/*-
5+ * Copyright (c) 2005 The DragonFly Project. All rights reserved.
6+ * Copyright (c) 2003 Citrus Project,
7+ * All rights reserved.
8+ *
9+ * Redistribution and use in source and binary forms, with or without
10+ * modification, are permitted provided that the following conditions
11+ * are met:
12+ * 1. Redistributions of source code must retain the above copyright
13+ * notice, this list of conditions and the following disclaimer.
14+ * 2. Redistributions in binary form must reproduce the above copyright
15+ * notice, this list of conditions and the following disclaimer in the
16+ * documentation and/or other materials provided with the distribution.
17+ *
18+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28+ * SUCH DAMAGE.
29+ *
30+ * Created by Kamil Rytarowski, based on ID:
31+ * NetBSD: src/common/lib/libc/stdlib/strtoul.c,v 1.3 2008/08/20 19:58:34 oster Exp
32+ */
33+
34+#if defined(HAVE_NBTOOL_CONFIG_H) && HAVE_NBTOOL_CONFIG_H
35+#include "nbtool_config.h"
36+#endif
37+
38+#include <sys/cdefs.h>
39+__RCSID("$NetBSD: strtou.c,v 1.3 2019/11/28 12:33:23 roy Exp $");
40+
41+#ifdef _LIBC
42+#include "namespace.h"
43+#endif
44+
45+#if defined(_KERNEL)
46+#include <sys/param.h>
47+#include <sys/types.h>
48+#include <lib/libkern/libkern.h>
49+#elif defined(_STANDALONE)
50+#include <sys/param.h>
51+#include <sys/types.h>
52+#include <lib/libkern/libkern.h>
53+#include <lib/libsa/stand.h>
54+#else
55+#include <stddef.h>
56+#include <assert.h>
57+#include <errno.h>
58+#include <inttypes.h>
59+#endif
60+
61+#define _FUNCNAME strtou
62+#define __TYPE uintmax_t
63+#define __WRAPPED strtoumax
64+
65+#include "_strtoi.h"
66+
67+#ifdef _LIBC
68+__weak_alias(strtou, _strtou)
69+__weak_alias(strtou_l, _strtou_l)
70+#endif
+61,
-0
1@@ -40,4 +40,65 @@
2 #define __THROW
3 #endif
4
5+#ifndef __P
6+#define __P(x) x
7+#endif
8+
9+#ifndef __RENAME
10+#define __RENAME(x)
11+#endif
12+
13+#ifndef __packed
14+#if defined(__GNUC__) || defined(__clang__)
15+#define __packed __attribute__((__packed__))
16+#else
17+#define __packed
18+#endif
19+#endif
20+
21+#ifndef __constfunc
22+#if defined(__GNUC__) || defined(__clang__)
23+#define __constfunc __attribute__((__const__))
24+#else
25+#define __constfunc
26+#endif
27+#endif
28+
29+#ifndef __RCSID
30+#define __RCSID(x)
31+#endif
32+
33+#ifndef __COPYRIGHT
34+#define __COPYRIGHT(x)
35+#endif
36+
37+#ifndef __dead
38+#if defined(__GNUC__) || defined(__clang__)
39+#define __dead __attribute__((__noreturn__))
40+#else
41+#define __dead
42+#endif
43+#endif
44+
45+#ifndef __printflike
46+#if defined(__GNUC__) || defined(__clang__)
47+#define __printflike(fmtarg, firstvararg) \
48+ __attribute__((__format__(__printf__, fmtarg, firstvararg)))
49+#else
50+#define __printflike(fmtarg, firstvararg)
51+#endif
52+#endif
53+
54+#ifndef __predict_false
55+#define __predict_false(exp) (exp)
56+#endif
57+
58+#ifndef __predict_true
59+#define __predict_true(exp) (exp)
60+#endif
61+
62+#ifndef _DIAGASSERT
63+#define _DIAGASSERT(exp) ((void)0)
64+#endif
65+
66 #endif
+140,
-0
1@@ -0,0 +1,140 @@
2+/* $NetBSD: endian.h,v 1.39 2026/01/08 15:39:08 nia Exp $ */
3+
4+#ifndef _SYS_ENDIAN_H_
5+#define _SYS_ENDIAN_H_
6+
7+#include <stdint.h>
8+#include <endian.h>
9+#include <byteswap.h>
10+#include <sys/cdefs.h>
11+
12+#define _LITTLE_ENDIAN 1234
13+#define _BIG_ENDIAN 4321
14+#define _PDP_ENDIAN 3412
15+
16+#ifndef LITTLE_ENDIAN
17+#define LITTLE_ENDIAN _LITTLE_ENDIAN
18+#endif
19+#ifndef BIG_ENDIAN
20+#define BIG_ENDIAN _BIG_ENDIAN
21+#endif
22+#ifndef PDP_ENDIAN
23+#define PDP_ENDIAN _PDP_ENDIAN
24+#endif
25+
26+#ifndef BYTE_ORDER
27+#if __BYTE_ORDER == __LITTLE_ENDIAN
28+#define BYTE_ORDER LITTLE_ENDIAN
29+#else
30+#define BYTE_ORDER BIG_ENDIAN
31+#endif
32+#endif
33+
34+#ifndef bswap16
35+#define bswap16 bswap_16
36+#endif
37+
38+#ifndef bswap32
39+#define bswap32 bswap_32
40+#endif
41+
42+#ifndef bswap64
43+#define bswap64 bswap_64
44+#endif
45+
46+#if BYTE_ORDER == BIG_ENDIAN
47+#ifndef htobe16
48+#define htobe16(x) __CAST(uint16_t, (x))
49+#endif
50+#ifndef htobe32
51+#define htobe32(x) __CAST(uint32_t, (x))
52+#endif
53+#ifndef htobe64
54+#define htobe64(x) __CAST(uint64_t, (x))
55+#endif
56+#ifndef htole16
57+#define htole16(x) bswap16(__CAST(uint16_t, (x)))
58+#endif
59+#ifndef htole32
60+#define htole32(x) bswap32(__CAST(uint32_t, (x)))
61+#endif
62+#ifndef htole64
63+#define htole64(x) bswap64(__CAST(uint64_t, (x)))
64+#endif
65+#else
66+#ifndef htobe16
67+#define htobe16(x) bswap16(__CAST(uint16_t, (x)))
68+#endif
69+#ifndef htobe32
70+#define htobe32(x) bswap32(__CAST(uint32_t, (x)))
71+#endif
72+#ifndef htobe64
73+#define htobe64(x) bswap64(__CAST(uint64_t, (x)))
74+#endif
75+#ifndef htole16
76+#define htole16(x) __CAST(uint16_t, (x))
77+#endif
78+#ifndef htole32
79+#define htole32(x) __CAST(uint32_t, (x))
80+#endif
81+#ifndef htole64
82+#define htole64(x) __CAST(uint64_t, (x))
83+#endif
84+#endif
85+
86+#ifndef be16toh
87+#define be16toh(x) htobe16(x)
88+#endif
89+#ifndef be32toh
90+#define be32toh(x) htobe32(x)
91+#endif
92+#ifndef be64toh
93+#define be64toh(x) htobe64(x)
94+#endif
95+#ifndef le16toh
96+#define le16toh(x) htole16(x)
97+#endif
98+#ifndef le32toh
99+#define le32toh(x) htole32(x)
100+#endif
101+#ifndef le64toh
102+#define le64toh(x) htole64(x)
103+#endif
104+
105+static __inline uint16_t NETCOMPAT_UNUSED
106+be16dec(const void *_buf)
107+{
108+ uint16_t u;
109+
110+ __builtin_memcpy(&u, _buf, sizeof(u));
111+ return be16toh(u);
112+}
113+
114+static __inline uint16_t NETCOMPAT_UNUSED
115+le16dec(const void *_buf)
116+{
117+ uint16_t u;
118+
119+ __builtin_memcpy(&u, _buf, sizeof(u));
120+ return le16toh(u);
121+}
122+
123+static __inline uint32_t NETCOMPAT_UNUSED
124+be32dec(const void *_buf)
125+{
126+ uint32_t u;
127+
128+ __builtin_memcpy(&u, _buf, sizeof(u));
129+ return be32toh(u);
130+}
131+
132+static __inline uint32_t NETCOMPAT_UNUSED
133+le32dec(const void *_buf)
134+{
135+ uint32_t u;
136+
137+ __builtin_memcpy(&u, _buf, sizeof(u));
138+ return le32toh(u);
139+}
140+
141+#endif
+612,
-0
1@@ -0,0 +1,612 @@
2+/* $NetBSD: queue.h,v 1.39 2004/04/18 14:25:34 lukem Exp $ */
3+
4+/*
5+ * Copyright (c) 1991, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ *
32+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
33+ */
34+
35+#ifndef _SYS_QUEUE_H_
36+#define _SYS_QUEUE_H_
37+
38+/*
39+ * This file defines five types of data structures: singly-linked lists,
40+ * lists, simple queues, tail queues, and circular queues.
41+ *
42+ * A singly-linked list is headed by a single forward pointer. The
43+ * elements are singly linked for minimum space and pointer manipulation
44+ * overhead at the expense of O(n) removal for arbitrary elements. New
45+ * elements can be added to the list after an existing element or at the
46+ * head of the list. Elements being removed from the head of the list
47+ * should use the explicit macro for this purpose for optimum
48+ * efficiency. A singly-linked list may only be traversed in the forward
49+ * direction. Singly-linked lists are ideal for applications with large
50+ * datasets and few or no removals or for implementing a LIFO queue.
51+ *
52+ * A list is headed by a single forward pointer (or an array of forward
53+ * pointers for a hash table header). The elements are doubly linked
54+ * so that an arbitrary element can be removed without a need to
55+ * traverse the list. New elements can be added to the list before
56+ * or after an existing element or at the head of the list. A list
57+ * may only be traversed in the forward direction.
58+ *
59+ * A simple queue is headed by a pair of pointers, one the head of the
60+ * list and the other to the tail of the list. The elements are singly
61+ * linked to save space, so only elements can only be removed from the
62+ * head of the list. New elements can be added to the list after
63+ * an existing element, at the head of the list, or at the end of the
64+ * list. A simple queue may only be traversed in the forward direction.
65+ *
66+ * A tail queue is headed by a pair of pointers, one to the head of the
67+ * list and the other to the tail of the list. The elements are doubly
68+ * linked so that an arbitrary element can be removed without a need to
69+ * traverse the list. New elements can be added to the list before or
70+ * after an existing element, at the head of the list, or at the end of
71+ * the list. A tail queue may be traversed in either direction.
72+ *
73+ * A circle queue is headed by a pair of pointers, one to the head of the
74+ * list and the other to the tail of the list. The elements are doubly
75+ * linked so that an arbitrary element can be removed without a need to
76+ * traverse the list. New elements can be added to the list before or after
77+ * an existing element, at the head of the list, or at the end of the list.
78+ * A circle queue may be traversed in either direction, but has a more
79+ * complex end of list detection.
80+ *
81+ * For details on the use of these macros, see the queue(3) manual page.
82+ */
83+
84+/*
85+ * List definitions.
86+ */
87+#define LIST_HEAD(name, type) \
88+struct name { \
89+ struct type *lh_first; /* first element */ \
90+}
91+
92+#define LIST_HEAD_INITIALIZER(head) \
93+ { NULL }
94+
95+#define LIST_ENTRY(type) \
96+struct { \
97+ struct type *le_next; /* next element */ \
98+ struct type **le_prev; /* address of previous next element */ \
99+}
100+
101+/*
102+ * List functions.
103+ */
104+#if defined(_KERNEL) && defined(QUEUEDEBUG)
105+#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \
106+ if ((head)->lh_first && \
107+ (head)->lh_first->field.le_prev != &(head)->lh_first) \
108+ panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__);
109+#define QUEUEDEBUG_LIST_OP(elm, field) \
110+ if ((elm)->field.le_next && \
111+ (elm)->field.le_next->field.le_prev != \
112+ &(elm)->field.le_next) \
113+ panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\
114+ if (*(elm)->field.le_prev != (elm)) \
115+ panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__);
116+#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \
117+ (elm)->field.le_next = (void *)1L; \
118+ (elm)->field.le_prev = (void *)1L;
119+#else
120+#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
121+#define QUEUEDEBUG_LIST_OP(elm, field)
122+#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
123+#endif
124+
125+#define LIST_INIT(head) do { \
126+ (head)->lh_first = NULL; \
127+} while (/*CONSTCOND*/0)
128+
129+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
130+ QUEUEDEBUG_LIST_OP((listelm), field) \
131+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
132+ (listelm)->field.le_next->field.le_prev = \
133+ &(elm)->field.le_next; \
134+ (listelm)->field.le_next = (elm); \
135+ (elm)->field.le_prev = &(listelm)->field.le_next; \
136+} while (/*CONSTCOND*/0)
137+
138+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
139+ QUEUEDEBUG_LIST_OP((listelm), field) \
140+ (elm)->field.le_prev = (listelm)->field.le_prev; \
141+ (elm)->field.le_next = (listelm); \
142+ *(listelm)->field.le_prev = (elm); \
143+ (listelm)->field.le_prev = &(elm)->field.le_next; \
144+} while (/*CONSTCOND*/0)
145+
146+#define LIST_INSERT_HEAD(head, elm, field) do { \
147+ QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \
148+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
149+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
150+ (head)->lh_first = (elm); \
151+ (elm)->field.le_prev = &(head)->lh_first; \
152+} while (/*CONSTCOND*/0)
153+
154+#define LIST_REMOVE(elm, field) do { \
155+ QUEUEDEBUG_LIST_OP((elm), field) \
156+ if ((elm)->field.le_next != NULL) \
157+ (elm)->field.le_next->field.le_prev = \
158+ (elm)->field.le_prev; \
159+ *(elm)->field.le_prev = (elm)->field.le_next; \
160+ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
161+} while (/*CONSTCOND*/0)
162+
163+#define LIST_FOREACH(var, head, field) \
164+ for ((var) = ((head)->lh_first); \
165+ (var); \
166+ (var) = ((var)->field.le_next))
167+
168+/*
169+ * List access methods.
170+ */
171+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
172+#define LIST_FIRST(head) ((head)->lh_first)
173+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
174+
175+
176+/*
177+ * Singly-linked List definitions.
178+ */
179+#define SLIST_HEAD(name, type) \
180+struct name { \
181+ struct type *slh_first; /* first element */ \
182+}
183+
184+#define SLIST_HEAD_INITIALIZER(head) \
185+ { NULL }
186+
187+#define SLIST_ENTRY(type) \
188+struct { \
189+ struct type *sle_next; /* next element */ \
190+}
191+
192+/*
193+ * Singly-linked List functions.
194+ */
195+#define SLIST_INIT(head) do { \
196+ (head)->slh_first = NULL; \
197+} while (/*CONSTCOND*/0)
198+
199+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
200+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
201+ (slistelm)->field.sle_next = (elm); \
202+} while (/*CONSTCOND*/0)
203+
204+#define SLIST_INSERT_HEAD(head, elm, field) do { \
205+ (elm)->field.sle_next = (head)->slh_first; \
206+ (head)->slh_first = (elm); \
207+} while (/*CONSTCOND*/0)
208+
209+#define SLIST_REMOVE_HEAD(head, field) do { \
210+ (head)->slh_first = (head)->slh_first->field.sle_next; \
211+} while (/*CONSTCOND*/0)
212+
213+#define SLIST_REMOVE(head, elm, type, field) do { \
214+ if ((head)->slh_first == (elm)) { \
215+ SLIST_REMOVE_HEAD((head), field); \
216+ } \
217+ else { \
218+ struct type *curelm = (head)->slh_first; \
219+ while(curelm->field.sle_next != (elm)) \
220+ curelm = curelm->field.sle_next; \
221+ curelm->field.sle_next = \
222+ curelm->field.sle_next->field.sle_next; \
223+ } \
224+} while (/*CONSTCOND*/0)
225+
226+#define SLIST_FOREACH(var, head, field) \
227+ for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
228+
229+/*
230+ * Singly-linked List access methods.
231+ */
232+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
233+#define SLIST_FIRST(head) ((head)->slh_first)
234+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
235+
236+
237+/*
238+ * Singly-linked Tail queue declarations.
239+ */
240+#define STAILQ_HEAD(name, type) \
241+struct name { \
242+ struct type *stqh_first; /* first element */ \
243+ struct type **stqh_last; /* addr of last next element */ \
244+}
245+
246+#define STAILQ_HEAD_INITIALIZER(head) \
247+ { NULL, &(head).stqh_first }
248+
249+#define STAILQ_ENTRY(type) \
250+struct { \
251+ struct type *stqe_next; /* next element */ \
252+}
253+
254+/*
255+ * Singly-linked Tail queue functions.
256+ */
257+#define STAILQ_INIT(head) do { \
258+ (head)->stqh_first = NULL; \
259+ (head)->stqh_last = &(head)->stqh_first; \
260+} while (/*CONSTCOND*/0)
261+
262+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
263+ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
264+ (head)->stqh_last = &(elm)->field.stqe_next; \
265+ (head)->stqh_first = (elm); \
266+} while (/*CONSTCOND*/0)
267+
268+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
269+ (elm)->field.stqe_next = NULL; \
270+ *(head)->stqh_last = (elm); \
271+ (head)->stqh_last = &(elm)->field.stqe_next; \
272+} while (/*CONSTCOND*/0)
273+
274+#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
275+ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
276+ (head)->stqh_last = &(elm)->field.stqe_next; \
277+ (listelm)->field.stqe_next = (elm); \
278+} while (/*CONSTCOND*/0)
279+
280+#define STAILQ_REMOVE_HEAD(head, field) do { \
281+ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
282+ (head)->stqh_last = &(head)->stqh_first; \
283+} while (/*CONSTCOND*/0)
284+
285+#define STAILQ_REMOVE(head, elm, type, field) do { \
286+ if ((head)->stqh_first == (elm)) { \
287+ STAILQ_REMOVE_HEAD((head), field); \
288+ } else { \
289+ struct type *curelm = (head)->stqh_first; \
290+ while (curelm->field.stqe_next != (elm)) \
291+ curelm = curelm->field.stqe_next; \
292+ if ((curelm->field.stqe_next = \
293+ curelm->field.stqe_next->field.stqe_next) == NULL) \
294+ (head)->stqh_last = &(curelm)->field.stqe_next; \
295+ } \
296+} while (/*CONSTCOND*/0)
297+
298+#define STAILQ_FOREACH(var, head, field) \
299+ for ((var) = ((head)->stqh_first); \
300+ (var); \
301+ (var) = ((var)->field.stqe_next))
302+
303+/*
304+ * Singly-linked Tail queue access methods.
305+ */
306+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
307+#define STAILQ_FIRST(head) ((head)->stqh_first)
308+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
309+
310+
311+/*
312+ * Simple queue definitions.
313+ */
314+#define SIMPLEQ_HEAD(name, type) \
315+struct name { \
316+ struct type *sqh_first; /* first element */ \
317+ struct type **sqh_last; /* addr of last next element */ \
318+}
319+
320+#define SIMPLEQ_HEAD_INITIALIZER(head) \
321+ { NULL, &(head).sqh_first }
322+
323+#define SIMPLEQ_ENTRY(type) \
324+struct { \
325+ struct type *sqe_next; /* next element */ \
326+}
327+
328+/*
329+ * Simple queue functions.
330+ */
331+#define SIMPLEQ_INIT(head) do { \
332+ (head)->sqh_first = NULL; \
333+ (head)->sqh_last = &(head)->sqh_first; \
334+} while (/*CONSTCOND*/0)
335+
336+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
337+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
338+ (head)->sqh_last = &(elm)->field.sqe_next; \
339+ (head)->sqh_first = (elm); \
340+} while (/*CONSTCOND*/0)
341+
342+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
343+ (elm)->field.sqe_next = NULL; \
344+ *(head)->sqh_last = (elm); \
345+ (head)->sqh_last = &(elm)->field.sqe_next; \
346+} while (/*CONSTCOND*/0)
347+
348+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
349+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
350+ (head)->sqh_last = &(elm)->field.sqe_next; \
351+ (listelm)->field.sqe_next = (elm); \
352+} while (/*CONSTCOND*/0)
353+
354+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
355+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
356+ (head)->sqh_last = &(head)->sqh_first; \
357+} while (/*CONSTCOND*/0)
358+
359+#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
360+ if ((head)->sqh_first == (elm)) { \
361+ SIMPLEQ_REMOVE_HEAD((head), field); \
362+ } else { \
363+ struct type *curelm = (head)->sqh_first; \
364+ while (curelm->field.sqe_next != (elm)) \
365+ curelm = curelm->field.sqe_next; \
366+ if ((curelm->field.sqe_next = \
367+ curelm->field.sqe_next->field.sqe_next) == NULL) \
368+ (head)->sqh_last = &(curelm)->field.sqe_next; \
369+ } \
370+} while (/*CONSTCOND*/0)
371+
372+#define SIMPLEQ_FOREACH(var, head, field) \
373+ for ((var) = ((head)->sqh_first); \
374+ (var); \
375+ (var) = ((var)->field.sqe_next))
376+
377+/*
378+ * Simple queue access methods.
379+ */
380+#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
381+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
382+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
383+
384+
385+/*
386+ * Tail queue definitions.
387+ */
388+#define TAILQ_HEAD(name, type) \
389+struct name { \
390+ struct type *tqh_first; /* first element */ \
391+ struct type **tqh_last; /* addr of last next element */ \
392+}
393+
394+#define TAILQ_HEAD_INITIALIZER(head) \
395+ { NULL, &(head).tqh_first }
396+
397+#define TAILQ_ENTRY(type) \
398+struct { \
399+ struct type *tqe_next; /* next element */ \
400+ struct type **tqe_prev; /* address of previous next element */ \
401+}
402+
403+/*
404+ * Tail queue functions.
405+ */
406+#if defined(_KERNEL) && defined(QUEUEDEBUG)
407+#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \
408+ if ((head)->tqh_first && \
409+ (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \
410+ panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__);
411+#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \
412+ if (*(head)->tqh_last != NULL) \
413+ panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__);
414+#define QUEUEDEBUG_TAILQ_OP(elm, field) \
415+ if ((elm)->field.tqe_next && \
416+ (elm)->field.tqe_next->field.tqe_prev != \
417+ &(elm)->field.tqe_next) \
418+ panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\
419+ if (*(elm)->field.tqe_prev != (elm)) \
420+ panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__);
421+#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \
422+ if ((elm)->field.tqe_next == NULL && \
423+ (head)->tqh_last != &(elm)->field.tqe_next) \
424+ panic("TAILQ_PREREMOVE head %p elm %p %s:%d", \
425+ (head), (elm), __FILE__, __LINE__);
426+#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \
427+ (elm)->field.tqe_next = (void *)1L; \
428+ (elm)->field.tqe_prev = (void *)1L;
429+#else
430+#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
431+#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
432+#define QUEUEDEBUG_TAILQ_OP(elm, field)
433+#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
434+#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
435+#endif
436+
437+#define TAILQ_INIT(head) do { \
438+ (head)->tqh_first = NULL; \
439+ (head)->tqh_last = &(head)->tqh_first; \
440+} while (/*CONSTCOND*/0)
441+
442+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
443+ QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \
444+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
445+ (head)->tqh_first->field.tqe_prev = \
446+ &(elm)->field.tqe_next; \
447+ else \
448+ (head)->tqh_last = &(elm)->field.tqe_next; \
449+ (head)->tqh_first = (elm); \
450+ (elm)->field.tqe_prev = &(head)->tqh_first; \
451+} while (/*CONSTCOND*/0)
452+
453+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
454+ QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \
455+ (elm)->field.tqe_next = NULL; \
456+ (elm)->field.tqe_prev = (head)->tqh_last; \
457+ *(head)->tqh_last = (elm); \
458+ (head)->tqh_last = &(elm)->field.tqe_next; \
459+} while (/*CONSTCOND*/0)
460+
461+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
462+ QUEUEDEBUG_TAILQ_OP((listelm), field) \
463+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
464+ (elm)->field.tqe_next->field.tqe_prev = \
465+ &(elm)->field.tqe_next; \
466+ else \
467+ (head)->tqh_last = &(elm)->field.tqe_next; \
468+ (listelm)->field.tqe_next = (elm); \
469+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
470+} while (/*CONSTCOND*/0)
471+
472+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
473+ QUEUEDEBUG_TAILQ_OP((listelm), field) \
474+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
475+ (elm)->field.tqe_next = (listelm); \
476+ *(listelm)->field.tqe_prev = (elm); \
477+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
478+} while (/*CONSTCOND*/0)
479+
480+#define TAILQ_REMOVE(head, elm, field) do { \
481+ QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \
482+ QUEUEDEBUG_TAILQ_OP((elm), field) \
483+ if (((elm)->field.tqe_next) != NULL) \
484+ (elm)->field.tqe_next->field.tqe_prev = \
485+ (elm)->field.tqe_prev; \
486+ else \
487+ (head)->tqh_last = (elm)->field.tqe_prev; \
488+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
489+ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
490+} while (/*CONSTCOND*/0)
491+
492+#define TAILQ_FOREACH(var, head, field) \
493+ for ((var) = ((head)->tqh_first); \
494+ (var); \
495+ (var) = ((var)->field.tqe_next))
496+
497+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
498+ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
499+ (var); \
500+ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
501+
502+/*
503+ * Tail queue access methods.
504+ */
505+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
506+#define TAILQ_FIRST(head) ((head)->tqh_first)
507+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
508+
509+#define TAILQ_LAST(head, headname) \
510+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
511+#define TAILQ_PREV(elm, headname, field) \
512+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
513+
514+
515+/*
516+ * Circular queue definitions.
517+ */
518+#define CIRCLEQ_HEAD(name, type) \
519+struct name { \
520+ struct type *cqh_first; /* first element */ \
521+ struct type *cqh_last; /* last element */ \
522+}
523+
524+#define CIRCLEQ_HEAD_INITIALIZER(head) \
525+ { (void *)&head, (void *)&head }
526+
527+#define CIRCLEQ_ENTRY(type) \
528+struct { \
529+ struct type *cqe_next; /* next element */ \
530+ struct type *cqe_prev; /* previous element */ \
531+}
532+
533+/*
534+ * Circular queue functions.
535+ */
536+#define CIRCLEQ_INIT(head) do { \
537+ (head)->cqh_first = (void *)(head); \
538+ (head)->cqh_last = (void *)(head); \
539+} while (/*CONSTCOND*/0)
540+
541+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
542+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
543+ (elm)->field.cqe_prev = (listelm); \
544+ if ((listelm)->field.cqe_next == (void *)(head)) \
545+ (head)->cqh_last = (elm); \
546+ else \
547+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
548+ (listelm)->field.cqe_next = (elm); \
549+} while (/*CONSTCOND*/0)
550+
551+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
552+ (elm)->field.cqe_next = (listelm); \
553+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
554+ if ((listelm)->field.cqe_prev == (void *)(head)) \
555+ (head)->cqh_first = (elm); \
556+ else \
557+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
558+ (listelm)->field.cqe_prev = (elm); \
559+} while (/*CONSTCOND*/0)
560+
561+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
562+ (elm)->field.cqe_next = (head)->cqh_first; \
563+ (elm)->field.cqe_prev = (void *)(head); \
564+ if ((head)->cqh_last == (void *)(head)) \
565+ (head)->cqh_last = (elm); \
566+ else \
567+ (head)->cqh_first->field.cqe_prev = (elm); \
568+ (head)->cqh_first = (elm); \
569+} while (/*CONSTCOND*/0)
570+
571+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
572+ (elm)->field.cqe_next = (void *)(head); \
573+ (elm)->field.cqe_prev = (head)->cqh_last; \
574+ if ((head)->cqh_first == (void *)(head)) \
575+ (head)->cqh_first = (elm); \
576+ else \
577+ (head)->cqh_last->field.cqe_next = (elm); \
578+ (head)->cqh_last = (elm); \
579+} while (/*CONSTCOND*/0)
580+
581+#define CIRCLEQ_REMOVE(head, elm, field) do { \
582+ if ((elm)->field.cqe_next == (void *)(head)) \
583+ (head)->cqh_last = (elm)->field.cqe_prev; \
584+ else \
585+ (elm)->field.cqe_next->field.cqe_prev = \
586+ (elm)->field.cqe_prev; \
587+ if ((elm)->field.cqe_prev == (void *)(head)) \
588+ (head)->cqh_first = (elm)->field.cqe_next; \
589+ else \
590+ (elm)->field.cqe_prev->field.cqe_next = \
591+ (elm)->field.cqe_next; \
592+} while (/*CONSTCOND*/0)
593+
594+#define CIRCLEQ_FOREACH(var, head, field) \
595+ for ((var) = ((head)->cqh_first); \
596+ (var) != (void *)(head); \
597+ (var) = ((var)->field.cqe_next))
598+
599+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
600+ for ((var) = ((head)->cqh_last); \
601+ (var) != (void *)(head); \
602+ (var) = ((var)->field.cqe_prev))
603+
604+/*
605+ * Circular queue access methods.
606+ */
607+#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
608+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
609+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
610+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
611+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
612+
613+#endif /* !_SYS_QUEUE_H_ */
+559,
-0
1@@ -0,0 +1,559 @@
2+/* $NetBSD: unvis.c,v 1.45 2022/04/19 20:32:15 rillig Exp $ */
3+
4+/*-
5+ * Copyright (c) 1989, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ */
32+
33+#include <sys/cdefs.h>
34+#if defined(LIBC_SCCS) && !defined(lint)
35+#if 0
36+static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
37+#else
38+__RCSID("$NetBSD: unvis.c,v 1.45 2022/04/19 20:32:15 rillig Exp $");
39+#endif
40+#endif /* LIBC_SCCS and not lint */
41+
42+#include "namespace.h"
43+#include <sys/types.h>
44+
45+#include <assert.h>
46+#include <ctype.h>
47+#include <stdint.h>
48+#include <stdio.h>
49+#include <errno.h>
50+#include <vis.h>
51+
52+#ifdef __weak_alias
53+__weak_alias(strnunvisx,_strnunvisx)
54+#endif
55+
56+#if !HAVE_VIS
57+/*
58+ * decode driven by state machine
59+ */
60+#define S_GROUND 0 /* haven't seen escape char */
61+#define S_START 1 /* start decoding special sequence */
62+#define S_META 2 /* metachar started (M) */
63+#define S_META1 3 /* metachar more, regular char (-) */
64+#define S_CTRL 4 /* control char started (^) */
65+#define S_OCTAL2 5 /* octal digit 2 */
66+#define S_OCTAL3 6 /* octal digit 3 */
67+#define S_HEX 7 /* mandatory hex digit */
68+#define S_HEX1 8 /* http hex digit */
69+#define S_HEX2 9 /* http hex digit 2 */
70+#define S_MIME1 10 /* mime hex digit 1 */
71+#define S_MIME2 11 /* mime hex digit 2 */
72+#define S_EATCRNL 12 /* mime eating CRNL */
73+#define S_AMP 13 /* seen & */
74+#define S_NUMBER 14 /* collecting number */
75+#define S_STRING 15 /* collecting string */
76+
77+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
78+#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10))
79+#define XTOD(c) (isdigit(c) ? (c - '0') : ((c - 'A') + 10))
80+
81+/*
82+ * RFC 1866
83+ */
84+static const struct nv {
85+ char name[7];
86+ uint8_t value;
87+} nv[] = {
88+ { "AElig", 198 }, /* capital AE diphthong (ligature) */
89+ { "Aacute", 193 }, /* capital A, acute accent */
90+ { "Acirc", 194 }, /* capital A, circumflex accent */
91+ { "Agrave", 192 }, /* capital A, grave accent */
92+ { "Aring", 197 }, /* capital A, ring */
93+ { "Atilde", 195 }, /* capital A, tilde */
94+ { "Auml", 196 }, /* capital A, dieresis or umlaut mark */
95+ { "Ccedil", 199 }, /* capital C, cedilla */
96+ { "ETH", 208 }, /* capital Eth, Icelandic */
97+ { "Eacute", 201 }, /* capital E, acute accent */
98+ { "Ecirc", 202 }, /* capital E, circumflex accent */
99+ { "Egrave", 200 }, /* capital E, grave accent */
100+ { "Euml", 203 }, /* capital E, dieresis or umlaut mark */
101+ { "Iacute", 205 }, /* capital I, acute accent */
102+ { "Icirc", 206 }, /* capital I, circumflex accent */
103+ { "Igrave", 204 }, /* capital I, grave accent */
104+ { "Iuml", 207 }, /* capital I, dieresis or umlaut mark */
105+ { "Ntilde", 209 }, /* capital N, tilde */
106+ { "Oacute", 211 }, /* capital O, acute accent */
107+ { "Ocirc", 212 }, /* capital O, circumflex accent */
108+ { "Ograve", 210 }, /* capital O, grave accent */
109+ { "Oslash", 216 }, /* capital O, slash */
110+ { "Otilde", 213 }, /* capital O, tilde */
111+ { "Ouml", 214 }, /* capital O, dieresis or umlaut mark */
112+ { "THORN", 222 }, /* capital THORN, Icelandic */
113+ { "Uacute", 218 }, /* capital U, acute accent */
114+ { "Ucirc", 219 }, /* capital U, circumflex accent */
115+ { "Ugrave", 217 }, /* capital U, grave accent */
116+ { "Uuml", 220 }, /* capital U, dieresis or umlaut mark */
117+ { "Yacute", 221 }, /* capital Y, acute accent */
118+ { "aacute", 225 }, /* small a, acute accent */
119+ { "acirc", 226 }, /* small a, circumflex accent */
120+ { "acute", 180 }, /* acute accent */
121+ { "aelig", 230 }, /* small ae diphthong (ligature) */
122+ { "agrave", 224 }, /* small a, grave accent */
123+ { "amp", 38 }, /* ampersand */
124+ { "aring", 229 }, /* small a, ring */
125+ { "atilde", 227 }, /* small a, tilde */
126+ { "auml", 228 }, /* small a, dieresis or umlaut mark */
127+ { "brvbar", 166 }, /* broken (vertical) bar */
128+ { "ccedil", 231 }, /* small c, cedilla */
129+ { "cedil", 184 }, /* cedilla */
130+ { "cent", 162 }, /* cent sign */
131+ { "copy", 169 }, /* copyright sign */
132+ { "curren", 164 }, /* general currency sign */
133+ { "deg", 176 }, /* degree sign */
134+ { "divide", 247 }, /* divide sign */
135+ { "eacute", 233 }, /* small e, acute accent */
136+ { "ecirc", 234 }, /* small e, circumflex accent */
137+ { "egrave", 232 }, /* small e, grave accent */
138+ { "eth", 240 }, /* small eth, Icelandic */
139+ { "euml", 235 }, /* small e, dieresis or umlaut mark */
140+ { "frac12", 189 }, /* fraction one-half */
141+ { "frac14", 188 }, /* fraction one-quarter */
142+ { "frac34", 190 }, /* fraction three-quarters */
143+ { "gt", 62 }, /* greater than */
144+ { "iacute", 237 }, /* small i, acute accent */
145+ { "icirc", 238 }, /* small i, circumflex accent */
146+ { "iexcl", 161 }, /* inverted exclamation mark */
147+ { "igrave", 236 }, /* small i, grave accent */
148+ { "iquest", 191 }, /* inverted question mark */
149+ { "iuml", 239 }, /* small i, dieresis or umlaut mark */
150+ { "laquo", 171 }, /* angle quotation mark, left */
151+ { "lt", 60 }, /* less than */
152+ { "macr", 175 }, /* macron */
153+ { "micro", 181 }, /* micro sign */
154+ { "middot", 183 }, /* middle dot */
155+ { "nbsp", 160 }, /* no-break space */
156+ { "not", 172 }, /* not sign */
157+ { "ntilde", 241 }, /* small n, tilde */
158+ { "oacute", 243 }, /* small o, acute accent */
159+ { "ocirc", 244 }, /* small o, circumflex accent */
160+ { "ograve", 242 }, /* small o, grave accent */
161+ { "ordf", 170 }, /* ordinal indicator, feminine */
162+ { "ordm", 186 }, /* ordinal indicator, masculine */
163+ { "oslash", 248 }, /* small o, slash */
164+ { "otilde", 245 }, /* small o, tilde */
165+ { "ouml", 246 }, /* small o, dieresis or umlaut mark */
166+ { "para", 182 }, /* pilcrow (paragraph sign) */
167+ { "plusmn", 177 }, /* plus-or-minus sign */
168+ { "pound", 163 }, /* pound sterling sign */
169+ { "quot", 34 }, /* double quote */
170+ { "raquo", 187 }, /* angle quotation mark, right */
171+ { "reg", 174 }, /* registered sign */
172+ { "sect", 167 }, /* section sign */
173+ { "shy", 173 }, /* soft hyphen */
174+ { "sup1", 185 }, /* superscript one */
175+ { "sup2", 178 }, /* superscript two */
176+ { "sup3", 179 }, /* superscript three */
177+ { "szlig", 223 }, /* small sharp s, German (sz ligature) */
178+ { "thorn", 254 }, /* small thorn, Icelandic */
179+ { "times", 215 }, /* multiply sign */
180+ { "uacute", 250 }, /* small u, acute accent */
181+ { "ucirc", 251 }, /* small u, circumflex accent */
182+ { "ugrave", 249 }, /* small u, grave accent */
183+ { "uml", 168 }, /* umlaut (dieresis) */
184+ { "uuml", 252 }, /* small u, dieresis or umlaut mark */
185+ { "yacute", 253 }, /* small y, acute accent */
186+ { "yen", 165 }, /* yen sign */
187+ { "yuml", 255 }, /* small y, dieresis or umlaut mark */
188+};
189+
190+/*
191+ * unvis - decode characters previously encoded by vis
192+ */
193+int
194+unvis(char *cp, int c, int *astate, int flag)
195+{
196+ unsigned char uc = (unsigned char)c;
197+ unsigned char st, ia, is, lc;
198+
199+/*
200+ * Bottom 8 bits of astate hold the state machine state.
201+ * Top 8 bits hold the current character in the http 1866 nv string decoding
202+ */
203+#define GS(a) ((a) & 0xff)
204+#define SS(a, b) (((uint32_t)(a) << 24) | (b))
205+#define GI(a) ((uint32_t)(a) >> 24)
206+
207+ _DIAGASSERT(cp != NULL);
208+ _DIAGASSERT(astate != NULL);
209+ st = GS(*astate);
210+
211+ if (flag & UNVIS_END) {
212+ switch (st) {
213+ case S_OCTAL2:
214+ case S_OCTAL3:
215+ case S_HEX2:
216+ *astate = SS(0, S_GROUND);
217+ return UNVIS_VALID;
218+ case S_GROUND:
219+ return UNVIS_NOCHAR;
220+ default:
221+ return UNVIS_SYNBAD;
222+ }
223+ }
224+
225+ switch (st) {
226+
227+ case S_GROUND:
228+ *cp = 0;
229+ if ((flag & VIS_NOESCAPE) == 0 && c == '\\') {
230+ *astate = SS(0, S_START);
231+ return UNVIS_NOCHAR;
232+ }
233+ if ((flag & VIS_HTTP1808) && c == '%') {
234+ *astate = SS(0, S_HEX1);
235+ return UNVIS_NOCHAR;
236+ }
237+ if ((flag & VIS_HTTP1866) && c == '&') {
238+ *astate = SS(0, S_AMP);
239+ return UNVIS_NOCHAR;
240+ }
241+ if ((flag & VIS_MIMESTYLE) && c == '=') {
242+ *astate = SS(0, S_MIME1);
243+ return UNVIS_NOCHAR;
244+ }
245+ *cp = c;
246+ return UNVIS_VALID;
247+
248+ case S_START:
249+ switch(c) {
250+ case '\\':
251+ *cp = c;
252+ *astate = SS(0, S_GROUND);
253+ return UNVIS_VALID;
254+ case '0': case '1': case '2': case '3':
255+ case '4': case '5': case '6': case '7':
256+ *cp = (c - '0');
257+ *astate = SS(0, S_OCTAL2);
258+ return UNVIS_NOCHAR;
259+ case 'M':
260+ *cp = (char)0200;
261+ *astate = SS(0, S_META);
262+ return UNVIS_NOCHAR;
263+ case '^':
264+ *astate = SS(0, S_CTRL);
265+ return UNVIS_NOCHAR;
266+ case 'n':
267+ *cp = '\n';
268+ *astate = SS(0, S_GROUND);
269+ return UNVIS_VALID;
270+ case 'r':
271+ *cp = '\r';
272+ *astate = SS(0, S_GROUND);
273+ return UNVIS_VALID;
274+ case 'b':
275+ *cp = '\b';
276+ *astate = SS(0, S_GROUND);
277+ return UNVIS_VALID;
278+ case 'a':
279+ *cp = '\007';
280+ *astate = SS(0, S_GROUND);
281+ return UNVIS_VALID;
282+ case 'v':
283+ *cp = '\v';
284+ *astate = SS(0, S_GROUND);
285+ return UNVIS_VALID;
286+ case 't':
287+ *cp = '\t';
288+ *astate = SS(0, S_GROUND);
289+ return UNVIS_VALID;
290+ case 'f':
291+ *cp = '\f';
292+ *astate = SS(0, S_GROUND);
293+ return UNVIS_VALID;
294+ case 's':
295+ *cp = ' ';
296+ *astate = SS(0, S_GROUND);
297+ return UNVIS_VALID;
298+ case 'E':
299+ *cp = '\033';
300+ *astate = SS(0, S_GROUND);
301+ return UNVIS_VALID;
302+ case 'x':
303+ *astate = SS(0, S_HEX);
304+ return UNVIS_NOCHAR;
305+ case '\n':
306+ /*
307+ * hidden newline
308+ */
309+ *astate = SS(0, S_GROUND);
310+ return UNVIS_NOCHAR;
311+ case '$':
312+ /*
313+ * hidden marker
314+ */
315+ *astate = SS(0, S_GROUND);
316+ return UNVIS_NOCHAR;
317+ default:
318+ if (isgraph(c)) {
319+ *cp = c;
320+ *astate = SS(0, S_GROUND);
321+ return UNVIS_VALID;
322+ }
323+ }
324+ goto bad;
325+
326+ case S_META:
327+ if (c == '-')
328+ *astate = SS(0, S_META1);
329+ else if (c == '^')
330+ *astate = SS(0, S_CTRL);
331+ else
332+ goto bad;
333+ return UNVIS_NOCHAR;
334+
335+ case S_META1:
336+ *astate = SS(0, S_GROUND);
337+ *cp |= c;
338+ return UNVIS_VALID;
339+
340+ case S_CTRL:
341+ if (c == '?')
342+ *cp |= 0177;
343+ else
344+ *cp |= c & 037;
345+ *astate = SS(0, S_GROUND);
346+ return UNVIS_VALID;
347+
348+ case S_OCTAL2: /* second possible octal digit */
349+ if (isoctal(uc)) {
350+ /*
351+ * yes - and maybe a third
352+ */
353+ *cp = (*cp << 3) + (c - '0');
354+ *astate = SS(0, S_OCTAL3);
355+ return UNVIS_NOCHAR;
356+ }
357+ /*
358+ * no - done with current sequence, push back passed char
359+ */
360+ *astate = SS(0, S_GROUND);
361+ return UNVIS_VALIDPUSH;
362+
363+ case S_OCTAL3: /* third possible octal digit */
364+ *astate = SS(0, S_GROUND);
365+ if (isoctal(uc)) {
366+ *cp = (*cp << 3) + (c - '0');
367+ return UNVIS_VALID;
368+ }
369+ /*
370+ * we were done, push back passed char
371+ */
372+ return UNVIS_VALIDPUSH;
373+
374+ case S_HEX:
375+ if (!isxdigit(uc))
376+ goto bad;
377+ /*FALLTHROUGH*/
378+ case S_HEX1:
379+ if (isxdigit(uc)) {
380+ *cp = xtod(uc);
381+ *astate = SS(0, S_HEX2);
382+ return UNVIS_NOCHAR;
383+ }
384+ /*
385+ * no - done with current sequence, push back passed char
386+ */
387+ *astate = SS(0, S_GROUND);
388+ return UNVIS_VALIDPUSH;
389+
390+ case S_HEX2:
391+ *astate = S_GROUND;
392+ if (isxdigit(uc)) {
393+ *cp = xtod(uc) | (*cp << 4);
394+ return UNVIS_VALID;
395+ }
396+ return UNVIS_VALIDPUSH;
397+
398+ case S_MIME1:
399+ if (uc == '\n' || uc == '\r') {
400+ *astate = SS(0, S_EATCRNL);
401+ return UNVIS_NOCHAR;
402+ }
403+ if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) {
404+ *cp = XTOD(uc);
405+ *astate = SS(0, S_MIME2);
406+ return UNVIS_NOCHAR;
407+ }
408+ goto bad;
409+
410+ case S_MIME2:
411+ if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) {
412+ *astate = SS(0, S_GROUND);
413+ *cp = XTOD(uc) | (*cp << 4);
414+ return UNVIS_VALID;
415+ }
416+ goto bad;
417+
418+ case S_EATCRNL:
419+ switch (uc) {
420+ case '\r':
421+ case '\n':
422+ return UNVIS_NOCHAR;
423+ case '=':
424+ *astate = SS(0, S_MIME1);
425+ return UNVIS_NOCHAR;
426+ default:
427+ *cp = uc;
428+ *astate = SS(0, S_GROUND);
429+ return UNVIS_VALID;
430+ }
431+
432+ case S_AMP:
433+ *cp = 0;
434+ if (uc == '#') {
435+ *astate = SS(0, S_NUMBER);
436+ return UNVIS_NOCHAR;
437+ }
438+ *astate = SS(0, S_STRING);
439+ /*FALLTHROUGH*/
440+
441+ case S_STRING:
442+ ia = *cp; /* index in the array */
443+ is = GI(*astate); /* index in the string */
444+ lc = is == 0 ? 0 : nv[ia].name[is - 1]; /* last character */
445+
446+ if (uc == ';')
447+ uc = '\0';
448+
449+ for (; ia < __arraycount(nv); ia++) {
450+ if (is != 0 && nv[ia].name[is - 1] != lc)
451+ goto bad;
452+ if (nv[ia].name[is] == uc)
453+ break;
454+ }
455+
456+ if (ia == __arraycount(nv))
457+ goto bad;
458+
459+ if (uc != 0) {
460+ *cp = ia;
461+ *astate = SS(is + 1, S_STRING);
462+ return UNVIS_NOCHAR;
463+ }
464+
465+ *cp = nv[ia].value;
466+ *astate = SS(0, S_GROUND);
467+ return UNVIS_VALID;
468+
469+ case S_NUMBER:
470+ if (uc == ';')
471+ return UNVIS_VALID;
472+ if (!isdigit(uc))
473+ goto bad;
474+ *cp += (*cp * 10) + uc - '0';
475+ return UNVIS_NOCHAR;
476+
477+ default:
478+ bad:
479+ /*
480+ * decoder in unknown state - (probably uninitialized)
481+ */
482+ *astate = SS(0, S_GROUND);
483+ return UNVIS_SYNBAD;
484+ }
485+}
486+
487+/*
488+ * strnunvisx - decode src into dst
489+ *
490+ * Number of chars decoded into dst is returned, -1 on error.
491+ * Dst is null terminated.
492+ */
493+
494+int
495+strnunvisx(char *dst, size_t dlen, const char *src, int flag)
496+{
497+ char c;
498+ char t = '\0', *start = dst;
499+ int state = 0;
500+
501+ _DIAGASSERT(src != NULL);
502+ _DIAGASSERT(dst != NULL);
503+#define CHECKSPACE() \
504+ do { \
505+ if (dlen-- == 0) { \
506+ errno = ENOSPC; \
507+ return -1; \
508+ } \
509+ } while (0)
510+
511+ while ((c = *src++) != '\0') {
512+ again:
513+ switch (unvis(&t, c, &state, flag)) {
514+ case UNVIS_VALID:
515+ CHECKSPACE();
516+ *dst++ = t;
517+ break;
518+ case UNVIS_VALIDPUSH:
519+ CHECKSPACE();
520+ *dst++ = t;
521+ goto again;
522+ case 0:
523+ case UNVIS_NOCHAR:
524+ break;
525+ case UNVIS_SYNBAD:
526+ errno = EINVAL;
527+ return -1;
528+ default:
529+ _DIAGASSERT(/*CONSTCOND*/0);
530+ errno = EINVAL;
531+ return -1;
532+ }
533+ }
534+ if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) {
535+ CHECKSPACE();
536+ *dst++ = t;
537+ }
538+ CHECKSPACE();
539+ *dst = '\0';
540+ return (int)(dst - start);
541+}
542+
543+int
544+strunvisx(char *dst, const char *src, int flag)
545+{
546+ return strnunvisx(dst, (size_t)~0, src, flag);
547+}
548+
549+int
550+strunvis(char *dst, const char *src)
551+{
552+ return strnunvisx(dst, (size_t)~0, src, 0);
553+}
554+
555+int
556+strnunvis(char *dst, size_t dlen, const char *src)
557+{
558+ return strnunvisx(dst, dlen, src, 0);
559+}
560+#endif
+68,
-0
1@@ -0,0 +1,68 @@
2+#ifndef _UTIL_H_
3+#define _UTIL_H_
4+
5+#include "netcompat.h"
6+#include <sys/cdefs.h>
7+#include <sys/types.h>
8+#include <inttypes.h>
9+#include <stdio.h>
10+#include <stdarg.h>
11+#include <sys/stat.h>
12+#include <grp.h>
13+#include <pwd.h>
14+
15+#ifndef FPARSELN_UNESCESC
16+#define FPARSELN_UNESCESC 0x01
17+#define FPARSELN_UNESCCONT 0x02
18+#define FPARSELN_UNESCCOMM 0x04
19+#define FPARSELN_UNESCREST 0x08
20+#define FPARSELN_UNESCALL 0x0f
21+#endif
22+
23+__BEGIN_DECLS
24+
25+char *flags_to_string(unsigned long, const char *);
26+int string_to_flags(char **, unsigned long *, unsigned long *);
27+
28+void (*esetfunc(void (*)(int, const char *, ...)))(int, const char *, ...);
29+size_t estrlcpy(char *, const char *, size_t);
30+size_t estrlcat(char *, const char *, size_t);
31+char *estrdup(const char *);
32+char *estrndup(const char *, size_t);
33+intmax_t estrtoi(const char *, int, intmax_t, intmax_t);
34+uintmax_t estrtou(const char *, int, uintmax_t, uintmax_t);
35+void *ecalloc(size_t, size_t);
36+void *emalloc(size_t);
37+void *erealloc(void *, size_t);
38+void ereallocarr(void *, size_t, size_t);
39+FILE *efopen(const char *, const char *);
40+int easprintf(char ** __restrict, const char * __restrict, ...)
41+ __printflike(2, 3);
42+int evasprintf(char ** __restrict, const char * __restrict, va_list)
43+ __printflike(2, 0);
44+
45+char *fgetln(FILE *, size_t *);
46+char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
47+mode_t getmode(const void *, mode_t);
48+void *setmode(const char *);
49+long long strsuftoll(const char *, const char *, long long, long long);
50+uintmax_t strtou(const char * __restrict, char ** __restrict, int,
51+ uintmax_t, uintmax_t, int *);
52+
53+const char *getprogname(void);
54+void setprogname(const char *);
55+
56+const char *user_from_uid(uid_t, int);
57+const char *group_from_gid(gid_t, int);
58+int uid_from_user(const char *, uid_t *);
59+int gid_from_group(const char *, gid_t *);
60+int pwcache_userdb(int (*)(int), void (*)(void),
61+ struct passwd *(*)(const char *), struct passwd *(*)(uid_t));
62+int pwcache_groupdb(int (*)(int), void (*)(void),
63+ struct group *(*)(const char *), struct group *(*)(gid_t));
64+int setpassent(int);
65+int setgroupent(int);
66+
67+__END_DECLS
68+
69+#endif
+819,
-85
1@@ -1,120 +1,854 @@
2+/* $NetBSD: vis.c,v 1.88 2024/03/17 21:48:02 andvar Exp $ */
3+
4+/*-
5+ * Copyright (c) 1989, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ */
32+
33+/*-
34+ * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
35+ * All rights reserved.
36+ *
37+ * Redistribution and use in source and binary forms, with or without
38+ * modification, are permitted provided that the following conditions
39+ * are met:
40+ * 1. Redistributions of source code must retain the above copyright
41+ * notice, this list of conditions and the following disclaimer.
42+ * 2. Redistributions in binary form must reproduce the above copyright
43+ * notice, this list of conditions and the following disclaimer in the
44+ * documentation and/or other materials provided with the distribution.
45+ *
46+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
47+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
48+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
49+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
50+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
56+ * POSSIBILITY OF SUCH DAMAGE.
57+ */
58+
59 #include <sys/cdefs.h>
60+#if defined(LIBC_SCCS) && !defined(lint)
61+__RCSID("$NetBSD: vis.c,v 1.88 2024/03/17 21:48:02 andvar Exp $");
62+#endif /* LIBC_SCCS and not lint */
63+#ifdef __FBSDID
64+__FBSDID("$FreeBSD$");
65+#define _DIAGASSERT(x) assert(x)
66+#endif
67+
68+#include "namespace.h"
69+
70+#include <sys/param.h>
71+#include <sys/types.h>
72+
73+#include <assert.h>
74+#include <errno.h>
75+#include <stdint.h>
76+#include <stdlib.h>
77+#include <vis.h>
78+#include <wchar.h>
79+#include <wctype.h>
80
81+#ifdef __weak_alias
82+__weak_alias(strvisx,_strvisx)
83+#endif
84+
85+#if !HAVE_VIS || !HAVE_SVIS
86 #include <ctype.h>
87-#include <stddef.h>
88+#include <limits.h>
89+#include <stdio.h>
90+#include <string.h>
91+
92+/*
93+ * The reason for going through the trouble to deal with character encodings
94+ * in vis(3), is that we use this to safe encode output of commands. This
95+ * safe encoding varies depending on the character set. For example if we
96+ * display ps output in French, we don't want to display French characters
97+ * as M-foo.
98+ */
99
100-#include "vis.h"
101+static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *);
102
103+#undef BELL
104+#define BELL L'\a'
105+
106+#if defined(LC_C_LOCALE)
107+#define iscgraph(c) isgraph_l(c, LC_C_LOCALE)
108+#else
109+/* Keep it simple for now, no locale stuff */
110+#define iscgraph(c) isgraph(c)
111+#ifdef notyet
112+#include <locale.h>
113 static int
114-needs_vis(unsigned char c, int flags)
115+iscgraph(int c) {
116+ int rv;
117+ char *ol;
118+
119+ ol = setlocale(LC_CTYPE, "C");
120+ rv = isgraph(c);
121+ if (ol)
122+ setlocale(LC_CTYPE, ol);
123+ return rv;
124+}
125+#endif
126+#endif
127+
128+#define ISGRAPH(flags, c) \
129+ (((flags) & VIS_NOLOCALE) ? iscgraph(c) : iswgraph(c))
130+
131+#define iswoctal(c) (((u_char)(c)) >= L'0' && ((u_char)(c)) <= L'7')
132+#define iswwhite(c) (c == L' ' || c == L'\t' || c == L'\n')
133+#define iswsafe(c) (c == L'\b' || c == BELL || c == L'\r')
134+#define xtoa(c) L"0123456789abcdef"[c]
135+#define XTOA(c) L"0123456789ABCDEF"[c]
136+
137+#define MAXEXTRAS 30
138+
139+static const wchar_t char_shell[] = L"'`\";&<>()|{}]\\$!^~";
140+static const wchar_t char_glob[] = L"*?[#";
141+
142+#if !HAVE_NBTOOL_CONFIG_H
143+#ifndef __NetBSD__
144+/*
145+ * On NetBSD MB_LEN_MAX is currently 32 which does not fit on any integer
146+ * integral type and it is probably wrong, since currently the maximum
147+ * number of bytes and character needs is 6. Until this is fixed, the
148+ * loops below are using sizeof(uint64_t) - 1 instead of MB_LEN_MAX, and
149+ * the assertion is commented out.
150+ */
151+#ifdef __FreeBSD__
152+/*
153+ * On FreeBSD including <sys/systm.h> for CTASSERT only works in kernel
154+ * mode.
155+ */
156+#ifndef CTASSERT
157+#define CTASSERT(x) _CTASSERT(x, __LINE__)
158+#define _CTASSERT(x, y) __CTASSERT(x, y)
159+#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
160+#endif
161+#endif /* __FreeBSD__ */
162+CTASSERT(MB_LEN_MAX <= sizeof(uint64_t));
163+#endif /* !__NetBSD__ */
164+#endif
165+
166+/*
167+ * This is do_hvis, for HTTP style (RFC 1808)
168+ */
169+static wchar_t *
170+do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
171 {
172- if (c == '\\' && !(flags & VIS_NOSLASH))
173- return 1;
174- if ((flags & VIS_SP) && c == ' ')
175- return 1;
176- if ((flags & VIS_TAB) && c == '\t')
177- return 1;
178- if ((flags & VIS_NL) && c == '\n')
179- return 1;
180- if (!isprint(c))
181- return 1;
182- return 0;
183+ if (iswalnum(c)
184+ /* safe */
185+ || c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+'
186+ /* extra */
187+ || c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')'
188+ || c == L',')
189+ dst = do_svis(dst, c, flags, nextc, extra);
190+ else {
191+ *dst++ = L'%';
192+ *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
193+ *dst++ = xtoa((unsigned int)c & 0xf);
194+ }
195+
196+ return dst;
197 }
198
199-static int
200-putc_vis(char **dst, size_t *dlen, unsigned char c)
201+/*
202+ * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
203+ * NB: No handling of long lines or CRLF.
204+ */
205+static wchar_t *
206+do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
207 {
208- if (*dlen <= 1)
209- return -1;
210- *(*dst)++ = (char)c;
211- (*dlen)--;
212- return 0;
213+ if ((c != L'\n') &&
214+ /* Space at the end of the line */
215+ ((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) ||
216+ /* Out of range */
217+ (!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
218+ /* Specific char to be escaped */
219+ wcschr(L"#$@[\\]^`{|}~", c) != NULL)) {
220+ *dst++ = L'=';
221+ *dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
222+ *dst++ = XTOA((unsigned int)c & 0xf);
223+ } else
224+ dst = do_svis(dst, c, flags, nextc, extra);
225+ return dst;
226 }
227
228-static int
229-put_oct(char **dst, size_t *dlen, unsigned char c)
230+/*
231+ * Output single byte of multibyte character.
232+ */
233+static wchar_t *
234+do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra)
235 {
236- if (*dlen <= 4)
237- return -1;
238- *(*dst)++ = '\\';
239- *(*dst)++ = (char)(((c >> 6) & 0x07) + '0');
240- *(*dst)++ = (char)(((c >> 3) & 0x07) + '0');
241- *(*dst)++ = (char)((c & 0x07) + '0');
242- *dlen -= 4;
243- return 0;
244+ if (flags & VIS_CSTYLE) {
245+ switch (c) {
246+ case L'\n':
247+ *dst++ = L'\\'; *dst++ = L'n';
248+ return dst;
249+ case L'\r':
250+ *dst++ = L'\\'; *dst++ = L'r';
251+ return dst;
252+ case L'\b':
253+ *dst++ = L'\\'; *dst++ = L'b';
254+ return dst;
255+ case BELL:
256+ *dst++ = L'\\'; *dst++ = L'a';
257+ return dst;
258+ case L'\v':
259+ *dst++ = L'\\'; *dst++ = L'v';
260+ return dst;
261+ case L'\t':
262+ *dst++ = L'\\'; *dst++ = L't';
263+ return dst;
264+ case L'\f':
265+ *dst++ = L'\\'; *dst++ = L'f';
266+ return dst;
267+ case L' ':
268+ *dst++ = L'\\'; *dst++ = L's';
269+ return dst;
270+ case L'\0':
271+ *dst++ = L'\\'; *dst++ = L'0';
272+ if (iswoctal(nextc)) {
273+ *dst++ = L'0';
274+ *dst++ = L'0';
275+ }
276+ return dst;
277+ /* We cannot encode these characters in VIS_CSTYLE
278+ * because they special meaning */
279+ case L'n':
280+ case L'r':
281+ case L'b':
282+ case L'a':
283+ case L'v':
284+ case L't':
285+ case L'f':
286+ case L's':
287+ case L'0':
288+ case L'M':
289+ case L'^':
290+ case L'$': /* vis(1) -l */
291+ break;
292+ default:
293+ if (ISGRAPH(flags, c) && !iswoctal(c)) {
294+ *dst++ = L'\\';
295+ *dst++ = c;
296+ return dst;
297+ }
298+ }
299+ }
300+ if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) {
301+ *dst++ = L'\\';
302+ *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0';
303+ *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0';
304+ *dst++ = (c & 07) + L'0';
305+ } else {
306+ if ((flags & VIS_NOSLASH) == 0)
307+ *dst++ = L'\\';
308+
309+ if (c & 0200) {
310+ c &= 0177;
311+ *dst++ = L'M';
312+ }
313+
314+ if (iswcntrl(c)) {
315+ *dst++ = L'^';
316+ if (c == 0177)
317+ *dst++ = L'?';
318+ else
319+ *dst++ = c + L'@';
320+ } else {
321+ *dst++ = L'-';
322+ *dst++ = c;
323+ }
324+ }
325+
326+ return dst;
327 }
328
329-static int
330-put_cstyle(char **dst, size_t *dlen, unsigned char c)
331-{
332- char esc;
333-
334- switch (c) {
335- case '\n': esc = 'n'; break;
336- case '\r': esc = 'r'; break;
337- case '\b': esc = 'b'; break;
338- case '\a': esc = 'a'; break;
339- case '\v': esc = 'v'; break;
340- case '\t': esc = 't'; break;
341- case '\f': esc = 'f'; break;
342- case ' ': esc = 's'; break;
343- case '\\': esc = '\\'; break;
344- default:
345- return put_oct(dst, dlen, c);
346+/*
347+ * This is do_vis, the central code of vis.
348+ * dst: Pointer to the destination buffer
349+ * c: Character to encode
350+ * flags: Flags word
351+ * nextc: The character following 'c'
352+ * extra: Pointer to the list of extra characters to be
353+ * backslash-protected.
354+ */
355+static wchar_t *
356+do_svis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
357+{
358+ int iswextra, i, shft;
359+ uint64_t bmsk, wmsk;
360+
361+ iswextra = wcschr(extra, c) != NULL;
362+ if (!iswextra && (ISGRAPH(flags, c) || iswwhite(c) ||
363+ ((flags & VIS_SAFE) && iswsafe(c)))) {
364+ *dst++ = c;
365+ return dst;
366 }
367
368- if (*dlen <= 2)
369- return -1;
370- *(*dst)++ = '\\';
371- *(*dst)++ = esc;
372- *dlen -= 2;
373- return 0;
374+ /* See comment in istrsenvisx() output loop, below. */
375+ wmsk = 0;
376+ for (i = sizeof(wmsk) - 1; i >= 0; i--) {
377+ shft = i * NBBY;
378+ bmsk = (uint64_t)0xffLL << shft;
379+ wmsk |= bmsk;
380+ if ((c & wmsk) || i == 0)
381+ dst = do_mbyte(dst, (wint_t)(
382+ (uint64_t)(c & bmsk) >> shft),
383+ flags, nextc, iswextra);
384+ }
385+
386+ return dst;
387 }
388
389-int
390-strnvisx(char *dst, size_t dlen, const char *src, size_t slen, int flags)
391+typedef wchar_t *(*visfun_t)(wchar_t *, wint_t, int, wint_t, const wchar_t *);
392+
393+/*
394+ * Return the appropriate encoding function depending on the flags given.
395+ */
396+static visfun_t
397+getvisfun(int flags)
398 {
399- char *start;
400- unsigned char c;
401+ if (flags & VIS_HTTPSTYLE)
402+ return do_hvis;
403+ if (flags & VIS_MIMESTYLE)
404+ return do_mvis;
405+ return do_svis;
406+}
407
408- if (dlen == 0)
409- return -1;
410+/*
411+ * Expand list of extra characters to not visually encode.
412+ */
413+static wchar_t *
414+makeextralist(int flags, const char *src)
415+{
416+ wchar_t *dst, *d;
417+ size_t len;
418+ const wchar_t *s;
419+ mbstate_t mbstate;
420+
421+ len = strlen(src);
422+ if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)
423+ return NULL;
424+
425+ memset(&mbstate, 0, sizeof(mbstate));
426+ if ((flags & VIS_NOLOCALE)
427+ || mbsrtowcs(dst, &src, len, &mbstate) == (size_t)-1) {
428+ size_t i;
429+ for (i = 0; i < len; i++)
430+ dst[i] = (wchar_t)(u_char)src[i];
431+ d = dst + len;
432+ } else
433+ d = dst + wcslen(dst);
434
435- start = dst;
436- while (slen-- > 0) {
437- c = (unsigned char)*src++;
438- if (!needs_vis(c, flags)) {
439- if (putc_vis(&dst, &dlen, c) == -1)
440- goto trunc;
441+ if (flags & VIS_GLOB)
442+ for (s = char_glob; *s; *d++ = *s++)
443 continue;
444+
445+ if (flags & VIS_SHELL)
446+ for (s = char_shell; *s; *d++ = *s++)
447+ continue;
448+
449+ if (flags & VIS_SP) *d++ = L' ';
450+ if (flags & VIS_TAB) *d++ = L'\t';
451+ if (flags & VIS_NL) *d++ = L'\n';
452+ if (flags & VIS_DQ) *d++ = L'"';
453+ if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\';
454+ *d = L'\0';
455+
456+ return dst;
457+}
458+
459+/*
460+ * istrsenvisx()
461+ * The main internal function.
462+ * All user-visible functions call this one.
463+ */
464+static int
465+istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
466+ int flags, const char *mbextra, int *cerr_ptr)
467+{
468+ char mbbuf[MB_LEN_MAX];
469+ wchar_t *dst, *src, *pdst, *psrc, *start, *extra;
470+ size_t len, olen;
471+ uint64_t bmsk, wmsk;
472+ wint_t c;
473+ visfun_t f;
474+ int cerr, error = -1, i, shft;
475+ ssize_t clen = 0;
476+ char *mbdst, *mbwrite, *mdst;
477+ size_t mbslength;
478+ size_t maxolen;
479+ mbstate_t mbstate;
480+
481+ _DIAGASSERT(mbdstp != NULL);
482+ _DIAGASSERT(mbsrc != NULL || mblength == 0);
483+ _DIAGASSERT(mbextra != NULL);
484+
485+ mbslength = mblength;
486+ /*
487+ * When inputing a single character, must also read in the
488+ * next character for nextc, the look-ahead character.
489+ */
490+ if (mbslength == 1)
491+ mbslength++;
492+
493+ /*
494+ * Input (mbsrc) is a char string considered to be multibyte
495+ * characters. The input loop will read this string pulling
496+ * one character, possibly multiple bytes, from mbsrc and
497+ * converting each to wchar_t in src.
498+ *
499+ * The vis conversion will be done using the wide char
500+ * wchar_t string.
501+ *
502+ * This will then be converted back to a multibyte string to
503+ * return to the caller.
504+ */
505+
506+ /*
507+ * Guarantee the arithmetic on input to calloc won't overflow.
508+ */
509+ if (mbslength > (SIZE_MAX - 1)/16) {
510+ errno = ENOMEM;
511+ return -1;
512+ }
513+
514+ /* Allocate space for the wide char strings */
515+ psrc = pdst = extra = NULL;
516+ mdst = NULL;
517+ if ((psrc = calloc(mbslength + 1, sizeof(*psrc))) == NULL)
518+ return -1;
519+ if ((pdst = calloc((16 * mbslength) + 1, sizeof(*pdst))) == NULL)
520+ goto out;
521+ if (*mbdstp == NULL) {
522+ if ((mdst = calloc((16 * mbslength) + 1, sizeof(*mdst))) == NULL)
523+ goto out;
524+ *mbdstp = mdst;
525+ }
526+
527+ mbdst = *mbdstp;
528+ dst = pdst;
529+ src = psrc;
530+
531+ if (flags & VIS_NOLOCALE) {
532+ /* Do one byte at a time conversion */
533+ cerr = 1;
534+ } else {
535+ /* Use caller's multibyte conversion error flag. */
536+ cerr = cerr_ptr ? *cerr_ptr : 0;
537+ }
538+
539+ /*
540+ * Input loop.
541+ * Handle up to mblength characters (not bytes). We do not
542+ * stop at NULs because we may be processing a block of data
543+ * that includes NULs.
544+ */
545+ memset(&mbstate, 0, sizeof(mbstate));
546+ while (mbslength > 0) {
547+ /* Convert one multibyte character to wchar_t. */
548+ if (!cerr) {
549+ clen = (ssize_t)mbrtowc(src, mbsrc,
550+ (mbslength < MB_LEN_MAX
551+ ? mbslength
552+ : MB_LEN_MAX),
553+ &mbstate);
554+ assert(clen < 0 || (size_t)clen <= mbslength);
555+ assert(clen <= MB_LEN_MAX);
556 }
557- if ((flags & VIS_CSTYLE) != 0) {
558- if (put_cstyle(&dst, &dlen, c) == -1)
559- goto trunc;
560- } else {
561- if (put_oct(&dst, &dlen, c) == -1)
562- goto trunc;
563+ if (cerr || clen < 0) {
564+ /* Conversion error, process as a byte instead. */
565+ *src = (wint_t)(u_char)*mbsrc;
566+ clen = 1;
567+ cerr = 1;
568+ }
569+ if (clen == 0) {
570+ /*
571+ * NUL in input gives 0 return value. process
572+ * as single NUL byte and keep going.
573+ */
574+ clen = 1;
575+ }
576+ /*
577+ * Let n := MIN(mbslength, MB_LEN_MAX). We have:
578+ *
579+ * mbslength >= 1
580+ * mbrtowc(..., n, &mbstate) <= n,
581+ * by the contract of mbrtowc
582+ *
583+ * clen is either
584+ * (a) mbrtowc(..., n, &mbstate), in which case
585+ * clen <= n <= mbslength; or
586+ * (b) 1, in which case clen = 1 <= mbslength.
587+ */
588+ assert(clen > 0);
589+ assert((size_t)clen <= mbslength);
590+ /* Advance buffer character pointer. */
591+ src++;
592+ /* Advance input pointer by number of bytes read. */
593+ mbsrc += clen;
594+ /* Decrement input byte count. */
595+ mbslength -= clen;
596+ }
597+ len = src - psrc;
598+ src = psrc;
599+
600+ /*
601+ * In the single character input case, we will have actually
602+ * processed two characters, c and nextc. Reset len back to
603+ * just a single character.
604+ */
605+ if (mblength < len)
606+ len = mblength;
607+
608+ /* Convert extra argument to list of characters for this mode. */
609+ extra = makeextralist(flags, mbextra);
610+ if (!extra) {
611+ if (dlen && *dlen == 0) {
612+ errno = ENOSPC;
613+ goto out;
614 }
615+ *mbdst = '\0'; /* can't create extra, return "" */
616+ error = 0;
617+ goto out;
618 }
619
620- *dst = '\0';
621- return (int)(dst - start);
622+ /* Look up which processing function to call. */
623+ f = getvisfun(flags);
624+
625+ /*
626+ * Main processing loop.
627+ * Call do_Xvis processing function one character at a time
628+ * with next character available for look-ahead.
629+ */
630+ for (start = dst; len > 0; len--) {
631+ c = *src++;
632+ dst = (*f)(dst, c, flags, len >= 1 ? *src : L'\0', extra);
633+ if (dst == NULL) {
634+ errno = ENOSPC;
635+ goto out;
636+ }
637+ }
638+
639+ /* Terminate the string in the buffer. */
640+ *dst = L'\0';
641+
642+ /*
643+ * Output loop.
644+ * Convert wchar_t string back to multibyte output string.
645+ * If we have hit a multi-byte conversion error on input,
646+ * output byte-by-byte here. Else use wctomb().
647+ */
648+ len = wcslen(start);
649+ if (dlen) {
650+ maxolen = *dlen;
651+ if (maxolen == 0) {
652+ errno = ENOSPC;
653+ goto out;
654+ }
655+ } else {
656+ if (len > (SIZE_MAX - 1)/MB_LEN_MAX) {
657+ errno = ENOSPC;
658+ goto out;
659+ }
660+ maxolen = len*MB_LEN_MAX + 1;
661+ }
662+ olen = 0;
663+ memset(&mbstate, 0, sizeof(mbstate));
664+ for (dst = start; len > 0; len--) {
665+ if (!cerr) {
666+ /*
667+ * If we have at least MB_CUR_MAX bytes in the buffer,
668+ * we'll just do the conversion in-place into mbdst. We
669+ * need to be a little more conservative when we get to
670+ * the end of the buffer, as we may not have MB_CUR_MAX
671+ * bytes but we may not need it.
672+ */
673+ if (maxolen - olen > MB_CUR_MAX)
674+ mbwrite = mbdst;
675+ else
676+ mbwrite = mbbuf;
677+ clen = (ssize_t)wcrtomb(mbwrite, *dst, &mbstate);
678+ if (clen > 0 && mbwrite != mbdst) {
679+ /*
680+ * Don't break past our output limit, noting
681+ * that maxolen includes the nul terminator so
682+ * we can't write past maxolen - 1 here.
683+ */
684+ if (olen + clen >= maxolen) {
685+ errno = ENOSPC;
686+ goto out;
687+ }
688+
689+ memcpy(mbdst, mbwrite, clen);
690+ }
691+ }
692+ if (cerr || clen < 0) {
693+ /*
694+ * Conversion error, process as a byte(s) instead.
695+ * Examine each byte and higher-order bytes for
696+ * data. E.g.,
697+ * 0x000000000000a264 -> a2 64
698+ * 0x000000001f00a264 -> 1f 00 a2 64
699+ */
700+ clen = 0;
701+ wmsk = 0;
702+ for (i = sizeof(wmsk) - 1; i >= 0; i--) {
703+ shft = i * NBBY;
704+ bmsk = (uint64_t)0xffLL << shft;
705+ wmsk |= bmsk;
706+ if ((*dst & wmsk) || i == 0) {
707+ if (olen + clen + 1 >= maxolen) {
708+ errno = ENOSPC;
709+ goto out;
710+ }
711
712-trunc:
713- *dst = '\0';
714- return -1;
715+ mbdst[clen++] = (char)(
716+ (uint64_t)(*dst & bmsk) >>
717+ shft);
718+ }
719+ }
720+ cerr = 1;
721+ }
722+
723+ /*
724+ * We'll be dereferencing mbdst[clen] after this to write the
725+ * nul terminator; the above paths should have checked for a
726+ * possible overflow already.
727+ */
728+ assert(olen + clen < maxolen);
729+
730+ /* Advance output pointer by number of bytes written. */
731+ mbdst += clen;
732+ /* Advance buffer character pointer. */
733+ dst++;
734+ /* Increment output character count. */
735+ olen += clen;
736+ }
737+
738+ /* Terminate the output string. */
739+ assert(olen < maxolen);
740+ *mbdst = '\0';
741+
742+ if (flags & VIS_NOLOCALE) {
743+ /* Pass conversion error flag out. */
744+ if (cerr_ptr)
745+ *cerr_ptr = cerr;
746+ }
747+
748+ free(extra);
749+ free(pdst);
750+ free(psrc);
751+
752+ return (int)olen;
753+out:
754+ free(extra);
755+ free(pdst);
756+ free(psrc);
757+ free(mdst);
758+ return error;
759+}
760+
761+static int
762+istrsenvisxl(char **mbdstp, size_t *dlen, const char *mbsrc,
763+ int flags, const char *mbextra, int *cerr_ptr)
764+{
765+ return istrsenvisx(mbdstp, dlen, mbsrc,
766+ mbsrc != NULL ? strlen(mbsrc) : 0, flags, mbextra, cerr_ptr);
767 }
768
769+#endif
770+
771+#if !HAVE_SVIS
772+/*
773+ * The "svis" variants all take an "extra" arg that is a pointer
774+ * to a NUL-terminated list of characters to be encoded, too.
775+ * These functions are useful e. g. to encode strings in such a
776+ * way so that they are not interpreted by a shell.
777+ */
778+
779 char *
780-vis(char *dst, int c, int flags, int nextc)
781+svis(char *mbdst, int c, int flags, int nextc, const char *mbextra)
782 {
783- char src[1];
784+ char cc[2];
785+ int ret;
786+
787+ cc[0] = c;
788+ cc[1] = nextc;
789
790- (void)nextc;
791- src[0] = (char)c;
792- if (strnvisx(dst, 5, src, 1, flags) == -1)
793+ ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, mbextra, NULL);
794+ if (ret < 0)
795 return NULL;
796- while (*dst != '\0')
797- dst++;
798- return dst;
799+ return mbdst + ret;
800+}
801+
802+char *
803+snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra)
804+{
805+ char cc[2];
806+ int ret;
807+
808+ cc[0] = c;
809+ cc[1] = nextc;
810+
811+ ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, mbextra, NULL);
812+ if (ret < 0)
813+ return NULL;
814+ return mbdst + ret;
815+}
816+
817+int
818+strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra)
819+{
820+ return istrsenvisxl(&mbdst, NULL, mbsrc, flags, mbextra, NULL);
821+}
822+
823+int
824+strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra)
825+{
826+ return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, mbextra, NULL);
827+}
828+
829+int
830+strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra)
831+{
832+ return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, mbextra, NULL);
833+}
834+
835+int
836+strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
837+ const char *mbextra)
838+{
839+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, NULL);
840+}
841+
842+int
843+strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
844+ const char *mbextra, int *cerr_ptr)
845+{
846+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr);
847+}
848+#endif
849+
850+#if !HAVE_VIS
851+/*
852+ * vis - visually encode characters
853+ */
854+char *
855+vis(char *mbdst, int c, int flags, int nextc)
856+{
857+ char cc[2];
858+ int ret;
859+
860+ cc[0] = c;
861+ cc[1] = nextc;
862+
863+ ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, "", NULL);
864+ if (ret < 0)
865+ return NULL;
866+ return mbdst + ret;
867+}
868+
869+char *
870+nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)
871+{
872+ char cc[2];
873+ int ret;
874+
875+ cc[0] = c;
876+ cc[1] = nextc;
877+
878+ ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, "", NULL);
879+ if (ret < 0)
880+ return NULL;
881+ return mbdst + ret;
882+}
883+
884+/*
885+ * strvis - visually encode characters from src into dst
886+ *
887+ * Dst must be 4 times the size of src to account for possible
888+ * expansion. The length of dst, not including the trailing NULL,
889+ * is returned.
890+ */
891+
892+int
893+strvis(char *mbdst, const char *mbsrc, int flags)
894+{
895+ return istrsenvisxl(&mbdst, NULL, mbsrc, flags, "", NULL);
896+}
897+
898+int
899+strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags)
900+{
901+ return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL);
902+}
903+
904+int
905+stravis(char **mbdstp, const char *mbsrc, int flags)
906+{
907+ *mbdstp = NULL;
908+ return istrsenvisxl(mbdstp, NULL, mbsrc, flags, "", NULL);
909+}
910+
911+/*
912+ * strvisx - visually encode characters from src into dst
913+ *
914+ * Dst must be 4 times the size of src to account for possible
915+ * expansion. The length of dst, not including the trailing NULL,
916+ * is returned.
917+ *
918+ * Strvisx encodes exactly len characters from src into dst.
919+ * This is useful for encoding a block of data.
920+ */
921+
922+int
923+strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)
924+{
925+ return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, "", NULL);
926+}
927+
928+int
929+strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags)
930+{
931+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", NULL);
932+}
933+
934+int
935+strenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
936+ int *cerr_ptr)
937+{
938+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);
939 }
940+#endif
+110,
-11
1@@ -1,22 +1,121 @@
2+/* $NetBSD: vis.h,v 1.26 2022/05/20 21:31:24 andvar Exp $ */
3+
4+/*-
5+ * Copyright (c) 1990, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ *
32+ * @(#)vis.h 8.1 (Berkeley) 6/2/93
33+ */
34+
35 #ifndef _VIS_H_
36-#define _VIS_H_
37+#define _VIS_H_
38
39 #include <sys/types.h>
40-#include <sys/cdefs.h>
41
42-#define VIS_OCTAL 0x0001
43-#define VIS_CSTYLE 0x0002
44-#define VIS_SP 0x0004
45-#define VIS_TAB 0x0008
46-#define VIS_NL 0x0010
47+/*
48+ * to select alternate encoding format
49+ */
50+#define VIS_OCTAL 0x0001 /* use octal \ddd format */
51+#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropriate */
52+
53+/*
54+ * to alter set of characters encoded (default is to encode all
55+ * non-graphic except space, tab, and newline).
56+ */
57+#define VIS_SP 0x0004 /* also encode space */
58+#define VIS_TAB 0x0008 /* also encode tab */
59+#define VIS_NL 0x0010 /* also encode newline */
60 #define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
61-#define VIS_SAFE 0x0020
62-#define VIS_DQ 0x8000
63-#define VIS_NOSLASH 0x0040
64+#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
65+#define VIS_DQ 0x8000 /* also encode double quotes */
66+
67+/*
68+ * other
69+ */
70+#define VIS_NOSLASH 0x0040 /* inhibit printing '\' */
71+#define VIS_HTTP1808 0x0080 /* http-style escape % hex hex */
72+#define VIS_HTTPSTYLE 0x0080 /* http-style escape % hex hex */
73+#define VIS_MIMESTYLE 0x0100 /* mime-style escape = HEX HEX */
74+#define VIS_HTTP1866 0x0200 /* http-style &#num; or &string; */
75+#define VIS_NOESCAPE 0x0400 /* don't decode `\' */
76+#define _VIS_END 0x0800 /* for unvis */
77+#define VIS_GLOB 0x1000 /* encode glob(3) magic characters */
78+#define VIS_SHELL 0x2000 /* encode shell special characters [not glob] */
79+#define VIS_META (VIS_WHITE | VIS_GLOB | VIS_SHELL)
80+#define VIS_NOLOCALE 0x4000 /* encode using the C locale */
81+
82+/*
83+ * unvis return codes
84+ */
85+#define UNVIS_VALID 1 /* character valid */
86+#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
87+#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
88+#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
89+#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
90+
91+/*
92+ * unvis flags
93+ */
94+#define UNVIS_END _VIS_END /* no more characters */
95+
96+#include <sys/cdefs.h>
97
98 __BEGIN_DECLS
99 char *vis(char *, int, int, int);
100+char *nvis(char *, size_t, int, int, int);
101+
102+char *svis(char *, int, int, int, const char *);
103+char *snvis(char *, size_t, int, int, int, const char *);
104+
105+int strvis(char *, const char *, int);
106+int stravis(char **, const char *, int);
107+int strnvis(char *, size_t, const char *, int);
108+
109+int strsvis(char *, const char *, int, const char *);
110+int strsnvis(char *, size_t, const char *, int, const char *);
111+
112+int strvisx(char *, const char *, size_t, int);
113 int strnvisx(char *, size_t, const char *, size_t, int);
114-__END_DECLS
115+int strenvisx(char *, size_t, const char *, size_t, int, int *);
116+
117+int strsvisx(char *, const char *, size_t, int, const char *);
118+int strsnvisx(char *, size_t, const char *, size_t, int, const char *);
119+int strsenvisx(char *, size_t, const char *, size_t , int, const char *,
120+ int *);
121
122+int strunvis(char *, const char *);
123+int strnunvis(char *, size_t, const char *);
124+
125+int strunvisx(char *, const char *, int);
126+int strnunvisx(char *, size_t, const char *, int);
127+
128+#ifndef __LIBC12_SOURCE__
129+int unvis(char *, int, int *, int) __RENAME(__unvis50);
130 #endif
131+__END_DECLS
132+
133+#endif /* !_VIS_H_ */
1@@ -1,8 +1,8 @@
2 .POSIX:
3
4 PROG = ctags
5-SRCS = C.c ctags.c fortran.c lisp.c print.c tree.c yacc.c \
6- ../compat/strlcpy.c ../compat/shquote.c
7+SRCS = C.c ctags.c fortran.c lisp.c print.c tree.c yacc.c
8+COMPATLIB = ../compat/libnetcompat.a
9 MAN = ctags.1
10
11 CC = cc
12@@ -14,8 +14,11 @@ MANDIR = /usr/local/share/man
13
14 all: $(PROG)
15
16-$(PROG): $(SRCS)
17- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
18+$(PROG): $(SRCS) $(COMPATLIB)
19+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
20+
21+$(COMPATLIB):
22+ (cd ../compat && $(MAKE) all)
23
24 install: $(PROG)
25 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+7,
-5
1@@ -1,9 +1,8 @@
2 .POSIX:
3
4 PROG = finger
5-SRCS = finger.c lprint.c net.c sprint.c util.c utmpentry.c \
6- ../compat/strlcpy.c ../compat/reallocarr.c ../compat/db.c \
7- ../compat/vis.c
8+SRCS = finger.c lprint.c net.c sprint.c util.c utmpentry.c
9+COMPATLIB = ../compat/libnetcompat.a
10 MAN = finger.1
11
12 CC = cc
13@@ -16,8 +15,11 @@ MANDIR = /usr/local/share/man
14
15 all: $(PROG)
16
17-$(PROG): $(SRCS)
18- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
19+$(PROG): $(SRCS) $(COMPATLIB)
20+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
21+
22+$(COMPATLIB):
23+ (cd ../compat && $(MAKE) all)
24
25 install: $(PROG)
26 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+7,
-3
1@@ -1,7 +1,8 @@
2 .POSIX:
3
4 PROG = jot
5-SRCS = jot.c ../compat/getprogname.c ../compat/strlcpy.c
6+SRCS = jot.c
7+COMPATLIB = ../compat/libnetcompat.a
8 MAN = jot.1
9
10 CC = cc
11@@ -14,8 +15,11 @@ MANDIR = /usr/local/share/man
12
13 all: $(PROG)
14
15-$(PROG): $(SRCS)
16- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
17+$(PROG): $(SRCS) $(COMPATLIB)
18+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
19+
20+$(COMPATLIB):
21+ (cd ../compat && $(MAKE) all)
22
23 install: $(PROG)
24 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+6,
-2
1@@ -2,6 +2,7 @@
2
3 PROG = look
4 SRCS = look.c
5+COMPATLIB = ../compat/libnetcompat.a
6 MAN = look.1
7 DICT = words
8
9@@ -15,8 +16,11 @@ DATADIR = /usr/local/share
10
11 all: $(PROG)
12
13-$(PROG): $(SRCS)
14- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
15+$(PROG): $(SRCS) $(COMPATLIB)
16+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
17+
18+$(COMPATLIB):
19+ (cd ../compat && $(MAKE) all)
20
21 install: $(PROG)
22 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 \
+40,
-0
1@@ -0,0 +1,40 @@
2+.POSIX:
3+
4+PROG = makefs
5+COMPATLIB = ../compat/libnetcompat.a
6+MAN = makefs.8
7+
8+CC = cc
9+CFLAGS = -O2
10+CPPFLAGS = -DHAVE_NBTOOL_CONFIG_H=1 -I. -I./cd9660 -I./mtree -I./fs/cd9660 -I../compat -include ../compat/netcompat.h
11+LDLIBS = -lm -lz
12+
13+SRCS = \
14+ makefs.c walk.c \
15+ cd9660.c \
16+ cd9660/cd9660_strings.c cd9660/cd9660_debug.c cd9660/cd9660_eltorito.c \
17+ cd9660/cd9660_write.c cd9660/cd9660_conversion.c cd9660/iso9660_rrip.c \
18+ cd9660/cd9660_archimedes.c \
19+ mtree/getid.c mtree/misc.c mtree/spec.c mtree/pack_dev.c mtree/stat_flags.c
20+
21+DESTDIR =
22+BINDIR = /usr/local/bin
23+MANDIR = /usr/local/share/man
24+
25+all: $(PROG)
26+
27+$(PROG): $(SRCS) $(COMPATLIB)
28+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
29+
30+$(COMPATLIB):
31+ (cd ../compat && $(MAKE) all)
32+
33+install: $(PROG)
34+ mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
35+ cp $(PROG) $(DESTDIR)$(BINDIR)/$(PROG)
36+ chmod 755 $(DESTDIR)$(BINDIR)/$(PROG)
37+ cp $(MAN) $(DESTDIR)$(MANDIR)/man8/$(MAN)
38+ chmod 644 $(DESTDIR)$(MANDIR)/man8/$(MAN)
39+
40+clean:
41+ rm -f $(PROG) *.o */*.o */*/*.o
+2153,
-0
1@@ -0,0 +1,2153 @@
2+/* $NetBSD: cd9660.c,v 1.61 2026/01/07 16:04:51 nia Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+/*
36+ * Copyright (c) 2001 Wasabi Systems, Inc.
37+ * All rights reserved.
38+ *
39+ * Written by Luke Mewburn for Wasabi Systems, Inc.
40+ *
41+ * Redistribution and use in source and binary forms, with or without
42+ * modification, are permitted provided that the following conditions
43+ * are met:
44+ * 1. Redistributions of source code must retain the above copyright
45+ * notice, this list of conditions and the following disclaimer.
46+ * 2. Redistributions in binary form must reproduce the above copyright
47+ * notice, this list of conditions and the following disclaimer in the
48+ * documentation and/or other materials provided with the distribution.
49+ * 3. All advertising materials mentioning features or use of this software
50+ * must display the following acknowledgement:
51+ * This product includes software developed for the NetBSD Project by
52+ * Wasabi Systems, Inc.
53+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
54+ * or promote products derived from this software without specific prior
55+ * written permission.
56+ *
57+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
58+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
61+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67+ * POSSIBILITY OF SUCH DAMAGE.
68+ */
69+/*
70+ * Copyright (c) 1982, 1986, 1989, 1993
71+ * The Regents of the University of California. All rights reserved.
72+ *
73+ * Redistribution and use in source and binary forms, with or without
74+ * modification, are permitted provided that the following conditions
75+ * are met:
76+ * 1. Redistributions of source code must retain the above copyright
77+ * notice, this list of conditions and the following disclaimer.
78+ * 2. Redistributions in binary form must reproduce the above copyright
79+ * notice, this list of conditions and the following disclaimer in the
80+ * documentation and/or other materials provided with the distribution.
81+ * 3. Neither the name of the University nor the names of its contributors
82+ * may be used to endorse or promote products derived from this software
83+ * without specific prior written permission.
84+ *
85+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95+ * SUCH DAMAGE.
96+ *
97+ */
98+
99+#if HAVE_NBTOOL_CONFIG_H
100+#include "nbtool_config.h"
101+#else
102+#include <sys/mount.h>
103+#endif
104+
105+#include <sys/cdefs.h>
106+#if defined(__RCSID) && !defined(__lint)
107+__RCSID("$NetBSD: cd9660.c,v 1.61 2026/01/07 16:04:51 nia Exp $");
108+#endif /* !__lint */
109+
110+#include <string.h>
111+#include <ctype.h>
112+#include <sys/param.h>
113+#include <sys/queue.h>
114+#include <util.h>
115+
116+#include "makefs.h"
117+#include "cd9660.h"
118+#include "cd9660/iso9660_rrip.h"
119+#include "cd9660/cd9660_archimedes.h"
120+
121+/*
122+ * Global variables
123+ */
124+
125+static void cd9660_finalize_PVD(iso9660_disk *);
126+static cd9660node *cd9660_allocate_cd9660node(void);
127+static void cd9660_set_defaults(iso9660_disk *);
128+static int cd9660_arguments_set_string(const char *, const char *, size_t,
129+ char, char *);
130+static void cd9660_populate_iso_dir_record(
131+ struct _iso_directory_record_cd9660 *, u_char, u_char, u_char,
132+ const char *);
133+static void cd9660_setup_root_node(iso9660_disk *);
134+static int cd9660_setup_volume_descriptors(iso9660_disk *);
135+#if 0
136+static int cd9660_fill_extended_attribute_record(cd9660node *);
137+#endif
138+static void cd9660_sort_nodes(cd9660node *);
139+static int cd9660_translate_node_common(iso9660_disk *, cd9660node *);
140+static int cd9660_translate_node(iso9660_disk *, fsnode *, cd9660node *);
141+static int cd9660_compare_filename(const char *, const char *);
142+static void cd9660_sorted_child_insert(cd9660node *, cd9660node *);
143+static int cd9660_handle_collisions(iso9660_disk *, cd9660node *, int);
144+static cd9660node *cd9660_rename_filename(iso9660_disk *, cd9660node *, int,
145+ int);
146+static void cd9660_copy_filenames(iso9660_disk *, cd9660node *);
147+static void cd9660_sorting_nodes(cd9660node *);
148+static int cd9660_count_collisions(cd9660node *);
149+static cd9660node *cd9660_rrip_move_directory(iso9660_disk *, cd9660node *);
150+static int cd9660_add_dot_records(iso9660_disk *, cd9660node *);
151+
152+static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int,
153+ int *, int *);
154+static void cd9660_free_structure(cd9660node *);
155+static int cd9660_generate_path_table(iso9660_disk *);
156+static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *,
157+ int);
158+static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *,
159+ int);
160+#if 0
161+static int cd9660_joliet_convert_filename(iso9660_disk *, const char *, char *,
162+ int);
163+#endif
164+static int cd9660_convert_filename(iso9660_disk *, const char *, char *, int);
165+static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *);
166+static int64_t cd9660_compute_offsets(iso9660_disk *, cd9660node *, int64_t);
167+#if 0
168+static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int);
169+#endif
170+static cd9660node *cd9660_create_virtual_entry(iso9660_disk *, const char *,
171+ cd9660node *, int, int);
172+static cd9660node *cd9660_create_file(iso9660_disk *, const char *,
173+ cd9660node *, cd9660node *);
174+static cd9660node *cd9660_create_directory(iso9660_disk *, const char *,
175+ cd9660node *, cd9660node *);
176+static cd9660node *cd9660_create_special_directory(iso9660_disk *, u_char,
177+ cd9660node *);
178+static int cd9660_add_generic_bootimage(iso9660_disk *, const char *);
179+
180+
181+/*
182+ * Allocate and initialize a cd9660node
183+ * @returns struct cd9660node * Pointer to new node, or NULL on error
184+ */
185+static cd9660node *
186+cd9660_allocate_cd9660node(void)
187+{
188+ cd9660node *temp = ecalloc(1, sizeof(*temp));
189+ TAILQ_INIT(&temp->cn_children);
190+ temp->parent = temp->dot_record = temp->dot_dot_record = NULL;
191+ temp->ptnext = temp->ptprev = temp->ptlast = NULL;
192+ temp->node = NULL;
193+ temp->isoDirRecord = NULL;
194+ temp->isoExtAttributes = NULL;
195+ temp->rr_real_parent = temp->rr_relocated = NULL;
196+ temp->su_tail_data = NULL;
197+ return temp;
198+}
199+
200+int cd9660_defaults_set = 0;
201+
202+/**
203+* Set default values for cd9660 extension to makefs
204+*/
205+static void
206+cd9660_set_defaults(iso9660_disk *diskStructure)
207+{
208+ /*Fix the sector size for now, though the spec allows for other sizes*/
209+ diskStructure->sectorSize = 2048;
210+
211+ /* Set up defaults in our own structure */
212+ diskStructure->verbose_level = 0;
213+ diskStructure->keep_bad_images = 0;
214+ diskStructure->follow_sym_links = 0;
215+ diskStructure->isoLevel = 2;
216+
217+ diskStructure->rock_ridge_enabled = 0;
218+ diskStructure->rock_ridge_renamed_dir_name = 0;
219+ diskStructure->rock_ridge_move_count = 0;
220+ diskStructure->rr_moved_dir = 0;
221+
222+ diskStructure->archimedes_enabled = 0;
223+ diskStructure->chrp_boot = 0;
224+
225+ diskStructure->include_padding_areas = 1;
226+
227+ /* Spec breaking functionality */
228+ diskStructure->allow_deep_trees =
229+ diskStructure->allow_start_dot =
230+ diskStructure->allow_max_name =
231+ diskStructure->allow_illegal_chars =
232+ diskStructure->allow_lowercase =
233+ diskStructure->allow_multidot =
234+ diskStructure->omit_trailing_period = 0;
235+
236+ /* Make sure the PVD is clear */
237+ memset(&diskStructure->primaryDescriptor, 0, 2048);
238+
239+ memset(diskStructure->primaryDescriptor.publisher_id, 0x20,128);
240+ memset(diskStructure->primaryDescriptor.preparer_id, 0x20,128);
241+ memset(diskStructure->primaryDescriptor.application_id, 0x20,128);
242+ memset(diskStructure->primaryDescriptor.copyright_file_id, 0x20,37);
243+ memset(diskStructure->primaryDescriptor.abstract_file_id, 0x20,37);
244+ memset(diskStructure->primaryDescriptor.bibliographic_file_id, 0x20,37);
245+
246+ strcpy(diskStructure->primaryDescriptor.system_id,"NetBSD");
247+
248+ cd9660_defaults_set = 1;
249+
250+ /* Boot support: Initially disabled */
251+ diskStructure->has_generic_bootimage = 0;
252+ diskStructure->generic_bootimage = NULL;
253+
254+ diskStructure->boot_image_directory = 0;
255+ /*memset(diskStructure->boot_descriptor, 0, 2048);*/
256+
257+ diskStructure->is_bootable = 0;
258+ TAILQ_INIT(&diskStructure->boot_images);
259+ LIST_INIT(&diskStructure->boot_entries);
260+}
261+
262+void
263+cd9660_prep_opts(fsinfo_t *fsopts)
264+{
265+ iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure));
266+
267+#define OPT_STR(letter, name, desc) \
268+ { letter, name, NULL, OPT_STRBUF, 0, 0, desc }
269+
270+#define OPT_NUM(letter, name, field, min, max, desc) \
271+ { letter, name, &diskStructure->field, \
272+ sizeof(diskStructure->field) == 8 ? OPT_INT64 : \
273+ (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \
274+ (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \
275+ min, max, desc }
276+
277+#define OPT_BOOL(letter, name, field, desc) \
278+ OPT_NUM(letter, name, field, 0, 1, desc)
279+
280+ const option_t cd9660_options[] = {
281+ OPT_NUM('l', "isolevel", isoLevel,
282+ 1, 3, "ISO Level"),
283+ OPT_NUM('v', "verbose", verbose_level,
284+ 0, 2, "Turns on verbose output"),
285+
286+ OPT_BOOL('h', "help", displayHelp,
287+ "Show help message"),
288+ OPT_BOOL('S', "follow-symlinks", follow_sym_links,
289+ "Resolve symlinks in pathnames"),
290+ OPT_BOOL('R', "rockridge", rock_ridge_enabled,
291+ "Enable Rock-Ridge extensions"),
292+ OPT_BOOL('C', "chrp-boot", chrp_boot,
293+ "Enable CHRP boot"),
294+ OPT_BOOL('K', "keep-bad-images", keep_bad_images,
295+ "Keep bad images"),
296+ OPT_BOOL('D', "allow-deep-trees", allow_deep_trees,
297+ "Allow trees more than 8 levels"),
298+ OPT_BOOL('a', "allow-max-name", allow_max_name,
299+ "Allow 37 char filenames (unimplemented)"),
300+ OPT_BOOL('i', "allow-illegal-chars", allow_illegal_chars,
301+ "Allow illegal characters in filenames"),
302+ OPT_BOOL('m', "allow-multidot", allow_multidot,
303+ "Allow multiple periods in filenames"),
304+ OPT_BOOL('o', "omit-trailing-period", omit_trailing_period,
305+ "Omit trailing periods in filenames"),
306+ OPT_BOOL('\0', "allow-lowercase", allow_lowercase,
307+ "Allow lowercase characters in filenames"),
308+ OPT_BOOL('\0', "archimedes", archimedes_enabled,
309+ "Enable Archimedes structure"),
310+ OPT_BOOL('\0', "no-trailing-padding", include_padding_areas,
311+ "Include padding areas"),
312+
313+ OPT_STR('A', "applicationid", "Application Identifier"),
314+ OPT_STR('P', "publisher", "Publisher Identifier"),
315+ OPT_STR('p', "preparer", "Preparer Identifier"),
316+ OPT_STR('L', "label", "Disk Label"),
317+ OPT_STR('V', "volumeid", "Volume Set Identifier"),
318+ OPT_STR('B', "bootimage", "Boot image parameter"),
319+ OPT_STR('G', "generic-bootimage", "Generic boot image param"),
320+ OPT_STR('\0', "bootimagedir", "Boot image directory"),
321+ OPT_STR('\0', "no-emul-boot", "No boot emulation"),
322+ OPT_STR('\0', "no-boot", "No boot support"),
323+ OPT_STR('\0', "hard-disk-boot", "Boot from hard disk"),
324+ OPT_STR('\0', "boot-load-segment", "Boot load segment"),
325+ OPT_STR('\0', "platformid", "Section Header Platform ID"),
326+
327+ { .name = NULL }
328+ };
329+
330+ fsopts->fs_specific = diskStructure;
331+ fsopts->fs_options = copy_opts(cd9660_options);
332+
333+ cd9660_set_defaults(diskStructure);
334+}
335+
336+void
337+cd9660_cleanup_opts(fsinfo_t *fsopts)
338+{
339+ free(fsopts->fs_specific);
340+ free(fsopts->fs_options);
341+}
342+
343+static int
344+cd9660_arguments_set_string(const char *val, const char *fieldtitle,
345+ size_t length, char testmode, char * dest)
346+{
347+ size_t len;
348+ int test;
349+
350+ if (val == NULL)
351+ warnx("error: The %s requires a string argument", fieldtitle);
352+ else if ((len = strlen(val)) <= length) {
353+ if (testmode == 'd')
354+ test = cd9660_valid_d_chars(val);
355+ else
356+ test = cd9660_valid_a_chars(val);
357+ if (test) {
358+ memcpy(dest, val, len);
359+ if (test == 2)
360+ cd9660_uppercase_characters(dest, len);
361+ return 1;
362+ } else
363+ warnx("error: The %s must be composed of "
364+ "%c-characters", fieldtitle, testmode);
365+ } else
366+ warnx("error: The %s must be at most 32 characters long",
367+ fieldtitle);
368+ return 0;
369+}
370+
371+/*
372+ * Command-line parsing function
373+ */
374+
375+int
376+cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
377+{
378+ int rv, i;
379+ iso9660_disk *diskStructure = fsopts->fs_specific;
380+ option_t *cd9660_options = fsopts->fs_options;
381+ char buf[1024];
382+ const char *name, *desc;
383+
384+ assert(option != NULL);
385+
386+ if (debug & DEBUG_FS_PARSE_OPTS)
387+ printf("%s: got `%s'\n", __func__, option);
388+
389+ i = set_option(cd9660_options, option, buf, sizeof(buf));
390+ if (i == -1)
391+ return 0;
392+
393+ if (cd9660_options[i].name == NULL)
394+ abort();
395+
396+
397+ name = cd9660_options[i].name;
398+ desc = cd9660_options[i].desc;
399+ switch (cd9660_options[i].letter) {
400+ case 'h':
401+ case 'S':
402+ rv = 0; /* this is not handled yet */
403+ break;
404+ case 'L':
405+ rv = cd9660_arguments_set_string(buf, desc, 32, 'd',
406+ diskStructure->primaryDescriptor.volume_id);
407+ break;
408+ case 'A':
409+ rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
410+ diskStructure->primaryDescriptor.application_id);
411+ break;
412+ case 'P':
413+ rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
414+ diskStructure->primaryDescriptor.publisher_id);
415+ break;
416+ case 'p':
417+ rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
418+ diskStructure->primaryDescriptor.preparer_id);
419+ break;
420+ case 'V':
421+ rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
422+ diskStructure->primaryDescriptor.volume_set_id);
423+ break;
424+ /* Boot options */
425+ case 'B':
426+ if (buf[0] == '\0') {
427+ warnx("The Boot Image parameter requires a valid boot"
428+ " information string");
429+ rv = 0;
430+ } else
431+ rv = cd9660_add_boot_disk(diskStructure, buf);
432+ break;
433+ case 'G':
434+ if (buf[0] == '\0') {
435+ warnx("The Generic Boot Image parameter requires a"
436+ " valid boot information string");
437+ rv = 0;
438+ } else
439+ rv = cd9660_add_generic_bootimage(diskStructure, buf);
440+ break;
441+ default:
442+ if (strcmp(name, "bootimagedir") == 0) {
443+ /*
444+ * XXXfvdl this is unused.
445+ */
446+ if (buf[0] == '\0') {
447+ warnx("The Boot Image Directory parameter"
448+ " requires a directory name");
449+ rv = 0;
450+ } else {
451+ diskStructure->boot_image_directory =
452+ emalloc(strlen(buf) + 1);
453+ /* BIG TODO: Add the max length function here */
454+ rv = cd9660_arguments_set_string(buf, desc, 12,
455+ 'd', diskStructure->boot_image_directory);
456+ }
457+ } else if (strcmp(name, "no-emul-boot") == 0 ||
458+ strcmp(name, "no-boot") == 0 ||
459+ strcmp(name, "hard-disk-boot") == 0) {
460+ /* RRIP */
461+ cd9660_eltorito_add_boot_option(diskStructure, name, 0);
462+ rv = 1;
463+ } else if (strcmp(name, "boot-load-segment") == 0 ||
464+ strcmp(name, "platformid") == 0) {
465+ if (buf[0] == '\0') {
466+ warnx("Option `%s' doesn't contain a value",
467+ name);
468+ rv = 0;
469+ } else {
470+ cd9660_eltorito_add_boot_option(diskStructure,
471+ name, buf);
472+ rv = 1;
473+ }
474+ } else
475+ rv = 1;
476+ }
477+ return rv;
478+}
479+
480+/*
481+ * Main function for cd9660_makefs
482+ * Builds the ISO image file
483+ * @param const char *image The image filename to create
484+ * @param const char *dir The directory that is being read
485+ * @param struct fsnode *root The root node of the filesystem tree
486+ * @param struct fsinfo_t *fsopts Any options
487+ */
488+void
489+cd9660_makefs(const char *image, const char *dir, fsnode *root,
490+ fsinfo_t *fsopts)
491+{
492+ int64_t startoffset;
493+ int numDirectories;
494+ uint64_t pathTableSectors;
495+ int64_t firstAvailableSector;
496+ int64_t totalSpace;
497+ int error;
498+ cd9660node *real_root;
499+ iso9660_disk *diskStructure = fsopts->fs_specific;
500+
501+ if (diskStructure->verbose_level > 0)
502+ printf("%s: ISO level is %i\n", __func__,
503+ diskStructure->isoLevel);
504+ if (diskStructure->isoLevel < 2 &&
505+ diskStructure->allow_multidot)
506+ errx(EXIT_FAILURE, "allow-multidot requires iso level of 2");
507+
508+ assert(image != NULL);
509+ assert(dir != NULL);
510+ assert(root != NULL);
511+
512+ if (diskStructure->displayHelp) {
513+ /*
514+ * Display help here - probably want to put it in
515+ * a separate function
516+ */
517+ return;
518+ }
519+
520+ if (diskStructure->verbose_level > 0)
521+ printf("%s: image %s directory %s root %p\n", __func__,
522+ image, dir, root);
523+
524+ /* Set up some constants. Later, these will be defined with options */
525+
526+ /* Counter needed for path tables */
527+ numDirectories = 0;
528+
529+ /* Convert tree to our own format */
530+ /* Actually, we now need to add the REAL root node, at level 0 */
531+
532+ real_root = cd9660_allocate_cd9660node();
533+ real_root->isoDirRecord = emalloc(sizeof(*real_root->isoDirRecord));
534+ /* Leave filename blank for root */
535+ memset(real_root->isoDirRecord->name, 0,
536+ ISO_FILENAME_MAXLENGTH_WITH_PADDING);
537+
538+ real_root->level = 0;
539+ diskStructure->rootNode = real_root;
540+ real_root->type = CD9660_TYPE_DIR;
541+ error = 0;
542+ real_root->node = root;
543+ cd9660_convert_structure(diskStructure, root, real_root, 1,
544+ &numDirectories, &error);
545+
546+ if (TAILQ_EMPTY(&real_root->cn_children)) {
547+ errx(EXIT_FAILURE, "%s: converted directory is empty. "
548+ "Tree conversion failed", __func__);
549+ } else if (error != 0) {
550+ errx(EXIT_FAILURE, "%s: tree conversion failed", __func__);
551+ } else {
552+ if (diskStructure->verbose_level > 0)
553+ printf("%s: tree converted\n", __func__);
554+ }
555+
556+ /* Add the dot and dot dot records */
557+ cd9660_add_dot_records(diskStructure, real_root);
558+
559+ cd9660_setup_root_node(diskStructure);
560+
561+ if (diskStructure->verbose_level > 0)
562+ printf("%s: done converting tree\n", __func__);
563+
564+ /* non-SUSP extensions */
565+ if (diskStructure->archimedes_enabled)
566+ archimedes_convert_tree(diskStructure->rootNode);
567+
568+ /* Rock ridge / SUSP init pass */
569+ if (diskStructure->rock_ridge_enabled) {
570+ cd9660_susp_initialize(diskStructure, diskStructure->rootNode,
571+ diskStructure->rootNode, NULL);
572+ }
573+
574+ /* Build path table structure */
575+ diskStructure->pathTableLength = cd9660_generate_path_table(
576+ diskStructure);
577+
578+ pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize,
579+ diskStructure->pathTableLength);
580+
581+ firstAvailableSector = cd9660_setup_volume_descriptors(diskStructure);
582+ if (diskStructure->is_bootable) {
583+ firstAvailableSector = cd9660_setup_boot(diskStructure,
584+ firstAvailableSector);
585+ if (firstAvailableSector < 0)
586+ errx(EXIT_FAILURE, "setup_boot failed");
587+ }
588+ /* LE first, then BE */
589+ diskStructure->primaryLittleEndianTableSector = firstAvailableSector;
590+ diskStructure->primaryBigEndianTableSector =
591+ diskStructure->primaryLittleEndianTableSector + pathTableSectors;
592+
593+ /* Set the secondary ones to -1, not going to use them for now */
594+ diskStructure->secondaryBigEndianTableSector = -1;
595+ diskStructure->secondaryLittleEndianTableSector = -1;
596+
597+ diskStructure->dataFirstSector =
598+ diskStructure->primaryBigEndianTableSector + pathTableSectors;
599+ if (diskStructure->verbose_level > 0)
600+ printf("%s: Path table conversion complete. "
601+ "Each table is %i bytes, or %" PRIu64 " sectors.\n",
602+ __func__,
603+ diskStructure->pathTableLength, pathTableSectors);
604+
605+ startoffset = diskStructure->sectorSize*diskStructure->dataFirstSector;
606+
607+ totalSpace = cd9660_compute_offsets(diskStructure, real_root, startoffset);
608+
609+ if ((fsopts->maxsize > 0) && (totalSpace > fsopts->maxsize))
610+ errx(EXIT_FAILURE, "won't fit due to set maximum disk size");
611+
612+ diskStructure->totalSectors = diskStructure->dataFirstSector +
613+ CD9660_BLOCKS(diskStructure->sectorSize, totalSpace);
614+
615+ /* Disabled until pass 1 is done */
616+ if (diskStructure->rock_ridge_enabled) {
617+ diskStructure->susp_continuation_area_start_sector =
618+ diskStructure->totalSectors;
619+ diskStructure->totalSectors +=
620+ CD9660_BLOCKS(diskStructure->sectorSize,
621+ diskStructure->susp_continuation_area_size);
622+ cd9660_susp_finalize(diskStructure, diskStructure->rootNode);
623+ }
624+
625+
626+ cd9660_finalize_PVD(diskStructure);
627+
628+ /* Add padding sectors, just for testing purposes right now */
629+ /* diskStructure->totalSectors+=150; */
630+
631+ /* Debugging output */
632+ if (diskStructure->verbose_level > 0) {
633+ printf("%s: Sectors 0-15 reserved\n", __func__);
634+ printf("%s: Primary path tables starts in sector %"
635+ PRId64 "\n", __func__,
636+ diskStructure->primaryLittleEndianTableSector);
637+ printf("%s: File data starts in sector %"
638+ PRId64 "\n", __func__, diskStructure->dataFirstSector);
639+ printf("%s: Total sectors: %"
640+ PRId64 "\n", __func__, diskStructure->totalSectors);
641+ }
642+
643+ /*
644+ * Add padding sectors at the end
645+ * TODO: Clean this up and separate padding
646+ */
647+ if (diskStructure->include_padding_areas)
648+ diskStructure->totalSectors += 150;
649+
650+ cd9660_write_image(diskStructure, image);
651+
652+ if (diskStructure->verbose_level > 1) {
653+ debug_print_volume_descriptor_information(diskStructure);
654+ debug_print_tree(diskStructure, real_root, 0);
655+ debug_print_path_tree(real_root);
656+ }
657+
658+ /* Clean up data structures */
659+ cd9660_free_structure(real_root);
660+
661+ if (diskStructure->verbose_level > 0)
662+ printf("%s: done\n", __func__);
663+}
664+
665+/* Generic function pointer - implement later */
666+typedef int (*cd9660node_func)(cd9660node *);
667+
668+static void
669+cd9660_finalize_PVD(iso9660_disk *diskStructure)
670+{
671+ time_t tstamp = stampst.st_ino ? stampst.st_mtime : time(NULL);
672+
673+ /* root should be a fixed size of 34 bytes since it has no name */
674+ memcpy(diskStructure->primaryDescriptor.root_directory_record,
675+ diskStructure->rootNode->dot_record->isoDirRecord, 34);
676+
677+ /* In RRIP, this might be longer than 34 */
678+ diskStructure->primaryDescriptor.root_directory_record[0] = 34;
679+
680+ /* Set up all the important numbers in the PVD */
681+ cd9660_bothendian_dword(diskStructure->totalSectors,
682+ (unsigned char *)diskStructure->primaryDescriptor.volume_space_size);
683+ cd9660_bothendian_word(1,
684+ (unsigned char *)diskStructure->primaryDescriptor.volume_set_size);
685+ cd9660_bothendian_word(1,
686+ (unsigned char *)
687+ diskStructure->primaryDescriptor.volume_sequence_number);
688+ cd9660_bothendian_word(diskStructure->sectorSize,
689+ (unsigned char *)
690+ diskStructure->primaryDescriptor.logical_block_size);
691+ cd9660_bothendian_dword(diskStructure->pathTableLength,
692+ (unsigned char *)diskStructure->primaryDescriptor.path_table_size);
693+
694+ cd9660_731(diskStructure->primaryLittleEndianTableSector,
695+ (u_char *)diskStructure->primaryDescriptor.type_l_path_table);
696+ cd9660_732(diskStructure->primaryBigEndianTableSector,
697+ (u_char *)diskStructure->primaryDescriptor.type_m_path_table);
698+
699+ diskStructure->primaryDescriptor.file_structure_version[0] = 1;
700+
701+ /* Pad all strings with spaces instead of nulls */
702+ cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32);
703+ cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32);
704+ cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id,
705+ 128);
706+ cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id,
707+ 128);
708+ cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id,
709+ 128);
710+ cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id,
711+ 128);
712+ cd9660_pad_string_spaces(
713+ diskStructure->primaryDescriptor.copyright_file_id, 37);
714+ cd9660_pad_string_spaces(
715+ diskStructure->primaryDescriptor.abstract_file_id, 37);
716+ cd9660_pad_string_spaces(
717+ diskStructure->primaryDescriptor.bibliographic_file_id, 37);
718+
719+ /* Setup dates */
720+ cd9660_time_8426(
721+ (unsigned char *)diskStructure->primaryDescriptor.creation_date,
722+ tstamp);
723+ cd9660_time_8426(
724+ (unsigned char *)diskStructure->primaryDescriptor.modification_date,
725+ tstamp);
726+
727+#if 0
728+ cd9660_set_date(diskStructure->primaryDescriptor.expiration_date,
729+ tstamp);
730+#endif
731+ memset(diskStructure->primaryDescriptor.expiration_date, '0' ,16);
732+ diskStructure->primaryDescriptor.expiration_date[16] = 0;
733+
734+ cd9660_time_8426(
735+ (unsigned char *)diskStructure->primaryDescriptor.effective_date,
736+ tstamp);
737+}
738+
739+static void
740+cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record,
741+ u_char ext_attr_length, u_char flags,
742+ u_char name_len, const char * name)
743+{
744+ time_t tstamp = stampst.st_ino ? stampst.st_mtime : time(NULL);
745+
746+ record->ext_attr_length[0] = ext_attr_length;
747+ cd9660_time_915(record->date, tstamp);
748+ record->flags[0] = ISO_FLAG_CLEAR | flags;
749+ record->file_unit_size[0] = 0;
750+ record->interleave[0] = 0;
751+ cd9660_bothendian_word(1, record->volume_sequence_number);
752+ record->name_len[0] = name_len;
753+ memset(record->name, '\0', sizeof (record->name));
754+ memcpy(record->name, name, name_len);
755+ record->length[0] = 33 + name_len;
756+
757+ /* Todo : better rounding */
758+ record->length[0] += (record->length[0] & 1) ? 1 : 0;
759+}
760+
761+static void
762+cd9660_setup_root_node(iso9660_disk *diskStructure)
763+{
764+ cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord,
765+ 0, ISO_FLAG_DIRECTORY, 1, "\0");
766+
767+}
768+
769+/*********** SUPPORT FUNCTIONS ***********/
770+static int
771+cd9660_setup_volume_descriptors(iso9660_disk *diskStructure)
772+{
773+ /* Boot volume descriptor should come second */
774+ int sector = 16;
775+ /* For now, a fixed 2 : PVD and terminator */
776+ volume_descriptor *temp, *t;
777+
778+ /* Set up the PVD */
779+ temp = emalloc(sizeof(*temp));
780+ temp->volumeDescriptorData =
781+ (unsigned char *)&diskStructure->primaryDescriptor;
782+ temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD;
783+ temp->volumeDescriptorData[6] = 1;
784+ temp->sector = sector;
785+ memcpy(temp->volumeDescriptorData + 1,
786+ ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
787+ diskStructure->firstVolumeDescriptor = temp;
788+
789+ sector++;
790+ /* Set up boot support if enabled. BVD must reside in sector 17 */
791+ if (diskStructure->is_bootable) {
792+ t = emalloc(sizeof(*t));
793+ t->volumeDescriptorData = ecalloc(1, 2048);
794+ temp->next = t;
795+ temp = t;
796+ t->sector = 17;
797+ if (diskStructure->verbose_level > 0)
798+ printf("Setting up boot volume descriptor\n");
799+ cd9660_setup_boot_volume_descriptor(diskStructure, t);
800+ sector++;
801+ }
802+
803+ /* Set up the terminator */
804+ t = emalloc(sizeof(*t));
805+ t->volumeDescriptorData = ecalloc(1, 2048);
806+ temp->next = t;
807+ t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR;
808+ t->next = 0;
809+ t->volumeDescriptorData[6] = 1;
810+ t->sector = sector;
811+ memcpy(t->volumeDescriptorData + 1,
812+ ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
813+
814+ sector++;
815+ return sector;
816+}
817+
818+#if 0
819+/*
820+ * Populate EAR at some point. Not required, but is used by NetBSD's
821+ * cd9660 support
822+ */
823+static int
824+cd9660_fill_extended_attribute_record(cd9660node *node)
825+{
826+ node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes));
827+ return 1;
828+}
829+#endif
830+
831+static int
832+cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode)
833+{
834+ u_char flag;
835+ char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
836+
837+ /* Now populate the isoDirRecord structure */
838+ memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
839+
840+ (void)cd9660_convert_filename(diskStructure, newnode->node->name,
841+ temp, !(S_ISDIR(newnode->node->type)));
842+
843+ flag = ISO_FLAG_CLEAR;
844+ if (S_ISDIR(newnode->node->type))
845+ flag |= ISO_FLAG_DIRECTORY;
846+
847+ cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0,
848+ flag, strlen(temp), temp);
849+
850+ cd9660_bothendian_dword(newnode->fileDataLength,
851+ newnode->isoDirRecord->size);
852+ /* If the file is a link, we want to set the size to 0 */
853+ if (S_ISLNK(newnode->node->type))
854+ newnode->fileDataLength = 0;
855+
856+ return 1;
857+}
858+
859+/*
860+ * Translate fsnode to cd9660node
861+ * Translate filenames and other metadata, including dates, sizes,
862+ * permissions, etc
863+ * @param struct fsnode * The node generated by makefs
864+ * @param struct cd9660node * The intermediate node to be written to
865+ * @returns int 0 on failure, 1 on success
866+ */
867+static int
868+cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node,
869+ cd9660node *newnode)
870+{
871+ if (node == NULL) {
872+ if (diskStructure->verbose_level > 0)
873+ printf("%s: NULL node passed, returning\n", __func__);
874+ return 0;
875+ }
876+ newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord));
877+ /* Set the node pointer */
878+ newnode->node = node;
879+
880+ /* Set the size */
881+ if (!(S_ISDIR(node->type)))
882+ newnode->fileDataLength = node->inode->st.st_size;
883+
884+ if (cd9660_translate_node_common(diskStructure, newnode) == 0)
885+ return 0;
886+
887+ /* Finally, overwrite some of the values that are set by default */
888+ cd9660_time_915(newnode->isoDirRecord->date,
889+ stampst.st_ino ? stampst.st_mtime : node->inode->st.st_mtime);
890+
891+ return 1;
892+}
893+
894+/*
895+ * Compares two ISO filenames
896+ * @param const char * The first file name
897+ * @param const char * The second file name
898+ * @returns : -1 if first is less than second, 0 if they are the same, 1 if
899+ * the second is greater than the first
900+ */
901+static int
902+cd9660_compare_filename(const char *first, const char *second)
903+{
904+ /*
905+ * This can be made more optimal once it has been tested
906+ * (the extra character, for example, is for testing)
907+ */
908+
909+ int p1 = 0;
910+ int p2 = 0;
911+ char c1, c2;
912+ /* First, on the filename */
913+
914+ while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1
915+ && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) {
916+ c1 = first[p1];
917+ c2 = second[p2];
918+ if (c1 == '.' && c2 =='.')
919+ break;
920+ else if (c1 == '.') {
921+ p2++;
922+ c1 = ' ';
923+ } else if (c2 == '.') {
924+ p1++;
925+ c2 = ' ';
926+ } else {
927+ p1++;
928+ p2++;
929+ }
930+
931+ if (c1 < c2)
932+ return -1;
933+ else if (c1 > c2) {
934+ return 1;
935+ }
936+ }
937+
938+ if (first[p1] == '.' && second[p2] == '.') {
939+ p1++;
940+ p2++;
941+ while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1
942+ && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) {
943+ c1 = first[p1];
944+ c2 = second[p2];
945+ if (c1 == ';' && c2 == ';')
946+ break;
947+ else if (c1 == ';') {
948+ p2++;
949+ c1 = ' ';
950+ } else if (c2 == ';') {
951+ p1++;
952+ c2 = ' ';
953+ } else {
954+ p1++;
955+ p2++;
956+ }
957+
958+ if (c1 < c2)
959+ return -1;
960+ else if (c1 > c2)
961+ return 1;
962+ }
963+ }
964+ return 0;
965+}
966+
967+/*
968+ * Insert a node into list with ISO sorting rules
969+ * @param cd9660node * The head node of the list
970+ * @param cd9660node * The node to be inserted
971+ */
972+static void
973+cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new)
974+{
975+ int compare;
976+ cd9660node *cn;
977+ struct cd9660_children_head *head = &parent->cn_children;
978+
979+ /* TODO: Optimize? */
980+ cn_new->parent = parent;
981+
982+ /*
983+ * first will either be 0, the . or the ..
984+ * if . or .., this means no other entry may be written before first
985+ * if 0, the new node may be inserted at the head
986+ */
987+
988+ TAILQ_FOREACH(cn, head, cn_next_child) {
989+ /*
990+ * Dont insert a node twice -
991+ * that would cause an infinite loop
992+ */
993+ if (cn_new == cn)
994+ return;
995+
996+ compare = cd9660_compare_filename(cn_new->isoDirRecord->name,
997+ cn->isoDirRecord->name);
998+
999+ if (compare == 0)
1000+ compare = cd9660_compare_filename(cn_new->node->name,
1001+ cn->node->name);
1002+
1003+ if (compare < 0)
1004+ break;
1005+ }
1006+ if (cn == NULL)
1007+ TAILQ_INSERT_TAIL(head, cn_new, cn_next_child);
1008+ else
1009+ TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child);
1010+}
1011+
1012+/*
1013+ * Called After cd9660_sorted_child_insert
1014+ * handles file collisions by suffixing each filename with ~n
1015+ * where n represents the files respective place in the ordering
1016+ */
1017+static int
1018+cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding,
1019+ int past)
1020+{
1021+ cd9660node *iter, *next, *prev;
1022+ int skip;
1023+ int delete_chars = 0;
1024+ int temp_past = past;
1025+ int temp_skip;
1026+ int flag = 0;
1027+ cd9660node *end_of_range;
1028+
1029+ for (iter = TAILQ_FIRST(&colliding->cn_children);
1030+ iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) {
1031+ if (strcmp(iter->isoDirRecord->name,
1032+ next->isoDirRecord->name) != 0) {
1033+ iter = TAILQ_NEXT(iter, cn_next_child);
1034+ continue;
1035+ }
1036+ flag = 1;
1037+ temp_skip = skip = cd9660_count_collisions(iter);
1038+ end_of_range = iter;
1039+ while (temp_skip > 0) {
1040+ temp_skip--;
1041+ end_of_range = TAILQ_NEXT(end_of_range, cn_next_child);
1042+ }
1043+ temp_past = past;
1044+ while (temp_past > 0) {
1045+ if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL)
1046+ end_of_range = next;
1047+ else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL)
1048+ iter = prev;
1049+ else
1050+ delete_chars++;
1051+ temp_past--;
1052+ }
1053+ skip += past;
1054+ iter = cd9660_rename_filename(diskStructure, iter, skip,
1055+ delete_chars);
1056+ }
1057+ return flag;
1058+}
1059+
1060+
1061+static cd9660node *
1062+cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num,
1063+ int delete_chars)
1064+{
1065+ int i = 0;
1066+ int numbts, dot, semi, digit, digits, temp, powers, multiplier, count;
1067+ char *naming;
1068+ int maxlength;
1069+ char *tmp;
1070+
1071+ if (diskStructure->verbose_level > 0)
1072+ printf("Rename_filename called\n");
1073+
1074+ /* TODO : A LOT of chanes regarding 8.3 filenames */
1075+ if (diskStructure->isoLevel == 1)
1076+ maxlength = 8;
1077+ else if (diskStructure->isoLevel == 2)
1078+ maxlength = 31;
1079+ else
1080+ maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION;
1081+
1082+ tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING);
1083+
1084+ while (i < num && iter) {
1085+ powers = 1;
1086+ count = 0;
1087+ digits = 1;
1088+ multiplier = 1;
1089+ while (((int)(i / powers) ) >= 10) {
1090+ digits++;
1091+ powers = powers * 10;
1092+ }
1093+
1094+ naming = iter->o_name;
1095+
1096+ /*
1097+ while ((*naming != '.') && (*naming != ';')) {
1098+ naming++;
1099+ count++;
1100+ }
1101+ */
1102+
1103+ dot = -1;
1104+ semi = -1;
1105+ while (count < maxlength) {
1106+ if (*naming == '.')
1107+ dot = count;
1108+ else if (*naming == ';') {
1109+ semi = count;
1110+ break;
1111+ }
1112+ naming++;
1113+ count++;
1114+ }
1115+
1116+ if ((count + digits) < maxlength)
1117+ numbts = count;
1118+ else
1119+ numbts = maxlength - (digits);
1120+ numbts -= delete_chars;
1121+
1122+ /* 8.3 rules - keep the extension, add before the dot */
1123+
1124+ /*
1125+ * This code makes a bunch of assumptions.
1126+ * See if you can spot them all :)
1127+ */
1128+
1129+#if 0
1130+ if (diskStructure->isoLevel == 1) {
1131+ numbts = 8 - digits - delete_chars;
1132+ if (dot < 0) {
1133+
1134+ } else {
1135+ if (dot < 8) {
1136+ memmove(&tmp[numbts],&tmp[dot],4);
1137+ }
1138+ }
1139+ }
1140+#else
1141+ __USE(dot);
1142+ __USE(semi);
1143+ __USE(multiplier);
1144+#endif
1145+
1146+ /* (copying just the filename before the '.' */
1147+ memcpy(tmp, (iter->o_name), numbts);
1148+
1149+ /* adding the appropriate number following the name */
1150+ temp = i;
1151+ while (digits > 0) {
1152+ digit = (int)(temp / powers);
1153+ temp = temp - digit * powers;
1154+ sprintf(&tmp[numbts] , "%d", digit);
1155+ digits--;
1156+ numbts++;
1157+ powers = powers / 10;
1158+ }
1159+
1160+ while ((*naming != ';') && (numbts < maxlength)) {
1161+ tmp[numbts] = (*naming);
1162+ naming++;
1163+ numbts++;
1164+ }
1165+
1166+ tmp[numbts] = ';';
1167+ tmp[numbts+1] = '1';
1168+ tmp[numbts+2] = '\0';
1169+
1170+ /*
1171+ * now tmp has exactly the identifier
1172+ * we want so we'll copy it back to record
1173+ */
1174+ memcpy((iter->isoDirRecord->name), tmp, numbts + 3);
1175+
1176+ iter = TAILQ_NEXT(iter, cn_next_child);
1177+ i++;
1178+ }
1179+
1180+ free(tmp);
1181+ return iter;
1182+}
1183+
1184+/* Todo: Figure out why these functions are nec. */
1185+static void
1186+cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node)
1187+{
1188+ cd9660node *cn;
1189+
1190+ if (TAILQ_EMPTY(&node->cn_children))
1191+ return;
1192+
1193+ if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) {
1194+ debug_print_tree(diskStructure, diskStructure->rootNode, 0);
1195+ exit(EXIT_FAILURE);
1196+ }
1197+
1198+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
1199+ cd9660_copy_filenames(diskStructure, cn);
1200+ memcpy(cn->o_name, cn->isoDirRecord->name,
1201+ ISO_FILENAME_MAXLENGTH_WITH_PADDING);
1202+ }
1203+}
1204+
1205+static void
1206+cd9660_sorting_nodes(cd9660node *node)
1207+{
1208+ cd9660node *cn;
1209+
1210+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
1211+ cd9660_sorting_nodes(cn);
1212+ cd9660_sort_nodes(node);
1213+}
1214+
1215+/* XXX Bubble sort. */
1216+static void
1217+cd9660_sort_nodes(cd9660node *node)
1218+{
1219+ cd9660node *cn, *next;
1220+
1221+ do {
1222+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
1223+ if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL)
1224+ return;
1225+ else if (strcmp(next->isoDirRecord->name,
1226+ cn->isoDirRecord->name) >= 0)
1227+ continue;
1228+ TAILQ_REMOVE(&node->cn_children, next, cn_next_child);
1229+ TAILQ_INSERT_BEFORE(cn, next, cn_next_child);
1230+ break;
1231+ }
1232+ } while (cn != NULL);
1233+}
1234+
1235+static int
1236+cd9660_count_collisions(cd9660node *copy)
1237+{
1238+ int count = 0;
1239+ cd9660node *iter, *next;
1240+
1241+ for (iter = copy;
1242+ (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;
1243+ iter = next) {
1244+ if (cd9660_compare_filename(iter->isoDirRecord->name,
1245+ next->isoDirRecord->name) == 0)
1246+ count++;
1247+ else
1248+ return count;
1249+ }
1250+#if 0
1251+ if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) {
1252+ printf("%s: count is %i \n", __func__, count);
1253+ compare = cd9660_compare_filename(iter->isoDirRecord->name,
1254+ next->isoDirRecord->name);
1255+ if (compare == 0) {
1256+ count++;
1257+ return cd9660_recurse_on_collision(next, count);
1258+ } else
1259+ return count;
1260+ }
1261+#endif
1262+ return count;
1263+}
1264+
1265+static cd9660node *
1266+cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir)
1267+{
1268+ char newname[9];
1269+ cd9660node *tfile;
1270+
1271+ /*
1272+ * This function needs to:
1273+ * 1) Create an empty virtual file in place of the old directory
1274+ * 2) Point the virtual file to the new directory
1275+ * 3) Point the relocated directory to its old parent
1276+ * 4) Move the directory specified by dir into rr_moved_dir,
1277+ * and rename it to "diskStructure->rock_ridge_move_count" (as a string)
1278+ */
1279+
1280+ /* First see if the moved directory even exists */
1281+ if (diskStructure->rr_moved_dir == NULL) {
1282+ diskStructure->rr_moved_dir = cd9660_create_directory(
1283+ diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME,
1284+ diskStructure->rootNode, dir);
1285+ if (diskStructure->rr_moved_dir == NULL)
1286+ return 0;
1287+ cd9660_time_915(diskStructure->rr_moved_dir->isoDirRecord->date,
1288+ stampst.st_ino ? stampst.st_mtime : start_time.tv_sec);
1289+ }
1290+
1291+ /* Create a file with the same ORIGINAL name */
1292+ tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent,
1293+ dir);
1294+ if (tfile == NULL)
1295+ return NULL;
1296+
1297+ diskStructure->rock_ridge_move_count++;
1298+ snprintf(newname, sizeof(newname), "%08u",
1299+ diskStructure->rock_ridge_move_count);
1300+
1301+ /* Point to old parent */
1302+ dir->rr_real_parent = dir->parent;
1303+
1304+ /* Place the placeholder file */
1305+ if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) {
1306+ TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile,
1307+ cn_next_child);
1308+ } else {
1309+ cd9660_sorted_child_insert(dir->rr_real_parent, tfile);
1310+ }
1311+
1312+ /* Point to new parent */
1313+ dir->parent = diskStructure->rr_moved_dir;
1314+
1315+ /* Point the file to the moved directory */
1316+ tfile->rr_relocated = dir;
1317+
1318+ /* Actually move the directory */
1319+ cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir);
1320+
1321+ /* TODO: Inherit permissions / ownership (basically the entire inode) */
1322+
1323+ /* Set the new name */
1324+ memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
1325+ strncpy(dir->isoDirRecord->name, newname, 8);
1326+ dir->isoDirRecord->length[0] = 34 + 8;
1327+ dir->isoDirRecord->name_len[0] = 8;
1328+
1329+ return dir;
1330+}
1331+
1332+static int
1333+cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root)
1334+{
1335+ struct cd9660_children_head *head = &root->cn_children;
1336+ cd9660node *cn;
1337+
1338+ TAILQ_FOREACH(cn, head, cn_next_child) {
1339+ if ((cn->type & CD9660_TYPE_DIR) == 0)
1340+ continue;
1341+ /* Recursion first */
1342+ cd9660_add_dot_records(diskStructure, cn);
1343+ }
1344+ cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root);
1345+ cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT,
1346+ root);
1347+ return 1;
1348+}
1349+
1350+/*
1351+ * Convert node to cd9660 structure
1352+ * This function is designed to be called recursively on the root node of
1353+ * the filesystem
1354+ * Lots of recursion going on here, want to make sure it is efficient
1355+ * @param struct fsnode * The root node to be converted
1356+ * @param struct cd9660* The parent node (should not be NULL)
1357+ * @param int Current directory depth
1358+ * @param int* Running count of the number of directories that are being created
1359+ */
1360+static void
1361+cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root,
1362+ cd9660node *parent_node, int level, int *numDirectories, int *error)
1363+{
1364+ fsnode *iterator = root;
1365+ cd9660node *this_node;
1366+ int working_level;
1367+ int add;
1368+ int flag = 0;
1369+ int counter = 0;
1370+
1371+ /*
1372+ * Newer, more efficient method, reduces recursion depth
1373+ */
1374+ if (root == NULL) {
1375+ warnx("%s: root is null", __func__);
1376+ return;
1377+ }
1378+
1379+ /* Test for an empty directory - makefs still gives us the . record */
1380+ if ((S_ISDIR(root->type)) && (root->name[0] == '.')
1381+ && (root->name[1] == '\0')) {
1382+ root = root->next;
1383+ if (root == NULL)
1384+ return;
1385+ }
1386+ if ((this_node = cd9660_allocate_cd9660node()) == NULL) {
1387+ CD9660_MEM_ALLOC_ERROR(__func__);
1388+ }
1389+
1390+ /*
1391+ * To reduce the number of recursive calls, we will iterate over
1392+ * the next pointers to the right.
1393+ */
1394+ while (iterator != NULL) {
1395+ add = 1;
1396+ /*
1397+ * Increment the directory count if this is a directory
1398+ * Ignore "." entries. We will generate them later
1399+ */
1400+ if (!S_ISDIR(iterator->type) ||
1401+ strcmp(iterator->name, ".") != 0) {
1402+
1403+ /* Translate the node, including its filename */
1404+ this_node->parent = parent_node;
1405+ cd9660_translate_node(diskStructure, iterator,
1406+ this_node);
1407+ this_node->level = level;
1408+
1409+ if (S_ISDIR(iterator->type)) {
1410+ (*numDirectories)++;
1411+ this_node->type = CD9660_TYPE_DIR;
1412+ working_level = level + 1;
1413+
1414+ /*
1415+ * If at level 8, directory would be at 8
1416+ * and have children at 9 which is not
1417+ * allowed as per ISO spec
1418+ */
1419+ if (level == 8) {
1420+ if ((!diskStructure->allow_deep_trees) &&
1421+ (!diskStructure->rock_ridge_enabled)) {
1422+ warnx("error: found entry "
1423+ "with depth greater "
1424+ "than 8.");
1425+ (*error) = 1;
1426+ return;
1427+ } else if (diskStructure->
1428+ rock_ridge_enabled) {
1429+ working_level = 3;
1430+ /*
1431+ * Moved directory is actually
1432+ * at level 2.
1433+ */
1434+ this_node->level =
1435+ working_level - 1;
1436+ if (cd9660_rrip_move_directory(
1437+ diskStructure,
1438+ this_node) == 0) {
1439+ warnx("Failure in "
1440+ "cd9660_rrip_"
1441+ "move_directory"
1442+ );
1443+ (*error) = 1;
1444+ return;
1445+ }
1446+ add = 0;
1447+ }
1448+ }
1449+
1450+ /* Do the recursive call on the children */
1451+ if (iterator->child != 0) {
1452+ cd9660_convert_structure(diskStructure,
1453+ iterator->child, this_node,
1454+ working_level,
1455+ numDirectories, error);
1456+
1457+ if ((*error) == 1) {
1458+ warnx("%s: Error on recursive "
1459+ "call", __func__);
1460+ return;
1461+ }
1462+ }
1463+
1464+ } else {
1465+ /* Only directories should have children */
1466+ assert(iterator->child == NULL);
1467+
1468+ this_node->type = CD9660_TYPE_FILE;
1469+ }
1470+
1471+ /*
1472+ * Finally, do a sorted insert
1473+ */
1474+ if (add) {
1475+ cd9660_sorted_child_insert(
1476+ parent_node, this_node);
1477+ }
1478+
1479+ /*Allocate new temp_node */
1480+ if (iterator->next != 0) {
1481+ this_node = cd9660_allocate_cd9660node();
1482+ if (this_node == NULL)
1483+ CD9660_MEM_ALLOC_ERROR(__func__);
1484+ }
1485+ }
1486+ iterator = iterator->next;
1487+ }
1488+
1489+ /* cd9660_handle_collisions(first_node); */
1490+
1491+ /* TODO: need cleanup */
1492+ cd9660_copy_filenames(diskStructure, parent_node);
1493+
1494+ do {
1495+ flag = cd9660_handle_collisions(diskStructure, parent_node,
1496+ counter);
1497+ counter++;
1498+ cd9660_sorting_nodes(parent_node);
1499+ } while ((flag == 1) && (counter < 100));
1500+}
1501+
1502+/*
1503+ * Clean up the cd9660node tree
1504+ * This is designed to be called recursively on the root node
1505+ * @param struct cd9660node *root The node to free
1506+ * @returns void
1507+ */
1508+static void
1509+cd9660_free_structure(cd9660node *root)
1510+{
1511+ cd9660node *cn;
1512+
1513+ while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) {
1514+ TAILQ_REMOVE(&root->cn_children, cn, cn_next_child);
1515+ cd9660_free_structure(cn);
1516+ }
1517+ free(root);
1518+}
1519+
1520+/*
1521+ * Be a little more memory conservative:
1522+ * instead of having the TAILQ_ENTRY as part of the cd9660node,
1523+ * just create a temporary structure
1524+ */
1525+struct ptq_entry
1526+{
1527+ TAILQ_ENTRY(ptq_entry) ptq;
1528+ cd9660node *node;
1529+} *n;
1530+
1531+#define PTQUEUE_NEW(n,s,r,t){\
1532+ n = emalloc(sizeof(struct s)); \
1533+ if (n == NULL) \
1534+ return r; \
1535+ n->node = t;\
1536+}
1537+
1538+/*
1539+ * Generate the path tables
1540+ * The specific implementation of this function is left as an exercise to the
1541+ * programmer. It could be done recursively. Make sure you read how the path
1542+ * table has to be laid out, it has levels.
1543+ * @param struct iso9660_disk *disk The disk image
1544+ * @returns int The number of built path tables (between 1 and 4), 0 on failure
1545+ */
1546+static int
1547+cd9660_generate_path_table(iso9660_disk *diskStructure)
1548+{
1549+ cd9660node *cn, *dirNode = diskStructure->rootNode;
1550+ cd9660node *last = dirNode;
1551+ int pathTableSize = 0; /* computed as we go */
1552+ int counter = 1; /* root gets a count of 0 */
1553+
1554+ TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head;
1555+ TAILQ_INIT(&pt_head);
1556+
1557+ PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode);
1558+
1559+ /* Push the root node */
1560+ TAILQ_INSERT_HEAD(&pt_head, n, ptq);
1561+
1562+ /* Breadth-first traversal of file structure */
1563+ while (pt_head.tqh_first != 0) {
1564+ n = pt_head.tqh_first;
1565+ dirNode = n->node;
1566+ TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq);
1567+ free(n);
1568+
1569+ /* Update the size */
1570+ pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE
1571+ + dirNode->isoDirRecord->name_len[0]+
1572+ (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1);
1573+ /* includes the padding bit */
1574+
1575+ dirNode->ptnumber=counter;
1576+ if (dirNode != last) {
1577+ last->ptnext = dirNode;
1578+ dirNode->ptprev = last;
1579+ }
1580+ last = dirNode;
1581+
1582+ /* Push children onto queue */
1583+ TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) {
1584+ /*
1585+ * Dont add the DOT and DOTDOT types to the path
1586+ * table.
1587+ */
1588+ if ((cn->type != CD9660_TYPE_DOT)
1589+ && (cn->type != CD9660_TYPE_DOTDOT)) {
1590+
1591+ if (S_ISDIR(cn->node->type)) {
1592+ PTQUEUE_NEW(n, ptq_entry, -1, cn);
1593+ TAILQ_INSERT_TAIL(&pt_head, n, ptq);
1594+ }
1595+ }
1596+ }
1597+ counter++;
1598+ }
1599+ return pathTableSize;
1600+}
1601+
1602+void
1603+cd9660_compute_full_filename(cd9660node *node, char *buf)
1604+{
1605+ int len;
1606+
1607+ len = CD9660MAXPATH + 1;
1608+ len = snprintf(buf, len, "%s/%s/%s", node->node->root,
1609+ node->node->path, node->node->name);
1610+ if (len > CD9660MAXPATH)
1611+ errx(EXIT_FAILURE, "Pathname too long.");
1612+}
1613+
1614+/* NEW filename conversion method */
1615+typedef int(*cd9660_filename_conversion_functor)(iso9660_disk *, const char *,
1616+ char *, int);
1617+
1618+
1619+/*
1620+ * TODO: These two functions are almost identical.
1621+ * Some code cleanup is possible here
1622+ *
1623+ * XXX bounds checking!
1624+ */
1625+static int
1626+cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1627+ char *newname, int is_file)
1628+{
1629+ /*
1630+ * ISO 9660 : 10.1
1631+ * File Name shall not contain more than 8 d or d1 characters
1632+ * File Name Extension shall not contain more than 3 d or d1 characters
1633+ * Directory Identifier shall not contain more than 8 d or d1 characters
1634+ */
1635+ int namelen = 0;
1636+ int extlen = 0;
1637+ int found_ext = 0;
1638+
1639+ while (*oldname != '\0' && extlen < 3) {
1640+ /* Handle period first, as it is special */
1641+ if (*oldname == '.') {
1642+ if (found_ext) {
1643+ *newname++ = '_';
1644+ extlen ++;
1645+ }
1646+ else {
1647+ *newname++ = '.';
1648+ found_ext = 1;
1649+ }
1650+ } else {
1651+ /* cut RISC OS file type off ISO name */
1652+ if (diskStructure->archimedes_enabled &&
1653+ *oldname == ',' && strlen(oldname) == 4)
1654+ break;
1655+
1656+ /* Enforce 12.3 / 8 */
1657+ if (namelen == 8 && !found_ext)
1658+ break;
1659+
1660+ if (islower((unsigned char)*oldname))
1661+ *newname++ = toupper((unsigned char)*oldname);
1662+ else if (isupper((unsigned char)*oldname)
1663+ || isdigit((unsigned char)*oldname))
1664+ *newname++ = *oldname;
1665+ else
1666+ *newname++ = '_';
1667+
1668+ if (found_ext)
1669+ extlen++;
1670+ else
1671+ namelen++;
1672+ }
1673+ oldname++;
1674+ }
1675+ if (is_file) {
1676+ if (!found_ext && !diskStructure->omit_trailing_period)
1677+ *newname++ = '.';
1678+ /* Add version */
1679+ sprintf(newname, ";%i", 1);
1680+ }
1681+ return namelen + extlen + found_ext;
1682+}
1683+
1684+/* XXX bounds checking! */
1685+static int
1686+cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1687+ char *newname, int is_file)
1688+{
1689+ /*
1690+ * ISO 9660 : 7.5.1
1691+ * File name : 0+ d or d1 characters
1692+ * separator 1 (.)
1693+ * File name extension : 0+ d or d1 characters
1694+ * separator 2 (;)
1695+ * File version number (5 characters, 1-32767)
1696+ * 1 <= Sum of File name and File name extension <= 30
1697+ */
1698+ int namelen = 0;
1699+ int extlen = 0;
1700+ int found_ext = 0;
1701+
1702+ while (*oldname != '\0' && namelen + extlen < 30) {
1703+ /* Handle period first, as it is special */
1704+ if (*oldname == '.') {
1705+ if (found_ext) {
1706+ if (diskStructure->allow_multidot) {
1707+ *newname++ = '.';
1708+ } else {
1709+ *newname++ = '_';
1710+ }
1711+ extlen ++;
1712+ }
1713+ else {
1714+ *newname++ = '.';
1715+ found_ext = 1;
1716+ }
1717+ } else {
1718+ /* cut RISC OS file type off ISO name */
1719+ if (diskStructure->archimedes_enabled &&
1720+ *oldname == ',' && strlen(oldname) == 4)
1721+ break;
1722+
1723+ if (islower((unsigned char)*oldname))
1724+ *newname++ = toupper((unsigned char)*oldname);
1725+ else if (isupper((unsigned char)*oldname) ||
1726+ isdigit((unsigned char)*oldname))
1727+ *newname++ = *oldname;
1728+ else if (diskStructure->allow_multidot &&
1729+ *oldname == '.') {
1730+ *newname++ = '.';
1731+ } else {
1732+ *newname++ = '_';
1733+ }
1734+
1735+ if (found_ext)
1736+ extlen++;
1737+ else
1738+ namelen++;
1739+ }
1740+ oldname ++;
1741+ }
1742+ if (is_file) {
1743+ if (!found_ext && !diskStructure->omit_trailing_period)
1744+ *newname++ = '.';
1745+ /* Add version */
1746+ sprintf(newname, ";%i", 1);
1747+ }
1748+ return namelen + extlen + found_ext;
1749+}
1750+
1751+#if 0
1752+static int
1753+cd9660_joliet_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1754+ char *newname, int is_file)
1755+{
1756+ /* TODO: implement later, move to cd9660_joliet.c ?? */
1757+}
1758+#endif
1759+
1760+
1761+/*
1762+ * Convert a file name to ISO compliant file name
1763+ * @param char * oldname The original filename
1764+ * @param char ** newname The new file name, in the appropriate character
1765+ * set and of appropriate length
1766+ * @param int 1 if file, 0 if directory
1767+ * @returns int The length of the new string
1768+ */
1769+static int
1770+cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1771+ char *newname, int is_file)
1772+{
1773+ /* NEW */
1774+ cd9660_filename_conversion_functor conversion_function = 0;
1775+ if (diskStructure->isoLevel == 1)
1776+ conversion_function = &cd9660_level1_convert_filename;
1777+ else if (diskStructure->isoLevel == 2)
1778+ conversion_function = &cd9660_level2_convert_filename;
1779+ return (*conversion_function)(diskStructure, oldname, newname, is_file);
1780+}
1781+
1782+int
1783+cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node)
1784+{
1785+ int size = node->isoDirRecord->length[0];
1786+
1787+ if (diskStructure->rock_ridge_enabled)
1788+ size += node->susp_entry_size;
1789+ size += node->su_tail_size;
1790+ size += size & 1; /* Ensure length of record is even. */
1791+ assert(size <= 254);
1792+ return size;
1793+}
1794+
1795+static void
1796+cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node)
1797+{
1798+ node->dot_record->fileDataSector = node->fileDataSector;
1799+ memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34);
1800+ node->dot_record->isoDirRecord->name_len[0] = 1;
1801+ node->dot_record->isoDirRecord->name[0] = 0;
1802+ node->dot_record->isoDirRecord->name[1] = 0;
1803+ node->dot_record->isoDirRecord->length[0] = 34;
1804+ node->dot_record->fileRecordSize =
1805+ cd9660_compute_record_size(diskStructure, node->dot_record);
1806+
1807+ if (node == diskStructure->rootNode) {
1808+ node->dot_dot_record->fileDataSector = node->fileDataSector;
1809+ memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord,
1810+ 34);
1811+ } else {
1812+ node->dot_dot_record->fileDataSector =
1813+ node->parent->fileDataSector;
1814+ memcpy(node->dot_dot_record->isoDirRecord,
1815+ node->parent->isoDirRecord,34);
1816+ }
1817+ node->dot_dot_record->isoDirRecord->name_len[0] = 1;
1818+ node->dot_dot_record->isoDirRecord->name[0] = 1;
1819+ node->dot_dot_record->isoDirRecord->name[1] = 0;
1820+ node->dot_dot_record->isoDirRecord->length[0] = 34;
1821+ node->dot_dot_record->fileRecordSize =
1822+ cd9660_compute_record_size(diskStructure, node->dot_dot_record);
1823+}
1824+
1825+/*
1826+ * @param struct cd9660node *node The node
1827+ * @param int The offset (in bytes) - SHOULD align to the beginning of a sector
1828+ * @returns int The total size of files and directory entries (should be
1829+ * a multiple of sector size)
1830+*/
1831+static int64_t
1832+cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node,
1833+ int64_t startOffset)
1834+{
1835+ /*
1836+ * This function needs to compute the size of directory records and
1837+ * runs, file lengths, and set the appropriate variables both in
1838+ * cd9660node and isoDirEntry
1839+ */
1840+ int64_t used_bytes = 0;
1841+ int64_t current_sector_usage = 0;
1842+ cd9660node *child;
1843+ fsinode *inode;
1844+ int64_t r;
1845+
1846+ assert(node != NULL);
1847+
1848+
1849+ /*
1850+ * NOTE : There needs to be some special case detection for
1851+ * the "real root" node, since for it, node->node is undefined
1852+ */
1853+
1854+ node->fileDataSector = -1;
1855+
1856+ if (node->type & CD9660_TYPE_DIR) {
1857+ node->fileRecordSize = cd9660_compute_record_size(
1858+ diskStructure, node);
1859+ /*Set what sector this directory starts in*/
1860+ node->fileDataSector =
1861+ CD9660_BLOCKS(diskStructure->sectorSize,startOffset);
1862+
1863+ cd9660_bothendian_dword(node->fileDataSector,
1864+ node->isoDirRecord->extent);
1865+
1866+ /*
1867+ * First loop over children, need to know the size of
1868+ * their directory records
1869+ */
1870+ node->fileSectorsUsed = 1;
1871+ TAILQ_FOREACH(child, &node->cn_children, cn_next_child) {
1872+ node->fileDataLength +=
1873+ cd9660_compute_record_size(diskStructure, child);
1874+ if ((cd9660_compute_record_size(diskStructure, child) +
1875+ current_sector_usage) >=
1876+ diskStructure->sectorSize) {
1877+ current_sector_usage = 0;
1878+ node->fileSectorsUsed++;
1879+ }
1880+
1881+ current_sector_usage +=
1882+ cd9660_compute_record_size(diskStructure, child);
1883+ }
1884+
1885+ cd9660_bothendian_dword(node->fileSectorsUsed *
1886+ diskStructure->sectorSize,node->isoDirRecord->size);
1887+
1888+ /*
1889+ * This should point to the sector after the directory
1890+ * record (or, the first byte in that sector)
1891+ */
1892+ used_bytes += node->fileSectorsUsed * diskStructure->sectorSize;
1893+
1894+ for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
1895+ child != NULL; child = TAILQ_NEXT(child, cn_next_child)) {
1896+ /* Directories need recursive call */
1897+ if (S_ISDIR(child->node->type)) {
1898+ r = cd9660_compute_offsets(diskStructure, child,
1899+ used_bytes + startOffset);
1900+
1901+ if (r != -1)
1902+ used_bytes += r;
1903+ else
1904+ return -1;
1905+ }
1906+ }
1907+
1908+ /* Explicitly set the . and .. records */
1909+ cd9660_populate_dot_records(diskStructure, node);
1910+
1911+ /* Finally, do another iteration to write the file data*/
1912+ for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
1913+ child != NULL;
1914+ child = TAILQ_NEXT(child, cn_next_child)) {
1915+ /* Files need extent set */
1916+ if (S_ISDIR(child->node->type))
1917+ continue;
1918+ child->fileRecordSize =
1919+ cd9660_compute_record_size(diskStructure, child);
1920+
1921+ child->fileSectorsUsed =
1922+ CD9660_BLOCKS(diskStructure->sectorSize,
1923+ child->fileDataLength);
1924+
1925+ inode = child->node->inode;
1926+ if ((inode->flags & FI_ALLOCATED) == 0) {
1927+ inode->ino =
1928+ CD9660_BLOCKS(diskStructure->sectorSize,
1929+ used_bytes + startOffset);
1930+ inode->flags |= FI_ALLOCATED;
1931+ used_bytes += child->fileSectorsUsed *
1932+ diskStructure->sectorSize;
1933+ } else {
1934+ INODE_WARNX(("%s: already allocated inode %d "
1935+ "data sectors at %" PRIu32, __func__,
1936+ (int)inode->st.st_ino, inode->ino));
1937+ }
1938+ child->fileDataSector = inode->ino;
1939+ cd9660_bothendian_dword(child->fileDataSector,
1940+ child->isoDirRecord->extent);
1941+ }
1942+ }
1943+
1944+ return used_bytes;
1945+}
1946+
1947+#if 0
1948+/* Might get rid of this func */
1949+static int
1950+cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file)
1951+{
1952+ to->node->inode->st.st_dev = 0;
1953+ to->node->inode->st.st_ino = 0;
1954+ to->node->inode->st.st_size = 0;
1955+ to->node->inode->st.st_blksize = from->node->inode->st.st_blksize;
1956+ to->node->inode->st.st_atime = from->node->inode->st.st_atime;
1957+ to->node->inode->st.st_mtime = from->node->inode->st.st_mtime;
1958+ to->node->inode->st.st_ctime = from->node->inode->st.st_ctime;
1959+ to->node->inode->st.st_uid = from->node->inode->st.st_uid;
1960+ to->node->inode->st.st_gid = from->node->inode->st.st_gid;
1961+ to->node->inode->st.st_mode = from->node->inode->st.st_mode;
1962+ /* Clear out type */
1963+ to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT);
1964+ if (file)
1965+ to->node->inode->st.st_mode |= S_IFREG;
1966+ else
1967+ to->node->inode->st.st_mode |= S_IFDIR;
1968+ return 1;
1969+}
1970+#endif
1971+
1972+static cd9660node *
1973+cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name,
1974+ cd9660node *parent, int file, int insert)
1975+{
1976+ cd9660node *temp;
1977+ fsnode * tfsnode;
1978+
1979+ assert(parent != NULL);
1980+
1981+ temp = cd9660_allocate_cd9660node();
1982+ if (temp == NULL)
1983+ return NULL;
1984+
1985+ tfsnode = emalloc(sizeof(*tfsnode));
1986+ tfsnode->name = estrdup(name);
1987+ temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord));
1988+
1989+ cd9660_convert_filename(diskStructure, tfsnode->name,
1990+ temp->isoDirRecord->name, file);
1991+
1992+ temp->node = tfsnode;
1993+ temp->parent = parent;
1994+
1995+ if (insert) {
1996+ if (temp->parent != NULL) {
1997+ temp->level = temp->parent->level + 1;
1998+ if (!TAILQ_EMPTY(&temp->parent->cn_children))
1999+ cd9660_sorted_child_insert(temp->parent, temp);
2000+ else
2001+ TAILQ_INSERT_HEAD(&temp->parent->cn_children,
2002+ temp, cn_next_child);
2003+ }
2004+ }
2005+
2006+ if (parent->node != NULL) {
2007+ tfsnode->type = parent->node->type;
2008+ }
2009+
2010+ /* Clear out file type bits */
2011+ tfsnode->type &= ~(S_IFMT);
2012+ if (file)
2013+ tfsnode->type |= S_IFREG;
2014+ else
2015+ tfsnode->type |= S_IFDIR;
2016+
2017+ /* Indicate that there is no spec entry (inode) */
2018+ tfsnode->flags &= ~(FSNODE_F_HASSPEC);
2019+#if 0
2020+ cd9660_copy_stat_info(parent, temp, file);
2021+#endif
2022+ return temp;
2023+}
2024+
2025+static cd9660node *
2026+cd9660_create_file(iso9660_disk *diskStructure, const char *name,
2027+ cd9660node *parent, cd9660node *me)
2028+{
2029+ cd9660node *temp;
2030+
2031+ temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1);
2032+ if (temp == NULL)
2033+ return NULL;
2034+
2035+ temp->fileDataLength = 0;
2036+
2037+ temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL;
2038+
2039+ temp->node->inode = ecalloc(1, sizeof(*temp->node->inode));
2040+ *temp->node->inode = *me->node->inode;
2041+
2042+ if (cd9660_translate_node_common(diskStructure, temp) == 0)
2043+ return NULL;
2044+ return temp;
2045+}
2046+
2047+/*
2048+ * Create a new directory which does not exist on disk
2049+ * @param const char * name The name to assign to the directory
2050+ * @param const char * parent Pointer to the parent directory
2051+ * @returns cd9660node * Pointer to the new directory
2052+ */
2053+static cd9660node *
2054+cd9660_create_directory(iso9660_disk *diskStructure, const char *name,
2055+ cd9660node *parent, cd9660node *me)
2056+{
2057+ cd9660node *temp;
2058+
2059+ temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1);
2060+ if (temp == NULL)
2061+ return NULL;
2062+ temp->node->type |= S_IFDIR;
2063+
2064+ temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL;
2065+
2066+ temp->node->inode = ecalloc(1, sizeof(*temp->node->inode));
2067+ *temp->node->inode = *me->node->inode;
2068+
2069+ if (cd9660_translate_node_common(diskStructure, temp) == 0)
2070+ return NULL;
2071+ return temp;
2072+}
2073+
2074+static cd9660node *
2075+cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type,
2076+ cd9660node *parent)
2077+{
2078+ cd9660node *temp, *first;
2079+ char na[2];
2080+
2081+ assert(parent != NULL);
2082+
2083+ if (type == CD9660_TYPE_DOT)
2084+ na[0] = 0;
2085+ else if (type == CD9660_TYPE_DOTDOT)
2086+ na[0] = 1;
2087+ else
2088+ return 0;
2089+
2090+ na[1] = 0;
2091+ if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent,
2092+ 0, 0)) == NULL)
2093+ return NULL;
2094+
2095+ temp->parent = parent;
2096+ temp->type = type;
2097+ temp->isoDirRecord->length[0] = 34;
2098+ /* Dot record is always first */
2099+ if (type == CD9660_TYPE_DOT) {
2100+ parent->dot_record = temp;
2101+ TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child);
2102+ /* DotDot should be second */
2103+ } else if (type == CD9660_TYPE_DOTDOT) {
2104+ parent->dot_dot_record = temp;
2105+ /*
2106+ * If the first child is the dot record, insert
2107+ * this second. Otherwise, insert it at the head.
2108+ */
2109+ if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL ||
2110+ (first->type & CD9660_TYPE_DOT) == 0) {
2111+ TAILQ_INSERT_HEAD(&parent->cn_children, temp,
2112+ cn_next_child);
2113+ } else {
2114+ TAILQ_INSERT_AFTER(&parent->cn_children, first, temp,
2115+ cn_next_child);
2116+ }
2117+ }
2118+
2119+ return temp;
2120+}
2121+
2122+static int
2123+cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage)
2124+{
2125+ struct stat stbuf;
2126+
2127+ assert(bootimage != NULL);
2128+
2129+ if (*bootimage == '\0') {
2130+ warnx("Error: Boot image must be a filename");
2131+ return 0;
2132+ }
2133+
2134+ diskStructure->generic_bootimage = estrdup(bootimage);
2135+
2136+ /* Get information about the file */
2137+ if (lstat(diskStructure->generic_bootimage, &stbuf) == -1)
2138+ err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
2139+ diskStructure->generic_bootimage);
2140+
2141+ if (stbuf.st_size > 32768) {
2142+ warnx("Error: Boot image must be no greater than 32768 bytes");
2143+ return 0;
2144+ }
2145+
2146+ if (diskStructure->verbose_level > 0) {
2147+ printf("Generic boot image image has size %lld\n",
2148+ (long long)stbuf.st_size);
2149+ }
2150+
2151+ diskStructure->has_generic_bootimage = 1;
2152+
2153+ return 1;
2154+}
+357,
-0
1@@ -0,0 +1,357 @@
2+/* $NetBSD: cd9660.h,v 1.21 2015/12/24 15:52:37 christos Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+
36+#ifndef _MAKEFS_CD9660_H
37+#define _MAKEFS_CD9660_H
38+
39+#if HAVE_NBTOOL_CONFIG_H
40+#include "nbtool_config.h"
41+#endif
42+
43+#include <assert.h>
44+#include <errno.h>
45+#include <fcntl.h>
46+#include <stdarg.h>
47+#include <stdio.h>
48+#include <stdlib.h>
49+#include <string.h>
50+#include <unistd.h>
51+#include <time.h>
52+#include <limits.h>
53+#include <sys/queue.h>
54+#include <sys/param.h>
55+#include <sys/endian.h>
56+
57+#include "makefs.h"
58+#include "iso.h"
59+#include "iso_rrip.h"
60+#include "cd9660/cd9660_eltorito.h"
61+
62+#ifdef DEBUG
63+#define INODE_WARNX(__x) warnx __x
64+#else /* DEBUG */
65+#define INODE_WARNX(__x)
66+#endif /* DEBUG */
67+
68+#define CD9660MAXPATH 4096
69+
70+#define ISO_STRING_FILTER_NONE = 0x00
71+#define ISO_STRING_FILTER_DCHARS = 0x01
72+#define ISO_STRING_FILTER_ACHARS = 0x02
73+
74+/*
75+Extended preferences type, in the spirit of what makefs gives us (only ints)
76+*/
77+typedef struct {
78+ const char *shortName; /* Short option */
79+ const char *name; /* option name */
80+ char *value; /* where to stuff the value */
81+ int minLength; /* minimum for value */
82+ int maxLength; /* maximum for value */
83+ const char *desc; /* option description */
84+ int filterFlags;
85+} string_option_t;
86+
87+/******** STRUCTURES **********/
88+
89+/*Defaults*/
90+#define ISO_DEFAULT_VOLUMEID "MAKEFS_CD9660_IMAGE"
91+#define ISO_DEFAULT_APPID "MAKEFS"
92+#define ISO_DEFAULT_PUBLISHER "MAKEFS"
93+#define ISO_DEFAULT_PREPARER "MAKEFS"
94+
95+#define ISO_VOLUME_DESCRIPTOR_STANDARD_ID "CD001"
96+#define ISO_VOLUME_DESCRIPTOR_BOOT 0
97+#define ISO_VOLUME_DESCRIPTOR_PVD 1
98+#define ISO_VOLUME_DESCRIPTOR_TERMINATOR 255
99+
100+/*30 for name and extension, as well as version number and padding bit*/
101+#define ISO_FILENAME_MAXLENGTH_BEFORE_VERSION 30
102+#define ISO_FILENAME_MAXLENGTH 36
103+#define ISO_FILENAME_MAXLENGTH_WITH_PADDING 37
104+
105+#define ISO_FLAG_CLEAR 0x00
106+#define ISO_FLAG_HIDDEN 0x01
107+#define ISO_FLAG_DIRECTORY 0x02
108+#define ISO_FLAG_ASSOCIATED 0x04
109+#define ISO_FLAG_PERMISSIONS 0x08
110+#define ISO_FLAG_RESERVED5 0x10
111+#define ISO_FLAG_RESERVED6 0x20
112+#define ISO_FLAG_FINAL_RECORD 0x40
113+
114+#define ISO_PATHTABLE_ENTRY_BASESIZE 8
115+
116+#define ISO_RRIP_DEFAULT_MOVE_DIR_NAME "RR_MOVED"
117+#define RRIP_DEFAULT_MOVE_DIR_NAME ".rr_moved"
118+
119+#define CD9660_BLOCKS(__sector_size, __bytes) \
120+ howmany((__bytes), (__sector_size))
121+
122+#define CD9660_MEM_ALLOC_ERROR(_F) \
123+ err(EXIT_FAILURE, "%s, %s l. %d", _F, __FILE__, __LINE__)
124+
125+#define CD9660_TYPE_FILE 0x01
126+#define CD9660_TYPE_DIR 0x02
127+#define CD9660_TYPE_DOT 0x04
128+#define CD9660_TYPE_DOTDOT 0x08
129+#define CD9660_TYPE_VIRTUAL 0x80
130+
131+#define CD9660_INODE_HASH_SIZE 1024
132+#define CD9660_SECTOR_SIZE 2048
133+
134+#define CD9660_END_PADDING 150
135+
136+/* Slight modification of the ISO structure in iso.h */
137+typedef struct _iso_directory_record_cd9660 {
138+ u_char length [ISODCL (1, 1)]; /* 711 */
139+ u_char ext_attr_length [ISODCL (2, 2)]; /* 711 */
140+ u_char extent [ISODCL (3, 10)]; /* 733 */
141+ u_char size [ISODCL (11, 18)]; /* 733 */
142+ u_char date [ISODCL (19, 25)]; /* 7 by 711 */
143+ u_char flags [ISODCL (26, 26)];
144+ u_char file_unit_size [ISODCL (27, 27)]; /* 711 */
145+ u_char interleave [ISODCL (28, 28)]; /* 711 */
146+ u_char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
147+ u_char name_len [ISODCL (33, 33)]; /* 711 */
148+ char name [ISO_FILENAME_MAXLENGTH_WITH_PADDING];
149+} iso_directory_record_cd9660;
150+
151+/* TODO: Lots of optimization of this structure */
152+typedef struct _cd9660node {
153+ u_char type;/* Used internally */
154+ /* Tree structure */
155+ struct _cd9660node *parent; /* parent (NULL if root) */
156+ TAILQ_HEAD(cd9660_children_head, _cd9660node) cn_children;
157+ TAILQ_ENTRY(_cd9660node) cn_next_child;
158+
159+ struct _cd9660node *dot_record; /* For directories, used mainly in RRIP */
160+ struct _cd9660node *dot_dot_record;
161+
162+ fsnode *node; /* pointer to fsnode */
163+ struct _iso_directory_record_cd9660 *isoDirRecord;
164+ struct iso_extended_attributes *isoExtAttributes;
165+
166+ /***** SIZE CALCULATION *****/
167+ /*already stored in isoDirRecord, but this is an int version, and will be
168+ copied to isoDirRecord on writing*/
169+ uint32_t fileDataSector;
170+
171+ /*
172+ * same thing, though some notes:
173+ * If a file, this is the file size
174+ * If a directory, this is the size of all its children's
175+ * directory records
176+ * plus necessary padding
177+ */
178+ int64_t fileDataLength;
179+
180+ int64_t fileSectorsUsed;
181+ int fileRecordSize;/*copy of a variable, int for quicker calculations*/
182+
183+ /* Old name, used for renaming - needs to be optimized but low priority */
184+ char o_name [ISO_FILENAME_MAXLENGTH_WITH_PADDING];
185+
186+ /***** SPACE RESERVED FOR EXTENSIONS *****/
187+ /* For memory efficiency's sake - we should move this to a separate struct
188+ and point to null if not needed */
189+ /* For Rock Ridge */
190+ struct _cd9660node *rr_real_parent, *rr_relocated;
191+
192+ int64_t susp_entry_size;
193+ int64_t susp_dot_entry_size;
194+ int64_t susp_dot_dot_entry_size;
195+
196+ /* Continuation area stuff */
197+ int64_t susp_entry_ce_start;
198+ int64_t susp_dot_ce_start;
199+ int64_t susp_dot_dot_ce_start;
200+
201+ int64_t susp_entry_ce_length;
202+ int64_t susp_dot_ce_length;
203+ int64_t susp_dot_dot_ce_length;
204+
205+ /* Data to put at the end of the System Use field */
206+ int64_t su_tail_size;
207+ char *su_tail_data;
208+
209+ /*** PATH TABLE STUFF ***/
210+ int level; /*depth*/
211+ int ptnumber;
212+ struct _cd9660node *ptnext, *ptprev, *ptlast;
213+
214+ /* SUSP entries */
215+ TAILQ_HEAD(susp_linked_list, ISO_SUSP_ATTRIBUTES) head;
216+} cd9660node;
217+
218+typedef struct _path_table_entry
219+{
220+ u_char length[ISODCL (1, 1)];
221+ u_char extended_attribute_length[ISODCL (2, 2)];
222+ u_char first_sector[ISODCL (3, 6)];
223+ u_char parent_number[ISODCL (7, 8)];
224+ u_char name[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
225+} path_table_entry;
226+
227+typedef struct _volume_descriptor
228+{
229+ u_char *volumeDescriptorData; /*ALWAYS 2048 bytes long*/
230+ int64_t sector;
231+ struct _volume_descriptor *next;
232+} volume_descriptor;
233+
234+typedef struct _iso9660_disk {
235+ int sectorSize;
236+ struct iso_primary_descriptor primaryDescriptor;
237+ struct iso_supplementary_descriptor supplementaryDescriptor;
238+
239+ volume_descriptor *firstVolumeDescriptor;
240+
241+ cd9660node *rootNode;
242+
243+ /* Important sector numbers here */
244+ /* primaryDescriptor.type_l_path_table*/
245+ int64_t primaryBigEndianTableSector;
246+
247+ /* primaryDescriptor.type_m_path_table*/
248+ int64_t primaryLittleEndianTableSector;
249+
250+ /* primaryDescriptor.opt_type_l_path_table*/
251+ int64_t secondaryBigEndianTableSector;
252+
253+ /* primaryDescriptor.opt_type_m_path_table*/
254+ int64_t secondaryLittleEndianTableSector;
255+
256+ /* primaryDescriptor.path_table_size*/
257+ int pathTableLength;
258+ int64_t dataFirstSector;
259+
260+ int64_t totalSectors;
261+ /* OPTIONS GO HERE */
262+ int isoLevel;
263+
264+ int include_padding_areas;
265+
266+ int follow_sym_links;
267+ int verbose_level;
268+ int displayHelp;
269+ int keep_bad_images;
270+
271+ /* SUSP options and variables */
272+ int64_t susp_continuation_area_start_sector;
273+ int64_t susp_continuation_area_size;
274+ int64_t susp_continuation_area_current_free;
275+
276+ int rock_ridge_enabled;
277+ /* Other Rock Ridge Variables */
278+ char *rock_ridge_renamed_dir_name;
279+ int rock_ridge_move_count;
280+ cd9660node *rr_moved_dir;
281+
282+ int archimedes_enabled;
283+ int chrp_boot;
284+
285+ /* Spec breaking options */
286+ u_char allow_deep_trees;
287+ u_char allow_start_dot;
288+ u_char allow_max_name; /* Allow 37 char filenames*/
289+ u_char allow_illegal_chars; /* ~, !, # */
290+ u_char allow_lowercase;
291+ u_char allow_multidot;
292+ u_char omit_trailing_period;
293+
294+ /* BOOT INFORMATION HERE */
295+ int has_generic_bootimage; /* Default to 0 */
296+ char *generic_bootimage;
297+
298+ int is_bootable;/* Default to 0 */
299+ int64_t boot_catalog_sector;
300+ boot_volume_descriptor *boot_descriptor;
301+ char * boot_image_directory;
302+
303+ TAILQ_HEAD(boot_image_list,cd9660_boot_image) boot_images;
304+ int image_serialno;
305+ LIST_HEAD(boot_catalog_entries,boot_catalog_entry) boot_entries;
306+
307+} iso9660_disk;
308+
309+/************ FUNCTIONS **************/
310+int cd9660_valid_a_chars(const char *);
311+int cd9660_valid_d_chars(const char *);
312+void cd9660_uppercase_characters(char *, size_t);
313+
314+/* ISO Data Types */
315+void cd9660_721(uint16_t, unsigned char *);
316+void cd9660_731(uint32_t, unsigned char *);
317+void cd9660_722(uint16_t, unsigned char *);
318+void cd9660_732(uint32_t, unsigned char *);
319+void cd9660_bothendian_dword(uint32_t dw, unsigned char *);
320+void cd9660_bothendian_word(uint16_t dw, unsigned char *);
321+void cd9660_set_date(char *, time_t);
322+void cd9660_time_8426(unsigned char *, time_t);
323+void cd9660_time_915(unsigned char *, time_t);
324+
325+/*** Boot Functions ***/
326+int cd9660_write_generic_bootimage(FILE *);
327+int cd9660_write_boot(iso9660_disk *, FILE *);
328+int cd9660_add_boot_disk(iso9660_disk *, const char *);
329+int cd9660_eltorito_add_boot_option(iso9660_disk *, const char *,
330+ const char *);
331+int cd9660_setup_boot(iso9660_disk *, int);
332+int cd9660_setup_boot_volume_descriptor(iso9660_disk *,
333+ volume_descriptor *);
334+
335+
336+/*** Write Functions ***/
337+int cd9660_write_image(iso9660_disk *, const char *image);
338+int cd9660_copy_file(iso9660_disk *, FILE *, off_t, const char *);
339+
340+void cd9660_compute_full_filename(cd9660node *, char *);
341+int cd9660_compute_record_size(iso9660_disk *, cd9660node *);
342+
343+/* Debugging functions */
344+void debug_print_tree(iso9660_disk *, cd9660node *,int);
345+void debug_print_path_tree(cd9660node *);
346+void debug_print_volume_descriptor_information(iso9660_disk *);
347+void debug_dump_to_xml_ptentry(path_table_entry *,int, int);
348+void debug_dump_to_xml_path_table(FILE *, off_t, int, int);
349+void debug_dump_to_xml(FILE *);
350+int debug_get_encoded_number(unsigned char *, int);
351+void debug_dump_integer(const char *, char *,int);
352+void debug_dump_string(const char *,unsigned char *,int);
353+void debug_dump_directory_record_9_1(unsigned char *);
354+void debug_dump_to_xml_volume_descriptor(unsigned char *,int);
355+
356+void cd9660_pad_string_spaces(char *, int);
357+
358+#endif
+15,
-0
1@@ -0,0 +1,15 @@
2+# $NetBSD: Makefile.inc,v 1.3 2012/08/10 12:10:29 joerg Exp $
3+#
4+
5+.PATH: ${.CURDIR}/cd9660 ${NETBSDSRCDIR}/sys/fs/cd9660
6+
7+CPPFLAGS+=-I${NETBSDSRCDIR}/sys/fs/cd9660
8+
9+SRCS+= cd9660_strings.c cd9660_debug.c cd9660_eltorito.c
10+SRCS+= cd9660_write.c cd9660_conversion.c iso9660_rrip.c cd9660_archimedes.c
11+
12+.if !defined(HOSTPROGNAME)
13+.for f in cd9660_debug cd9660_write
14+COPTS.${f}.c+= -Wno-pointer-sign
15+.endfor
16+.endif
+130,
-0
1@@ -0,0 +1,130 @@
2+/* $NetBSD: cd9660_archimedes.c,v 1.3 2022/04/09 10:05:35 riastradh Exp $ */
3+
4+/*-
5+ * Copyright (c) 1998, 2009 Ben Harris
6+ * All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. The name of the author may not be used to endorse or promote products
17+ * derived from this software without specific prior written permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+ */
30+/*
31+ * cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
32+ *
33+ * RISC OS CDFS looks for a special block at the end of the System Use
34+ * Field for each file. If present, this contains the RISC OS load
35+ * and exec address (used to hold the file timestamp and type), the
36+ * file attributes, and a flag indicating whether the first character
37+ * of the filename should be replaced with '!' (since many special
38+ * RISC OS filenames do).
39+ */
40+
41+#if HAVE_NBTOOL_CONFIG_H
42+#include "nbtool_config.h"
43+#endif
44+
45+#include <sys/cdefs.h>
46+#if defined(__RCSID) && !defined(__lint)
47+__RCSID("$NetBSD: cd9660_archimedes.c,v 1.3 2022/04/09 10:05:35 riastradh Exp $");
48+#endif /* !__lint */
49+
50+#include <assert.h>
51+#include <stdint.h>
52+#include <stdio.h>
53+#include <string.h>
54+#include <util.h>
55+
56+#include "makefs.h"
57+#include "cd9660.h"
58+#include "cd9660_archimedes.h"
59+
60+/*
61+ * Convert a Unix time_t (non-leap seconds since 1970-01-01) to a RISC
62+ * OS time (non-leap(?) centiseconds since 1900-01-01(?)).
63+ */
64+
65+static u_int64_t
66+riscos_date(time_t unixtime)
67+{
68+ u_int64_t base;
69+
70+ base = 31536000ULL * 70 + 86400 * 17;
71+ return (((u_int64_t)unixtime) + base)*100;
72+}
73+
74+/*
75+ * Add "ARCHIMEDES" metadata to a node if that seems appropriate.
76+ *
77+ * We touch regular files with names matching /,[0-9a-f]{3}$/ and
78+ * directories matching /^!/.
79+ */
80+static void
81+archimedes_convert_node(cd9660node *node)
82+{
83+ struct ISO_ARCHIMEDES *arc;
84+ size_t len;
85+ int type = -1;
86+ uint64_t stamp;
87+
88+ if (node->su_tail_data != NULL)
89+ /* Something else already has the tail. */
90+ return;
91+
92+ len = strlen(node->node->name);
93+ if (len < 1) return;
94+
95+ if (len >= 4 && node->node->name[len-4] == ',')
96+ /* XXX should support ,xxx and ,lxa */
97+ type = strtoul(node->node->name + len - 3, NULL, 16);
98+ if (type == -1 && node->node->name[0] != '!')
99+ return;
100+ if (type == -1) type = 0;
101+
102+ assert(sizeof(*arc) == 32);
103+ arc = ecalloc(1, sizeof(*arc));
104+
105+ stamp = riscos_date(node->node->inode->st.st_mtime);
106+
107+ memcpy(arc->magic, "ARCHIMEDES", 10);
108+ cd9660_731(0xfff00000 | (type << 8) | (stamp >> 32), arc->loadaddr);
109+ cd9660_731(stamp & 0x00ffffffffULL, arc->execaddr);
110+ arc->ro_attr = RO_ACCESS_UR | RO_ACCESS_OR;
111+ arc->cdfs_attr = node->node->name[0] == '!' ? CDFS_PLING : 0;
112+ node->su_tail_data = (void *)arc;
113+ node->su_tail_size = sizeof(*arc);
114+}
115+
116+/*
117+ * Add "ARCHIMEDES" metadata to an entire tree recursively.
118+ */
119+void
120+archimedes_convert_tree(cd9660node *node)
121+{
122+ cd9660node *cn;
123+
124+ assert(node != NULL);
125+
126+ archimedes_convert_node(node);
127+
128+ /* Recurse on children. */
129+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
130+ archimedes_convert_tree(cn);
131+}
+48,
-0
1@@ -0,0 +1,48 @@
2+/* $NetBSD: cd9660_archimedes.h,v 1.2 2022/04/09 10:05:35 riastradh Exp $ */
3+
4+/*-
5+ * Copyright (c) 1998, 2009 Ben Harris
6+ * All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. The name of the author may not be used to endorse or promote products
17+ * derived from this software without specific prior written permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+ */
30+/*
31+ * cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
32+ */
33+
34+struct ISO_ARCHIMEDES {
35+ char magic[10]; /* "ARCHIMEDES" */
36+ unsigned char loadaddr[4]; /* Load address, little-endian */
37+ unsigned char execaddr[4]; /* Exec address, little-endian */
38+ unsigned char ro_attr; /* RISC OS attributes */
39+#define RO_ACCESS_UR 0x01 /* Owner read */
40+#define RO_ACCESS_UW 0x02 /* Owner write */
41+#define RO_ACCESS_L 0x04 /* Locked */
42+#define RO_ACCESS_OR 0x10 /* Public read */
43+#define RO_ACCESS_OW 0x20 /* Public write */
44+ unsigned char cdfs_attr; /* Extra attributes for CDFS */
45+#define CDFS_PLING 0x01 /* Filename begins with '!' */
46+ char reserved[12];
47+};
48+
49+extern void archimedes_convert_tree(cd9660node *);
+212,
-0
1@@ -0,0 +1,212 @@
2+/* $NetBSD: cd9660_conversion.c,v 1.6 2024/06/17 13:31:17 reinoud Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+#include "cd9660.h"
36+
37+#include <sys/cdefs.h>
38+#if defined(__RCSID) && !defined(__lint)
39+__RCSID("$NetBSD: cd9660_conversion.c,v 1.6 2024/06/17 13:31:17 reinoud Exp $");
40+#endif /* !__lint */
41+
42+
43+static char cd9660_compute_gm_offset(time_t);
44+
45+#if 0
46+static inline int
47+cd9660_pad_even(length)
48+int length;
49+{
50+ return length + (length & 0x01);
51+}
52+#endif
53+
54+/*
55+* These can probably be implemented using a macro
56+*/
57+
58+/* Little endian */
59+void
60+cd9660_721(uint16_t w, unsigned char *twochar)
61+{
62+#if BYTE_ORDER == BIG_ENDIAN
63+ w = bswap16(w);
64+#endif
65+ memcpy(twochar,&w,2);
66+}
67+
68+void
69+cd9660_731(uint32_t w, unsigned char *fourchar)
70+{
71+#if BYTE_ORDER == BIG_ENDIAN
72+ w = bswap32(w);
73+#endif
74+ memcpy(fourchar,&w,4);
75+}
76+
77+/* Big endian */
78+void
79+cd9660_722(uint16_t w, unsigned char *twochar)
80+{
81+#if BYTE_ORDER == LITTLE_ENDIAN
82+ w = bswap16(w);
83+#endif
84+ memcpy(twochar,&w,2);
85+}
86+
87+void
88+cd9660_732(uint32_t w, unsigned char *fourchar)
89+{
90+#if BYTE_ORDER == LITTLE_ENDIAN
91+ w = bswap32(w);
92+#endif
93+ memcpy(fourchar,&w,4);
94+}
95+
96+/**
97+* Convert a dword into a double endian string of eight characters
98+* @param int The double word to convert
99+* @param char* The string to write the both endian double word to - It is assumed this is allocated and at least
100+* eight characters long
101+*/
102+void
103+cd9660_bothendian_dword(uint32_t dw, unsigned char *eightchar)
104+{
105+ uint32_t le, be;
106+#if BYTE_ORDER == LITTLE_ENDIAN
107+ le = dw;
108+ be = bswap32(dw);
109+#endif
110+#if BYTE_ORDER == BIG_ENDIAN
111+ be = dw;
112+ le = bswap32(dw);
113+#endif
114+ memcpy(eightchar, &le, 4);
115+ memcpy((eightchar+4), &be, 4);
116+}
117+
118+/**
119+* Convert a word into a double endian string of four characters
120+* @param int The word to convert
121+* @param char* The string to write the both endian word to - It is assumed this is allocated and at least
122+* four characters long
123+*/
124+void
125+cd9660_bothendian_word(uint16_t dw, unsigned char *fourchar)
126+{
127+ uint16_t le, be;
128+#if BYTE_ORDER == LITTLE_ENDIAN
129+ le = dw;
130+ be = bswap16(dw);
131+#endif
132+#if BYTE_ORDER == BIG_ENDIAN
133+ be = dw;
134+ le = bswap16(dw);
135+#endif
136+ memcpy(fourchar, &le, 2);
137+ memcpy((fourchar+2), &be, 2);
138+}
139+
140+void
141+cd9660_pad_string_spaces(char *str, int len)
142+{
143+ int i;
144+
145+ for (i = 0; i < len; i ++) {
146+ if (str[i] == '\0')
147+ str[i] = 0x20;
148+ }
149+}
150+
151+static char
152+cd9660_compute_gm_offset(time_t tim)
153+{
154+ if (stampst.st_ino)
155+ return 0;
156+
157+ struct tm t, gm;
158+
159+ (void)localtime_r(&tim, &t);
160+ (void)gmtime_r(&tim, &gm);
161+ gm.tm_year -= t.tm_year;
162+ gm.tm_yday -= t.tm_yday;
163+ gm.tm_hour -= t.tm_hour;
164+ gm.tm_min -= t.tm_min;
165+ if (gm.tm_year < 0)
166+ gm.tm_yday = -1;
167+ else if (gm.tm_year > 0)
168+ gm.tm_yday = 1;
169+
170+ return (char)(-(gm.tm_min + 60* (24 * gm.tm_yday + gm.tm_hour)) / 15);
171+}
172+
173+/* Long dates: 17 characters */
174+void
175+cd9660_time_8426(unsigned char *buf, time_t tim)
176+{
177+ struct tm t;
178+ char temp[70]; /* we know its only 18 but gcc can't figure this out */
179+
180+ if (stampst.st_ino)
181+ (void)gmtime_r(&tim, &t);
182+ else
183+ (void)localtime_r(&tim, &t);
184+ (void)snprintf(temp, sizeof(temp), "%04i%02i%02i%02i%02i%02i%02i",
185+ 1900+(int)t.tm_year,
186+ (int)t.tm_mon+1,
187+ (int)t.tm_mday,
188+ (int)t.tm_hour,
189+ (int)t.tm_min,
190+ (int)t.tm_sec,
191+ 0);
192+ (void)memcpy(buf, temp, 16);
193+ buf[16] = cd9660_compute_gm_offset(tim);
194+}
195+
196+/* Short dates: 7 characters */
197+void
198+cd9660_time_915(unsigned char *buf, time_t tim)
199+{
200+ struct tm t;
201+
202+ if (stampst.st_ino)
203+ (void)gmtime_r(&tim, &t);
204+ else
205+ (void)localtime_r(&tim, &t);
206+ buf[0] = t.tm_year;
207+ buf[1] = t.tm_mon+1;
208+ buf[2] = t.tm_mday;
209+ buf[3] = t.tm_hour;
210+ buf[4] = t.tm_min;
211+ buf[5] = t.tm_sec;
212+ buf[6] = cd9660_compute_gm_offset(tim);
213+}
+498,
-0
1@@ -0,0 +1,498 @@
2+/* $NetBSD: cd9660_debug.c,v 1.14 2023/12/28 12:13:55 tsutsui Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+
36+#if HAVE_NBTOOL_CONFIG_H
37+#include "nbtool_config.h"
38+#endif
39+
40+#include <sys/cdefs.h>
41+#include <sys/param.h>
42+
43+#if defined(__RCSID) && !defined(__lint)
44+__RCSID("$NetBSD: cd9660_debug.c,v 1.14 2023/12/28 12:13:55 tsutsui Exp $");
45+#endif /* !__lint */
46+
47+#if !HAVE_NBTOOL_CONFIG_H
48+#include <sys/mount.h>
49+#endif
50+
51+#include "makefs.h"
52+#include "cd9660.h"
53+#include "iso9660_rrip.h"
54+
55+static void debug_print_susp_attrs(cd9660node *, int);
56+static void debug_dump_to_xml_padded_hex_output(const char *, unsigned char *,
57+ int);
58+
59+static inline void
60+print_n_tabs(int n)
61+{
62+ int i;
63+
64+ for (i = 1; i <= n; i ++)
65+ printf("\t");
66+}
67+
68+#if 0
69+void
70+debug_print_rrip_info(n)
71+cd9660node *n;
72+{
73+ struct ISO_SUSP_ATTRIBUTES *t;
74+ TAILQ_FOREACH(t, &node->head, rr_ll) {
75+
76+ }
77+}
78+#endif
79+
80+static void
81+debug_print_susp_attrs(cd9660node *n, int indent)
82+{
83+ struct ISO_SUSP_ATTRIBUTES *t;
84+
85+ TAILQ_FOREACH(t, &n->head, rr_ll) {
86+ print_n_tabs(indent);
87+ printf("-");
88+ printf("%c%c: L:%i",t->attr.su_entry.SP.h.type[0],
89+ t->attr.su_entry.SP.h.type[1],
90+ (int)t->attr.su_entry.SP.h.length[0]);
91+ printf("\n");
92+ }
93+}
94+
95+void
96+debug_print_tree(iso9660_disk *diskStructure, cd9660node *node, int level)
97+{
98+#if !HAVE_NBTOOL_CONFIG_H
99+ cd9660node *cn;
100+
101+ print_n_tabs(level);
102+ if (node->type & CD9660_TYPE_DOT) {
103+ printf(". (%i)\n",
104+ isonum_733(node->isoDirRecord->extent));
105+ } else if (node->type & CD9660_TYPE_DOTDOT) {
106+ printf("..(%i)\n",
107+ isonum_733(node->isoDirRecord->extent));
108+ } else if (node->isoDirRecord->name[0]=='\0') {
109+ printf("(ROOT) (%" PRIu32 " to %" PRId64 ")\n",
110+ node->fileDataSector,
111+ node->fileDataSector +
112+ node->fileSectorsUsed - 1);
113+ } else {
114+ printf("%s (%s) (%" PRIu32 " to %" PRId64 ")\n",
115+ node->isoDirRecord->name,
116+ (node->isoDirRecord->flags[0]
117+ & ISO_FLAG_DIRECTORY) ? "DIR" : "FILE",
118+ node->fileDataSector,
119+ (node->fileSectorsUsed == 0) ?
120+ node->fileDataSector :
121+ node->fileDataSector
122+ + node->fileSectorsUsed - 1);
123+ }
124+ if (diskStructure->rock_ridge_enabled)
125+ debug_print_susp_attrs(node, level + 1);
126+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
127+ debug_print_tree(diskStructure, cn, level + 1);
128+#else
129+ printf("Sorry, debugging is not supported in host-tools mode.\n");
130+#endif
131+}
132+
133+void
134+debug_print_path_tree(cd9660node *n)
135+{
136+ cd9660node *iterator = n;
137+
138+ /* Only display this message when called with the root node */
139+ if (n->parent == NULL)
140+ printf("debug_print_path_table: Dumping path table contents\n");
141+
142+ while (iterator != NULL) {
143+ if (iterator->isoDirRecord->name[0] == '\0')
144+ printf("0) (ROOT)\n");
145+ else
146+ printf("%i) %s\n", iterator->level,
147+ iterator->isoDirRecord->name);
148+
149+ iterator = iterator->ptnext;
150+ }
151+}
152+
153+void
154+debug_print_volume_descriptor_information(iso9660_disk *diskStructure)
155+{
156+ volume_descriptor *tmp = diskStructure->firstVolumeDescriptor;
157+ char temp[CD9660_SECTOR_SIZE];
158+
159+ printf("==Listing Volume Descriptors==\n");
160+
161+ while (tmp != NULL) {
162+ memset(temp, 0, CD9660_SECTOR_SIZE);
163+ memcpy(temp, tmp->volumeDescriptorData + 1, 5);
164+ printf("Volume descriptor in sector %" PRId64
165+ ": type %i, ID %s\n",
166+ tmp->sector, tmp->volumeDescriptorData[0], temp);
167+ switch(tmp->volumeDescriptorData[0]) {
168+ case 0:/*boot record*/
169+ break;
170+
171+ case 1: /* PVD */
172+ break;
173+
174+ case 2: /* SVD */
175+ break;
176+
177+ case 3: /* Volume Partition Descriptor */
178+ break;
179+
180+ case 255: /* terminator */
181+ break;
182+ }
183+ tmp = tmp->next;
184+ }
185+
186+ printf("==Done Listing Volume Descriptors==\n");
187+}
188+
189+void
190+debug_dump_to_xml_ptentry(path_table_entry *pttemp, int num, int mode)
191+{
192+ printf("<ptentry num=\"%i\">\n" ,num);
193+ printf("<length>%i</length>\n", pttemp->length[0]);
194+ printf("<extended_attribute_length>%i</extended_attribute_length>\n",
195+ pttemp->extended_attribute_length[0]);
196+ printf("<parent_number>%i</parent_number>\n",
197+ debug_get_encoded_number(pttemp->parent_number,mode));
198+ debug_dump_to_xml_padded_hex_output("name",
199+ pttemp->name, pttemp->length[0]);
200+ printf("</ptentry>\n");
201+}
202+
203+void
204+debug_dump_to_xml_path_table(FILE *fd, off_t sector, int size, int mode)
205+{
206+ path_table_entry pttemp;
207+ int t = 0;
208+ int n = 0;
209+
210+ if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
211+ err(EXIT_FAILURE, "fseeko");
212+
213+ while (t < size) {
214+ /* Read fixed data first */
215+ fread(&pttemp, 1, 8, fd);
216+ t += 8;
217+ /* Read variable */
218+ fread(((unsigned char*)&pttemp) + 8, 1, pttemp.length[0], fd);
219+ t += pttemp.length[0];
220+ debug_dump_to_xml_ptentry(&pttemp, n, mode);
221+ n++;
222+ }
223+
224+}
225+
226+/*
227+ * XML Debug output functions
228+ * Dump hierarchy of CD, as well as volume info, to XML
229+ * Can be used later to diff against a standard,
230+ * or just provide easy to read detailed debug output
231+ */
232+void
233+debug_dump_to_xml(FILE *fd)
234+{
235+ unsigned char buf[CD9660_SECTOR_SIZE];
236+ off_t sector;
237+ int t, t2;
238+ struct iso_primary_descriptor primaryVD;
239+ struct _boot_volume_descriptor bootVD;
240+
241+ memset(&primaryVD, 0, sizeof(primaryVD));
242+ printf("<cd9660dump>\n");
243+
244+ /* Display Volume Descriptors */
245+ sector = 16;
246+ do {
247+ if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
248+ err(EXIT_FAILURE, "fseeko");
249+ fread(buf, 1, CD9660_SECTOR_SIZE, fd);
250+ t = (int)((unsigned char)buf[0]);
251+ switch (t) {
252+ case 0:
253+ memcpy(&bootVD, buf, CD9660_SECTOR_SIZE);
254+ break;
255+ case 1:
256+ memcpy(&primaryVD, buf, CD9660_SECTOR_SIZE);
257+ break;
258+ }
259+ debug_dump_to_xml_volume_descriptor(buf, sector);
260+ sector++;
261+ } while (t != 255);
262+
263+ t = debug_get_encoded_number((u_char *)primaryVD.type_l_path_table,
264+ 731);
265+ t2 = debug_get_encoded_number((u_char *)primaryVD.path_table_size, 733);
266+ printf("Path table 1 located at sector %i and is %i bytes long\n",
267+ t,t2);
268+ debug_dump_to_xml_path_table(fd, t, t2, 721);
269+
270+ t = debug_get_encoded_number((u_char *)primaryVD.type_m_path_table,
271+ 731);
272+ debug_dump_to_xml_path_table(fd, t, t2, 722);
273+
274+ printf("</cd9660dump>\n");
275+}
276+
277+static void
278+debug_dump_to_xml_padded_hex_output(const char *element, unsigned char *buf,
279+ int len)
280+{
281+ int i;
282+ int t;
283+
284+ printf("<%s>",element);
285+ for (i = 0; i < len; i++) {
286+ t = (unsigned char)buf[i];
287+ if (t >= 32 && t < 127)
288+ printf("%c",t);
289+ }
290+ printf("</%s>\n",element);
291+
292+ printf("<%s:hex>",element);
293+ for (i = 0; i < len; i++) {
294+ t = (unsigned char)buf[i];
295+ printf(" %x",t);
296+ }
297+ printf("</%s:hex>\n",element);
298+}
299+
300+int
301+debug_get_encoded_number(unsigned char* buf, int mode)
302+{
303+#if !HAVE_NBTOOL_CONFIG_H
304+ switch (mode) {
305+ /* 711: Single bite */
306+ case 711:
307+ return isonum_711(buf);
308+
309+ /* 712: Single signed byte */
310+ case 712:
311+ return isonum_712((signed char *)buf);
312+
313+ /* 721: 16 bit LE */
314+ case 721:
315+ return isonum_721(buf);
316+
317+ /* 731: 32 bit LE */
318+ case 731:
319+ return isonum_731(buf);
320+
321+ /* 722: 16 bit BE */
322+ case 722:
323+ return isonum_722(buf);
324+
325+ /* 732: 32 bit BE */
326+ case 732:
327+ return isonum_732(buf);
328+
329+ /* 723: 16 bit bothE */
330+ case 723:
331+ return isonum_723(buf);
332+
333+ /* 733: 32 bit bothE */
334+ case 733:
335+ return isonum_733(buf);
336+ }
337+#endif
338+ return 0;
339+}
340+
341+void
342+debug_dump_integer(const char *element, char* buf, int mode)
343+{
344+ printf("<%s>%i</%s>\n", element,
345+ debug_get_encoded_number((unsigned char *)buf, mode), element);
346+}
347+
348+void
349+debug_dump_string(const char *element NETCOMPAT_UNUSED,
350+ unsigned char *buf NETCOMPAT_UNUSED, int len NETCOMPAT_UNUSED)
351+{
352+
353+}
354+
355+void
356+debug_dump_directory_record_9_1(unsigned char* buf)
357+{
358+ printf("<directoryrecord>\n");
359+ debug_dump_integer("length",
360+ ((struct iso_directory_record*) buf)->length, 711);
361+ debug_dump_integer("ext_attr_length",
362+ ((struct iso_directory_record*) buf)->ext_attr_length,711);
363+ debug_dump_integer("extent",
364+ (char *)((struct iso_directory_record*) buf)->extent, 733);
365+ debug_dump_integer("size",
366+ (char *)((struct iso_directory_record*) buf)->size, 733);
367+ debug_dump_integer("flags",
368+ ((struct iso_directory_record*) buf)->flags, 711);
369+ debug_dump_integer("file_unit_size",
370+ ((struct iso_directory_record*) buf)->file_unit_size,711);
371+ debug_dump_integer("interleave",
372+ ((struct iso_directory_record*) buf)->interleave, 711);
373+ debug_dump_integer("volume_sequence_number",
374+ ((struct iso_directory_record*) buf)->volume_sequence_number,
375+ 723);
376+ debug_dump_integer("name_len",
377+ ((struct iso_directory_record*) buf)->name_len, 711);
378+ debug_dump_to_xml_padded_hex_output("name",
379+ (u_char *)((struct iso_directory_record*) buf)->name,
380+ debug_get_encoded_number((u_char *)
381+ ((struct iso_directory_record*) buf)->length, 711));
382+ printf("</directoryrecord>\n");
383+}
384+
385+
386+void
387+debug_dump_to_xml_volume_descriptor(unsigned char* buf, int sector)
388+{
389+ printf("<volumedescriptor sector=\"%i\">\n", sector);
390+ printf("<vdtype>");
391+ switch(buf[0]) {
392+ case 0:
393+ printf("boot");
394+ break;
395+
396+ case 1:
397+ printf("primary");
398+ break;
399+
400+ case 2:
401+ printf("supplementary");
402+ break;
403+
404+ case 3:
405+ printf("volume partition descriptor");
406+ break;
407+
408+ case 255:
409+ printf("terminator");
410+ break;
411+ }
412+
413+ printf("</vdtype>\n");
414+ switch(buf[0]) {
415+ case 1:
416+ debug_dump_integer("type",
417+ ((struct iso_primary_descriptor*)buf)->type, 711);
418+ debug_dump_to_xml_padded_hex_output("id",
419+ (u_char *)((struct iso_primary_descriptor*) buf)->id,
420+ ISODCL ( 2, 6));
421+ debug_dump_integer("version",
422+ ((struct iso_primary_descriptor*)buf)->version,
423+ 711);
424+ debug_dump_to_xml_padded_hex_output("system_id",
425+ (u_char *)((struct iso_primary_descriptor*)buf)->system_id,
426+ ISODCL(9,40));
427+ debug_dump_to_xml_padded_hex_output("volume_id",
428+ (u_char *)((struct iso_primary_descriptor*)buf)->volume_id,
429+ ISODCL(41,72));
430+ debug_dump_integer("volume_space_size",
431+ ((struct iso_primary_descriptor*)buf)->volume_space_size,
432+ 733);
433+ debug_dump_integer("volume_set_size",
434+ ((struct iso_primary_descriptor*)buf)->volume_set_size,
435+ 733);
436+ debug_dump_integer("volume_sequence_number",
437+ ((struct iso_primary_descriptor*)buf)->volume_sequence_number,
438+ 723);
439+ debug_dump_integer("logical_block_size",
440+ ((struct iso_primary_descriptor*)buf)->logical_block_size,
441+ 723);
442+ debug_dump_integer("path_table_size",
443+ ((struct iso_primary_descriptor*)buf)->path_table_size,
444+ 733);
445+ debug_dump_integer("type_l_path_table",
446+ ((struct iso_primary_descriptor*)buf)->type_l_path_table,
447+ 731);
448+ debug_dump_integer("opt_type_l_path_table",
449+ ((struct iso_primary_descriptor*)buf)->opt_type_l_path_table,
450+ 731);
451+ debug_dump_integer("type_m_path_table",
452+ ((struct iso_primary_descriptor*)buf)->type_m_path_table,
453+ 732);
454+ debug_dump_integer("opt_type_m_path_table",
455+ ((struct iso_primary_descriptor*)buf)->opt_type_m_path_table,732);
456+ debug_dump_directory_record_9_1(
457+ (u_char *)((struct iso_primary_descriptor*)buf)->root_directory_record);
458+ debug_dump_to_xml_padded_hex_output("volume_set_id",
459+ (u_char *)((struct iso_primary_descriptor*) buf)->volume_set_id,
460+ ISODCL (191, 318));
461+ debug_dump_to_xml_padded_hex_output("publisher_id",
462+ (u_char *)((struct iso_primary_descriptor*) buf)->publisher_id,
463+ ISODCL (319, 446));
464+ debug_dump_to_xml_padded_hex_output("preparer_id",
465+ (u_char *)((struct iso_primary_descriptor*) buf)->preparer_id,
466+ ISODCL (447, 574));
467+ debug_dump_to_xml_padded_hex_output("application_id",
468+ (u_char *)((struct iso_primary_descriptor*) buf)->application_id,
469+ ISODCL (575, 702));
470+ debug_dump_to_xml_padded_hex_output("copyright_file_id",
471+ (u_char *)((struct iso_primary_descriptor*) buf)->copyright_file_id,
472+ ISODCL (703, 739));
473+ debug_dump_to_xml_padded_hex_output("abstract_file_id",
474+ (u_char *)((struct iso_primary_descriptor*) buf)->abstract_file_id,
475+ ISODCL (740, 776));
476+ debug_dump_to_xml_padded_hex_output("bibliographic_file_id",
477+ (u_char *)((struct iso_primary_descriptor*) buf)->bibliographic_file_id,
478+ ISODCL (777, 813));
479+
480+ debug_dump_to_xml_padded_hex_output("creation_date",
481+ (u_char *)((struct iso_primary_descriptor*) buf)->creation_date,
482+ ISODCL (814, 830));
483+ debug_dump_to_xml_padded_hex_output("modification_date",
484+ (u_char *)((struct iso_primary_descriptor*) buf)->modification_date,
485+ ISODCL (831, 847));
486+ debug_dump_to_xml_padded_hex_output("expiration_date",
487+ (u_char *)((struct iso_primary_descriptor*) buf)->expiration_date,
488+ ISODCL (848, 864));
489+ debug_dump_to_xml_padded_hex_output("effective_date",
490+ (u_char *)((struct iso_primary_descriptor*) buf)->effective_date,
491+ ISODCL (865, 881));
492+
493+ debug_dump_to_xml_padded_hex_output("file_structure_version",
494+ (u_char *)((struct iso_primary_descriptor*) buf)->file_structure_version,
495+ ISODCL(882,882));
496+ break;
497+ }
498+ printf("</volumedescriptor>\n");
499+}
+752,
-0
1@@ -0,0 +1,752 @@
2+/* $NetBSD: cd9660_eltorito.c,v 1.27 2023/12/28 12:13:56 tsutsui Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+
36+
37+#include "cd9660.h"
38+#include "cd9660_eltorito.h"
39+#include <sys/bootblock.h>
40+#include <util.h>
41+
42+#include <sys/cdefs.h>
43+#if defined(__RCSID) && !defined(__lint)
44+__RCSID("$NetBSD: cd9660_eltorito.c,v 1.27 2023/12/28 12:13:56 tsutsui Exp $");
45+#endif /* !__lint */
46+
47+#ifdef DEBUG
48+#define ELTORITO_DPRINTF(__x) printf __x
49+#else
50+#define ELTORITO_DPRINTF(__x)
51+#endif
52+
53+#include <util.h>
54+
55+static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
56+static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
57+static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
58+ struct cd9660_boot_image *);
59+static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
60+#if 0
61+static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
62+#endif
63+
64+static struct cd9660_boot_image *default_boot_image;
65+
66+int
67+cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info)
68+{
69+ struct stat stbuf;
70+ const char *mode_msg;
71+ char *temp;
72+ char *sysname;
73+ char *filename;
74+ struct cd9660_boot_image *new_image, *tmp_image;
75+
76+ assert(boot_info != NULL);
77+
78+ if (*boot_info == '\0') {
79+ warnx("Error: Boot disk information must be in the "
80+ "format 'system;filename'");
81+ return 0;
82+ }
83+
84+ /* First decode the boot information */
85+ temp = estrdup(boot_info);
86+
87+ sysname = temp;
88+ filename = strchr(sysname, ';');
89+ if (filename == NULL) {
90+ warnx("supply boot disk information in the format "
91+ "'system;filename'");
92+ free(temp);
93+ return 0;
94+ }
95+
96+ *filename++ = '\0';
97+
98+ if (diskStructure->verbose_level > 0) {
99+ printf("Found bootdisk with system %s, and filename %s\n",
100+ sysname, filename);
101+ }
102+ new_image = ecalloc(1, sizeof(*new_image));
103+ new_image->loadSegment = 0; /* default for now */
104+
105+ /* Decode System */
106+ if (strcmp(sysname, "i386") == 0)
107+ new_image->system = ET_SYS_X86;
108+ else if (strcmp(sysname, "powerpc") == 0)
109+ new_image->system = ET_SYS_PPC;
110+ else if (strcmp(sysname, "macppc") == 0 ||
111+ strcmp(sysname, "mac68k") == 0)
112+ new_image->system = ET_SYS_MAC;
113+ else if (strcmp(sysname, "efi") == 0)
114+ new_image->system = ET_SYS_EFI;
115+ else {
116+ warnx("boot disk system must be "
117+ "i386, powerpc, macppc, mac68k, or efi");
118+ free(temp);
119+ free(new_image);
120+ return 0;
121+ }
122+
123+
124+ new_image->filename = estrdup(filename);
125+
126+ free(temp);
127+
128+ /* Get information about the file */
129+ if (lstat(new_image->filename, &stbuf) == -1)
130+ err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
131+ new_image->filename);
132+
133+ switch (stbuf.st_size) {
134+ case 1440 * 1024:
135+ new_image->targetMode = ET_MEDIA_144FDD;
136+ mode_msg = "Assigned boot image to 1.44 emulation mode";
137+ break;
138+ case 1200 * 1024:
139+ new_image->targetMode = ET_MEDIA_12FDD;
140+ mode_msg = "Assigned boot image to 1.2 emulation mode";
141+ break;
142+ case 2880 * 1024:
143+ new_image->targetMode = ET_MEDIA_288FDD;
144+ mode_msg = "Assigned boot image to 2.88 emulation mode";
145+ break;
146+ default:
147+ new_image->targetMode = ET_MEDIA_NOEM;
148+ mode_msg = "Assigned boot image to no emulation mode";
149+ break;
150+ }
151+
152+ if (diskStructure->verbose_level > 0)
153+ printf("%s\n", mode_msg);
154+
155+ new_image->size = stbuf.st_size;
156+ new_image->num_sectors =
157+ howmany(new_image->size, diskStructure->sectorSize) *
158+ howmany(diskStructure->sectorSize, 512);
159+ if (diskStructure->verbose_level > 0) {
160+ printf("New image has size %d, uses %d 512-byte sectors\n",
161+ new_image->size, new_image->num_sectors);
162+ }
163+ new_image->sector = -1;
164+ /* Bootable by default */
165+ new_image->bootable = ET_BOOTABLE;
166+ /* Add boot disk */
167+
168+ /* Group images for the same platform together. */
169+ TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) {
170+ if (tmp_image->system != new_image->system)
171+ break;
172+ }
173+
174+ if (tmp_image == NULL) {
175+ TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image,
176+ image_list);
177+ } else
178+ TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
179+
180+ new_image->serialno = diskStructure->image_serialno++;
181+
182+ new_image->platform_id = new_image->system;
183+
184+ /* TODO : Need to do anything about the boot image in the tree? */
185+ diskStructure->is_bootable = 1;
186+
187+ /* First boot image is initial/default entry. */
188+ if (default_boot_image == NULL)
189+ default_boot_image = new_image;
190+
191+ return 1;
192+}
193+
194+int
195+cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure,
196+ const char *option_string, const char *value)
197+{
198+ char *eptr;
199+ struct cd9660_boot_image *image;
200+
201+ assert(option_string != NULL);
202+
203+ /* Find the last image added */
204+ TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) {
205+ if (image->serialno + 1 == diskStructure->image_serialno)
206+ break;
207+ }
208+ if (image == NULL)
209+ errx(EXIT_FAILURE, "Attempted to add boot option, "
210+ "but no boot images have been specified");
211+
212+ if (strcmp(option_string, "no-emul-boot") == 0) {
213+ image->targetMode = ET_MEDIA_NOEM;
214+ } else if (strcmp(option_string, "no-boot") == 0) {
215+ image->bootable = ET_NOT_BOOTABLE;
216+ } else if (strcmp(option_string, "hard-disk-boot") == 0) {
217+ image->targetMode = ET_MEDIA_HDD;
218+ } else if (strcmp(option_string, "boot-load-segment") == 0) {
219+ image->loadSegment = strtoul(value, &eptr, 16);
220+ if (eptr == value || *eptr != '\0' || errno != ERANGE) {
221+ warn("%s: strtoul", __func__);
222+ return 0;
223+ }
224+ } else if (strcmp(option_string, "platformid") == 0) {
225+ if (strcmp(value, "efi") == 0)
226+ image->platform_id = ET_SYS_EFI;
227+ else {
228+ warn("%s: unknown platform: %s", __func__, value);
229+ return 0;
230+ }
231+ } else {
232+ return 0;
233+ }
234+ return 1;
235+}
236+
237+static struct boot_catalog_entry *
238+cd9660_init_boot_catalog_entry(void)
239+{
240+ return ecalloc(1, sizeof(struct boot_catalog_entry));
241+}
242+
243+static struct boot_catalog_entry *
244+cd9660_boot_setup_validation_entry(char sys)
245+{
246+ struct boot_catalog_entry *entry;
247+ boot_catalog_validation_entry *ve;
248+ int16_t checksum;
249+ unsigned char *csptr;
250+ size_t i;
251+ entry = cd9660_init_boot_catalog_entry();
252+
253+ entry->entry_type = ET_ENTRY_VE;
254+ ve = &entry->entry_data.VE;
255+
256+ ve->header_id[0] = 1;
257+ ve->platform_id[0] = sys;
258+ ve->key[0] = 0x55;
259+ ve->key[1] = 0xAA;
260+
261+ /* Calculate checksum */
262+ checksum = 0;
263+ cd9660_721(0, ve->checksum);
264+ csptr = (unsigned char*)ve;
265+ for (i = 0; i < sizeof(*ve); i += 2) {
266+ checksum += (int16_t)csptr[i];
267+ checksum += 256 * (int16_t)csptr[i + 1];
268+ }
269+ checksum = -checksum;
270+ cd9660_721(checksum, ve->checksum);
271+
272+ ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
273+ "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
274+ ve->key[0], ve->key[1], checksum));
275+ return entry;
276+}
277+
278+static struct boot_catalog_entry *
279+cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
280+{
281+ struct boot_catalog_entry *default_entry;
282+ boot_catalog_initial_entry *ie;
283+
284+ default_entry = cd9660_init_boot_catalog_entry();
285+ if (default_entry == NULL)
286+ return NULL;
287+
288+ default_entry->entry_type = ET_ENTRY_IE;
289+ ie = &default_entry->entry_data.IE;
290+
291+ ie->boot_indicator[0] = disk->bootable;
292+ ie->media_type[0] = disk->targetMode;
293+ cd9660_721(disk->loadSegment, ie->load_segment);
294+ ie->system_type[0] = disk->system;
295+ cd9660_721(disk->num_sectors, ie->sector_count);
296+ cd9660_731(disk->sector, ie->load_rba);
297+
298+ ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
299+ "load segment %04x, system type %d, sector count %d, "
300+ "load rba %d\n", __func__, ie->boot_indicator[0],
301+ ie->media_type[0], disk->loadSegment, ie->system_type[0],
302+ disk->num_sectors, disk->sector));
303+ return default_entry;
304+}
305+
306+static struct boot_catalog_entry *
307+cd9660_boot_setup_section_head(char platform)
308+{
309+ struct boot_catalog_entry *entry;
310+ boot_catalog_section_header *sh;
311+
312+ entry = cd9660_init_boot_catalog_entry();
313+ if (entry == NULL)
314+ return NULL;
315+
316+ entry->entry_type = ET_ENTRY_SH;
317+ sh = &entry->entry_data.SH;
318+ /* More by default. The last one will manually be set to 0x91 */
319+ sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
320+ sh->platform_id[0] = platform;
321+ sh->num_section_entries[0] = 0;
322+ return entry;
323+}
324+
325+static struct boot_catalog_entry *
326+cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
327+{
328+ struct boot_catalog_entry *entry;
329+ boot_catalog_section_entry *se;
330+ if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
331+ return NULL;
332+
333+ entry->entry_type = ET_ENTRY_SE;
334+ se = &entry->entry_data.SE;
335+
336+ se->boot_indicator[0] = ET_BOOTABLE;
337+ se->media_type[0] = disk->targetMode;
338+ cd9660_721(disk->loadSegment, se->load_segment);
339+ cd9660_721(disk->num_sectors, se->sector_count);
340+ cd9660_731(disk->sector, se->load_rba);
341+ return entry;
342+}
343+
344+#if 0
345+static u_char
346+cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
347+{
348+ /*
349+ For hard drive booting, we need to examine the MBR to figure
350+ out what the partition type is
351+ */
352+ return 0;
353+}
354+#endif
355+
356+/*
357+ * Set up the BVD, Boot catalog, and the boot entries, but do no writing
358+ */
359+int
360+cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector)
361+{
362+ int sector;
363+ int used_sectors;
364+ int num_entries = 0;
365+ int catalog_sectors;
366+ struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, *efi_head,
367+ *valid_entry, *default_entry, *temp, *head, **headp, *next;
368+ struct cd9660_boot_image *tmp_disk;
369+ u_char system;
370+
371+ headp = NULL;
372+ x86_head = mac_head = ppc_head = efi_head = NULL;
373+
374+ /* If there are no boot disks, don't bother building boot information */
375+ if (TAILQ_EMPTY(&diskStructure->boot_images))
376+ return 0;
377+
378+ /* Point to catalog: For now assume it consumes one sector */
379+ ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
380+ diskStructure->boot_catalog_sector = first_sector;
381+ cd9660_731(first_sector,
382+ diskStructure->boot_descriptor->boot_catalog_pointer);
383+
384+ /*
385+ * Use system type of default image for validation entry. Fallback to
386+ * X86 system type if not found.
387+ */
388+ system = default_boot_image != NULL ? default_boot_image->system :
389+ ET_SYS_X86;
390+
391+ /* Step 1: Generate boot catalog */
392+ /* Step 1a: Validation entry */
393+ valid_entry = cd9660_boot_setup_validation_entry(system);
394+ if (valid_entry == NULL)
395+ return -1;
396+
397+ /*
398+ * Count how many boot images there are,
399+ * and how many sectors they consume.
400+ */
401+ num_entries = 1;
402+ used_sectors = 0;
403+
404+ TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
405+ used_sectors += tmp_disk->num_sectors;
406+
407+ /* One default entry per image */
408+ num_entries++;
409+ }
410+ catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize);
411+ used_sectors += catalog_sectors;
412+
413+ if (diskStructure->verbose_level > 0) {
414+ printf("%s: there will be %i entries consuming %i sectors. "
415+ "Catalog is %i sectors\n", __func__, num_entries,
416+ used_sectors, catalog_sectors);
417+ }
418+
419+ /* Populate sector numbers */
420+ sector = first_sector + catalog_sectors;
421+ TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
422+ tmp_disk->sector = sector;
423+ sector += tmp_disk->num_sectors /
424+ (diskStructure->sectorSize / 512);
425+ }
426+
427+ LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct);
428+
429+ /* Step 1b: Initial/default entry */
430+ /* TODO : PARAM */
431+ if (default_boot_image != NULL) {
432+ struct cd9660_boot_image *tcbi;
433+ TAILQ_FOREACH(tcbi, &diskStructure->boot_images, image_list) {
434+ if (tcbi == default_boot_image) {
435+ tmp_disk = tcbi;
436+ break;
437+ }
438+ }
439+ }
440+ if (tmp_disk == NULL)
441+ tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
442+ default_entry = cd9660_boot_setup_default_entry(tmp_disk);
443+ if (default_entry == NULL) {
444+ warnx("Error: memory allocation failed in cd9660_setup_boot");
445+ return -1;
446+ }
447+
448+ LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
449+
450+ /* Todo: multiple default entries? */
451+
452+ tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
453+
454+ head = NULL;
455+ temp = default_entry;
456+
457+ /* If multiple boot images are given : */
458+ for (; tmp_disk != NULL; tmp_disk = TAILQ_NEXT(tmp_disk, image_list)) {
459+ if (tmp_disk == default_boot_image)
460+ continue;
461+
462+ /* Step 2: Section header */
463+ switch (tmp_disk->platform_id) {
464+ case ET_SYS_X86:
465+ headp = &x86_head;
466+ break;
467+ case ET_SYS_PPC:
468+ headp = &ppc_head;
469+ break;
470+ case ET_SYS_MAC:
471+ headp = &mac_head;
472+ break;
473+ case ET_SYS_EFI:
474+ headp = &efi_head;
475+ break;
476+ default:
477+ warnx("%s: internal error: unknown system type",
478+ __func__);
479+ return -1;
480+ }
481+
482+ if (*headp == NULL) {
483+ head =
484+ cd9660_boot_setup_section_head(tmp_disk->platform_id);
485+ if (head == NULL) {
486+ warnx("Error: memory allocation failed in "
487+ "cd9660_setup_boot");
488+ return -1;
489+ }
490+ LIST_INSERT_AFTER(default_entry, head, ll_struct);
491+ *headp = head;
492+ } else
493+ head = *headp;
494+
495+ head->entry_data.SH.num_section_entries[0]++;
496+
497+ /* Step 2a: Section entry and extensions */
498+ temp = cd9660_boot_setup_section_entry(tmp_disk);
499+ if (temp == NULL) {
500+ warn("%s: cd9660_boot_setup_section_entry", __func__);
501+ return -1;
502+ }
503+
504+ while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
505+ next->entry_type == ET_ENTRY_SE)
506+ head = next;
507+
508+ LIST_INSERT_AFTER(head, temp, ll_struct);
509+ }
510+
511+ /* Find the last Section Header entry and mark it as the last. */
512+ head = NULL;
513+ LIST_FOREACH(next, &diskStructure->boot_entries, ll_struct) {
514+ if (next->entry_type == ET_ENTRY_SH)
515+ head = next;
516+ }
517+ if (head != NULL)
518+ head->entry_data.SH.header_indicator[0] = ET_SECTION_HEADER_LAST;
519+
520+ /* TODO: Remaining boot disks when implemented */
521+
522+ return first_sector + used_sectors;
523+}
524+
525+int
526+cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure,
527+ volume_descriptor *bvd)
528+{
529+ boot_volume_descriptor *bvdData =
530+ (boot_volume_descriptor*)bvd->volumeDescriptorData;
531+
532+ bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
533+ memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
534+ bvdData->version[0] = 1;
535+ memcpy(bvdData->boot_system_identifier, ET_ID, 23);
536+ memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
537+ diskStructure->boot_descriptor =
538+ (boot_volume_descriptor*) bvd->volumeDescriptorData;
539+ return 1;
540+}
541+
542+static int
543+cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start,
544+ off_t nsectors, int type)
545+{
546+ uint8_t val;
547+ uint32_t lba;
548+
549+ if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1)
550+ err(EXIT_FAILURE, "fseeko");
551+
552+ val = 0x80; /* Bootable */
553+ fwrite(&val, sizeof(val), 1, fd);
554+
555+ val = 0xff; /* CHS begin */
556+ fwrite(&val, sizeof(val), 1, fd);
557+ fwrite(&val, sizeof(val), 1, fd);
558+ fwrite(&val, sizeof(val), 1, fd);
559+
560+ val = type; /* Part type */
561+ fwrite(&val, sizeof(val), 1, fd);
562+
563+ val = 0xff; /* CHS end */
564+ fwrite(&val, sizeof(val), 1, fd);
565+ fwrite(&val, sizeof(val), 1, fd);
566+ fwrite(&val, sizeof(val), 1, fd);
567+
568+ /* LBA extent */
569+ lba = htole32(sector_start);
570+ fwrite(&lba, sizeof(lba), 1, fd);
571+ lba = htole32(nsectors);
572+ fwrite(&lba, sizeof(lba), 1, fd);
573+
574+ return 0;
575+}
576+
577+static int
578+cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions,
579+ off_t sector_start, off_t nsectors, off_t sector_size,
580+ const char *part_name, const char *part_type)
581+{
582+ uint32_t apm32, part_status;
583+ uint16_t apm16;
584+
585+ /* See Apple Tech Note 1189 for the details about the pmPartStatus
586+ * flags.
587+ * Below the flags which are default:
588+ * - IsValid 0x01
589+ * - IsAllocated 0x02
590+ * - IsReadable 0x10
591+ * - IsWritable 0x20
592+ */
593+ part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE |
594+ APPLE_PS_WRITABLE;
595+
596+ if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1)
597+ err(EXIT_FAILURE, "fseeko");
598+
599+ /* Signature */
600+ apm16 = htobe16(0x504d);
601+ fwrite(&apm16, sizeof(apm16), 1, fd);
602+ apm16 = 0;
603+ fwrite(&apm16, sizeof(apm16), 1, fd);
604+
605+ /* Total number of partitions */
606+ apm32 = htobe32(total_partitions);
607+ fwrite(&apm32, sizeof(apm32), 1, fd);
608+ /* Bounds */
609+ apm32 = htobe32(sector_start);
610+ fwrite(&apm32, sizeof(apm32), 1, fd);
611+ apm32 = htobe32(nsectors);
612+ fwrite(&apm32, sizeof(apm32), 1, fd);
613+
614+ fwrite(part_name, strlen(part_name) + 1, 1, fd);
615+ fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
616+ fwrite(part_type, strlen(part_type) + 1, 1, fd);
617+ fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR);
618+
619+ apm32 = 0;
620+ /* pmLgDataStart */
621+ fwrite(&apm32, sizeof(apm32), 1, fd);
622+ /* pmDataCnt */
623+ apm32 = htobe32(nsectors);
624+ fwrite(&apm32, sizeof(apm32), 1, fd);
625+ /* pmPartStatus */
626+ apm32 = htobe32(part_status);
627+ fwrite(&apm32, sizeof(apm32), 1, fd);
628+
629+ return 0;
630+}
631+
632+int
633+cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd)
634+{
635+ struct boot_catalog_entry *e;
636+ struct cd9660_boot_image *t;
637+ int apm_partitions = 0;
638+ int mbr_partitions = 0;
639+
640+ /* write boot catalog */
641+ if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector *
642+ diskStructure->sectorSize, SEEK_SET) == -1)
643+ err(EXIT_FAILURE, "fseeko");
644+
645+ if (diskStructure->verbose_level > 0) {
646+ printf("Writing boot catalog to sector %" PRId64 "\n",
647+ diskStructure->boot_catalog_sector);
648+ }
649+ LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) {
650+ if (diskStructure->verbose_level > 0) {
651+ printf("Writing catalog entry of type %d\n",
652+ e->entry_type);
653+ }
654+ /*
655+ * It doesnt matter which one gets written
656+ * since they are the same size
657+ */
658+ fwrite(&(e->entry_data.VE), 1, 32, fd);
659+ }
660+ if (diskStructure->verbose_level > 0)
661+ printf("Finished writing boot catalog\n");
662+
663+ /* copy boot images */
664+ TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
665+ if (diskStructure->verbose_level > 0) {
666+ printf("Writing boot image from %s to sectors %d\n",
667+ t->filename, t->sector);
668+ }
669+ cd9660_copy_file(diskStructure, fd, t->sector, t->filename);
670+
671+ if (t->system == ET_SYS_MAC)
672+ apm_partitions++;
673+ if (t->system == ET_SYS_PPC)
674+ mbr_partitions++;
675+ }
676+
677+ /* some systems need partition tables as well */
678+ if (mbr_partitions > 0 || diskStructure->chrp_boot) {
679+ uint16_t sig;
680+
681+ fseek(fd, 0x1fe, SEEK_SET);
682+ sig = htole16(0xaa55);
683+ fwrite(&sig, sizeof(sig), 1, fd);
684+
685+ mbr_partitions = 0;
686+
687+ /* Write ISO9660 descriptor, enclosing the whole disk */
688+ if (diskStructure->chrp_boot)
689+ cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
690+ 0, diskStructure->totalSectors *
691+ (diskStructure->sectorSize / 512), 0x96);
692+
693+ /* Write all partition entries */
694+ TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
695+ if (t->system != ET_SYS_PPC)
696+ continue;
697+ cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
698+ t->sector * (diskStructure->sectorSize / 512),
699+ t->num_sectors * (diskStructure->sectorSize / 512),
700+ 0x41 /* PReP Boot */);
701+ }
702+ }
703+
704+ if (apm_partitions > 0) {
705+ /* Write DDR and global APM info */
706+ uint32_t apm32;
707+ uint16_t apm16;
708+ int total_parts;
709+
710+ fseek(fd, 0, SEEK_SET);
711+ apm16 = htobe16(0x4552);
712+ fwrite(&apm16, sizeof(apm16), 1, fd);
713+ /* Device block size */
714+ apm16 = htobe16(512);
715+ fwrite(&apm16, sizeof(apm16), 1, fd);
716+ /* Device block count */
717+ apm32 = htobe32(diskStructure->totalSectors *
718+ (diskStructure->sectorSize / 512));
719+ fwrite(&apm32, sizeof(apm32), 1, fd);
720+ /* Device type/id */
721+ apm16 = htobe16(1);
722+ fwrite(&apm16, sizeof(apm16), 1, fd);
723+ fwrite(&apm16, sizeof(apm16), 1, fd);
724+
725+ /* Count total needed entries */
726+ total_parts = 2 + apm_partitions; /* Self + ISO9660 */
727+
728+ /* Write self-descriptor */
729+ cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
730+ total_parts, 512, "Apple", "Apple_partition_map");
731+
732+ /* Write all partition entries */
733+ apm_partitions = 0;
734+ TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
735+ if (t->system != ET_SYS_MAC)
736+ continue;
737+
738+ cd9660_write_apm_partition_entry(fd,
739+ 1 + apm_partitions++, total_parts,
740+ t->sector * (diskStructure->sectorSize / 512),
741+ t->num_sectors * (diskStructure->sectorSize / 512),
742+ 512, "CD Boot", "Apple_Bootstrap");
743+ }
744+
745+ /* Write ISO9660 descriptor, enclosing the whole disk */
746+ cd9660_write_apm_partition_entry(fd, 2 + apm_partitions,
747+ total_parts, 0, diskStructure->totalSectors *
748+ (diskStructure->sectorSize / 512), 512, "ISO9660",
749+ "CD_ROM_Mode_1");
750+ }
751+
752+ return 0;
753+}
+164,
-0
1@@ -0,0 +1,164 @@
2+/* $NetBSD: cd9660_eltorito.h,v 1.6 2017/01/24 11:22:43 nonaka Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+
36+#ifndef _CD9660_ELTORITO_H_
37+#define _CD9660_ELTORITO_H_
38+
39+/* Boot defines */
40+#define ET_ID "EL TORITO SPECIFICATION"
41+#define ET_SYS_X86 0
42+#define ET_SYS_PPC 1
43+#define ET_SYS_MAC 2
44+#define ET_SYS_EFI 0xef /* Platform ID at section header entry */
45+
46+#define ET_BOOT_ENTRY_SIZE 0x20
47+
48+#define ET_BOOTABLE 0x88
49+#define ET_NOT_BOOTABLE 0
50+
51+#define ET_MEDIA_NOEM 0
52+#define ET_MEDIA_12FDD 1
53+#define ET_MEDIA_144FDD 2
54+#define ET_MEDIA_288FDD 3
55+#define ET_MEDIA_HDD 4
56+
57+#define ET_INDICATOR_HEADERMORE 0x90
58+#define ET_INDICATOR_HEADERLAST 0x91
59+#define ET_INDICATOR_EXTENSION 0x44
60+
61+/*** Boot Structures ***/
62+
63+typedef struct _boot_volume_descriptor {
64+ u_char boot_record_indicator [ISODCL(0x00,0x00)];
65+ u_char identifier [ISODCL(0x01,0x05)];
66+ u_char version [ISODCL(0x06,0x06)];
67+ u_char boot_system_identifier [ISODCL(0x07,0x26)];
68+ u_char unused1 [ISODCL(0x27,0x46)];
69+ u_char boot_catalog_pointer [ISODCL(0x47,0x4A)];
70+ u_char unused2 [ISODCL(0x4B,0x7FF)];
71+} boot_volume_descriptor;
72+
73+typedef struct _boot_catalog_validation_entry {
74+ u_char header_id [ISODCL(0x00,0x00)];
75+ u_char platform_id [ISODCL(0x01,0x01)];
76+ u_char reserved1 [ISODCL(0x02,0x03)];
77+ u_char manufacturer [ISODCL(0x04,0x1B)];
78+ u_char checksum [ISODCL(0x1C,0x1D)];
79+ u_char key [ISODCL(0x1E,0x1F)];
80+} boot_catalog_validation_entry;
81+
82+typedef struct _boot_catalog_initial_entry {
83+ u_char boot_indicator [ISODCL(0x00,0x00)];
84+ u_char media_type [ISODCL(0x01,0x01)];
85+ u_char load_segment [ISODCL(0x02,0x03)];
86+ u_char system_type [ISODCL(0x04,0x04)];
87+ u_char unused_1 [ISODCL(0x05,0x05)];
88+ u_char sector_count [ISODCL(0x06,0x07)];
89+ u_char load_rba [ISODCL(0x08,0x0B)];
90+ u_char unused_2 [ISODCL(0x0C,0x1F)];
91+} boot_catalog_initial_entry;
92+
93+#define ET_SECTION_HEADER_MORE 0x90
94+#define ET_SECTION_HEADER_LAST 0x91
95+
96+typedef struct _boot_catalog_section_header {
97+ u_char header_indicator [ISODCL(0x00,0x00)];
98+ u_char platform_id [ISODCL(0x01,0x01)];
99+ u_char num_section_entries [ISODCL(0x02,0x03)];
100+ u_char id_string [ISODCL(0x04,0x1F)];
101+} boot_catalog_section_header;
102+
103+typedef struct _boot_catalog_section_entry {
104+ u_char boot_indicator [ISODCL(0x00,0x00)];
105+ u_char media_type [ISODCL(0x01,0x01)];
106+ u_char load_segment [ISODCL(0x02,0x03)];
107+ u_char system_type [ISODCL(0x04,0x04)];
108+ u_char unused_1 [ISODCL(0x05,0x05)];
109+ u_char sector_count [ISODCL(0x06,0x07)];
110+ u_char load_rba [ISODCL(0x08,0x0B)];
111+ u_char selection_criteria [ISODCL(0x0C,0x0C)];
112+ u_char vendor_criteria [ISODCL(0x0D,0x1F)];
113+} boot_catalog_section_entry;
114+
115+typedef struct _boot_catalog_section_entry_extension {
116+ u_char extension_indicator [ISODCL(0x00,0x00)];
117+ u_char flags [ISODCL(0x01,0x01)];
118+ u_char vendor_criteria [ISODCL(0x02,0x1F)];
119+} boot_catalog_section_entry_extension;
120+
121+#define ET_ENTRY_VE 1
122+#define ET_ENTRY_IE 2
123+#define ET_ENTRY_SH 3
124+#define ET_ENTRY_SE 4
125+#define ET_ENTRY_EX 5
126+
127+struct boot_catalog_entry {
128+ char entry_type;
129+ union {
130+ boot_catalog_validation_entry VE;
131+ boot_catalog_initial_entry IE;
132+ boot_catalog_section_header SH;
133+ boot_catalog_section_entry SE;
134+ boot_catalog_section_entry_extension EX;
135+ } entry_data;
136+
137+ LIST_ENTRY(boot_catalog_entry) ll_struct;
138+};
139+
140+/* Temporary structure */
141+struct cd9660_boot_image {
142+ char *filename;
143+ int size;
144+ int sector; /* copied to LoadRBA */
145+ int num_sectors;
146+ unsigned int loadSegment;
147+ u_char targetMode;
148+ u_char system;
149+ u_char bootable;
150+ u_char platform_id; /* for section header entry */
151+ /*
152+ * If the boot image exists in the filesystem
153+ * already, this is a pointer to that node. For the sake
154+ * of simplicity in future versions, this pointer is only
155+ * to the node in the primary volume. This SHOULD be done
156+ * via a hashtable lookup.
157+ */
158+ struct _cd9660node *boot_image_node;
159+ TAILQ_ENTRY(cd9660_boot_image) image_list;
160+ int serialno;
161+};
162+
163+
164+#endif /* _CD9660_ELTORITO_H_ */
165+
+127,
-0
1@@ -0,0 +1,127 @@
2+/* $NetBSD: cd9660_strings.c,v 1.6 2015/12/24 15:52:37 christos Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+
36+#if HAVE_NBTOOL_CONFIG_H
37+#include "nbtool_config.h"
38+#else
39+#include <sys/mount.h>
40+#endif
41+
42+#include <sys/cdefs.h>
43+#include <sys/param.h>
44+#include <ctype.h>
45+
46+#include "makefs.h"
47+#include "cd9660.h"
48+
49+#if defined(__RCSID) && !defined(__lint)
50+__RCSID("$NetBSD: cd9660_strings.c,v 1.6 2015/12/24 15:52:37 christos Exp $");
51+#endif /* !__lint */
52+
53+
54+void
55+cd9660_uppercase_characters(char *str, size_t len)
56+{
57+ size_t p;
58+
59+ for (p = 0; p < len; p++) {
60+ if (islower((unsigned char)str[p]) )
61+ str[p] -= 32;
62+ }
63+}
64+
65+static inline int
66+cd9660_is_d_char(char c)
67+{
68+ return (isupper((unsigned char)c)
69+ || c == '_'
70+ || (c >= '0' && c <= '9'));
71+}
72+
73+static inline int
74+cd9660_is_a_char(char c)
75+{
76+ return (isupper((unsigned char)c)
77+ || c == '_'
78+ || (c >= '%' && c <= '?')
79+ || (c >= ' ' && c <= '\"'));
80+}
81+
82+/*
83+ * Test a string to see if it is composed of valid a characters
84+ * @param const char* The string to test
85+ * @returns int 1 if valid, 2 if valid if characters are converted to
86+ * upper case, 0 otherwise
87+ */
88+int
89+cd9660_valid_a_chars(const char *str)
90+{
91+ const char *c = str;
92+ int upperFound = 0;
93+
94+ while ((*c) != '\0') {
95+ if (!(cd9660_is_a_char(*c))) {
96+ if (islower((unsigned char)*c) )
97+ upperFound = 1;
98+ else
99+ return 0;
100+ }
101+ c++;
102+ }
103+ return upperFound + 1;
104+}
105+
106+/*
107+ * Test a string to see if it is composed of valid d characters
108+ * @param const char* The string to test
109+ * @returns int 1 if valid, 2 if valid if characters are converted to
110+ * upper case, 0 otherwise
111+ */
112+int
113+cd9660_valid_d_chars(const char *str)
114+{
115+ const char *c=str;
116+ int upperFound = 0;
117+
118+ while ((*c) != '\0') {
119+ if (!(cd9660_is_d_char(*c))) {
120+ if (islower((unsigned char)*c) )
121+ upperFound = 1;
122+ else
123+ return 0;
124+ }
125+ c++;
126+ }
127+ return upperFound + 1;
128+}
+509,
-0
1@@ -0,0 +1,509 @@
2+/* $NetBSD: cd9660_write.c,v 1.18 2023/12/28 12:13:56 tsutsui Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+
36+#include "cd9660.h"
37+#include "iso9660_rrip.h"
38+
39+#include <sys/cdefs.h>
40+#if defined(__RCSID) && !defined(__lint)
41+__RCSID("$NetBSD: cd9660_write.c,v 1.18 2023/12/28 12:13:56 tsutsui Exp $");
42+#endif /* !__lint */
43+
44+#include <util.h>
45+
46+static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *);
47+static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int);
48+static int cd9660_write_path_tables(iso9660_disk *, FILE *);
49+static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *);
50+static int cd9660_write_filedata(iso9660_disk *, FILE *, off_t,
51+ const unsigned char *, int);
52+#if 0
53+static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
54+#endif
55+static void cd9660_write_rr(iso9660_disk *, FILE *, cd9660node *, off_t, off_t);
56+
57+/*
58+ * Write the image
59+ * Writes the entire image
60+ * @param const char* The filename for the image
61+ * @returns int 1 on success, 0 on failure
62+ */
63+int
64+cd9660_write_image(iso9660_disk *diskStructure, const char* image)
65+{
66+ FILE *fd;
67+ int status;
68+ char buf[CD9660_SECTOR_SIZE];
69+
70+ if ((fd = fopen(image, "w+")) == NULL) {
71+ err(EXIT_FAILURE, "%s: Can't open `%s' for writing", __func__,
72+ image);
73+ }
74+
75+ if (diskStructure->verbose_level > 0)
76+ printf("Writing image\n");
77+
78+ if (diskStructure->has_generic_bootimage) {
79+ status = cd9660_copy_file(diskStructure, fd, 0,
80+ diskStructure->generic_bootimage);
81+ if (status == 0) {
82+ warnx("%s: Error writing generic boot image",
83+ __func__);
84+ goto cleanup_bad_image;
85+ }
86+ }
87+
88+ /* Write the volume descriptors */
89+ status = cd9660_write_volume_descriptors(diskStructure, fd);
90+ if (status == 0) {
91+ warnx("%s: Error writing volume descriptors to image",
92+ __func__);
93+ goto cleanup_bad_image;
94+ }
95+
96+ if (diskStructure->verbose_level > 0)
97+ printf("Volume descriptors written\n");
98+
99+ /*
100+ * Write the path tables: there are actually four, but right
101+ * now we are only concearned with two.
102+ */
103+ status = cd9660_write_path_tables(diskStructure, fd);
104+ if (status == 0) {
105+ warnx("%s: Error writing path tables to image", __func__);
106+ goto cleanup_bad_image;
107+ }
108+
109+ if (diskStructure->verbose_level > 0)
110+ printf("Path tables written\n");
111+
112+ /* Write the directories and files */
113+ status = cd9660_write_file(diskStructure, fd, diskStructure->rootNode);
114+ if (status == 0) {
115+ warnx("%s: Error writing files to image", __func__);
116+ goto cleanup_bad_image;
117+ }
118+
119+ if (diskStructure->is_bootable) {
120+ cd9660_write_boot(diskStructure, fd);
121+ }
122+
123+ /* Write padding bits. This is temporary */
124+ memset(buf, 0, CD9660_SECTOR_SIZE);
125+ cd9660_write_filedata(diskStructure, fd,
126+ diskStructure->totalSectors - 1, buf, 1);
127+
128+ if (diskStructure->verbose_level > 0)
129+ printf("Files written\n");
130+ fclose(fd);
131+
132+ if (diskStructure->verbose_level > 0)
133+ printf("Image closed\n");
134+ return 1;
135+
136+cleanup_bad_image:
137+ fclose(fd);
138+ if (!diskStructure->keep_bad_images)
139+ unlink(image);
140+ if (diskStructure->verbose_level > 0)
141+ printf("Bad image cleaned up\n");
142+ return 0;
143+}
144+
145+static int
146+cd9660_write_volume_descriptors(iso9660_disk *diskStructure, FILE *fd)
147+{
148+ volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor;
149+ while (vd_temp != NULL) {
150+ cd9660_write_filedata(diskStructure, fd, vd_temp->sector,
151+ vd_temp->volumeDescriptorData, 1);
152+ vd_temp = vd_temp->next;
153+ }
154+ return 1;
155+}
156+
157+/*
158+ * Write out an individual path table
159+ * Used just to keep redundant code to a minimum
160+ * @param FILE *fd Valid file pointer
161+ * @param int Sector to start writing path table to
162+ * @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
163+ * @returns int 1 on success, 0 on failure
164+ */
165+static int
166+cd9660_write_path_table(iso9660_disk *diskStructure, FILE *fd, off_t sector,
167+ int mode)
168+{
169+ int path_table_sectors = CD9660_BLOCKS(diskStructure->sectorSize,
170+ diskStructure->pathTableLength);
171+ unsigned char *buffer;
172+ unsigned char *buffer_head;
173+ int len;
174+ path_table_entry temp_entry;
175+ cd9660node *ptcur;
176+
177+ buffer = ecalloc(path_table_sectors, diskStructure->sectorSize);
178+ buffer_head = buffer;
179+
180+ ptcur = diskStructure->rootNode;
181+
182+ while (ptcur != NULL) {
183+ memset(&temp_entry, 0, sizeof(path_table_entry));
184+ temp_entry.length[0] = ptcur->isoDirRecord->name_len[0];
185+ temp_entry.extended_attribute_length[0] =
186+ ptcur->isoDirRecord->ext_attr_length[0];
187+ memcpy(temp_entry.name, ptcur->isoDirRecord->name,
188+ temp_entry.length[0] + 1);
189+
190+ /* round up */
191+ len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01);
192+
193+ /* todo: function pointers instead */
194+ if (mode == LITTLE_ENDIAN) {
195+ cd9660_731(ptcur->fileDataSector,
196+ temp_entry.first_sector);
197+ cd9660_721((ptcur->parent == NULL ?
198+ 1 : ptcur->parent->ptnumber),
199+ temp_entry.parent_number);
200+ } else {
201+ cd9660_732(ptcur->fileDataSector,
202+ temp_entry.first_sector);
203+ cd9660_722((ptcur->parent == NULL ?
204+ 1 : ptcur->parent->ptnumber),
205+ temp_entry.parent_number);
206+ }
207+
208+
209+ memcpy(buffer, &temp_entry, len);
210+ buffer += len;
211+
212+ ptcur = ptcur->ptnext;
213+ }
214+
215+ return cd9660_write_filedata(diskStructure, fd, sector, buffer_head,
216+ path_table_sectors);
217+}
218+
219+
220+/*
221+ * Write out the path tables to disk
222+ * Each file descriptor should be pointed to by the PVD, so we know which
223+ * sector to copy them to. One thing to watch out for: the only path tables
224+ * stored are in the endian mode that the application is compiled for. So,
225+ * the first thing to do is write out that path table, then to write the one
226+ * in the other endian mode requires to convert the endianness of each entry
227+ * in the table. The best way to do this would be to create a temporary
228+ * path_table_entry structure, then for each path table entry, copy it to
229+ * the temporary entry, translate, then copy that to disk.
230+ *
231+ * @param FILE* Valid file descriptor
232+ * @returns int 0 on failure, 1 on success
233+ */
234+static int
235+cd9660_write_path_tables(iso9660_disk *diskStructure, FILE *fd)
236+{
237+ if (cd9660_write_path_table(diskStructure, fd,
238+ diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0)
239+ return 0;
240+
241+ if (cd9660_write_path_table(diskStructure, fd,
242+ diskStructure->primaryBigEndianTableSector, BIG_ENDIAN) == 0)
243+ return 0;
244+
245+ /* @TODO: handle remaining two path tables */
246+ return 1;
247+}
248+
249+/*
250+ * Write a file to disk
251+ * Writes a file, its directory record, and its data to disk
252+ * This file is designed to be called RECURSIVELY, so initially call it
253+ * with the root node. All of the records should store what sector the
254+ * file goes in, so no computation should be necessary.
255+ *
256+ * @param int fd Valid file descriptor
257+ * @param struct cd9660node* writenode Pointer to the file to be written
258+ * @returns int 0 on failure, 1 on success
259+ */
260+static int
261+cd9660_write_file(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode)
262+{
263+ char *buf;
264+ char *temp_file_name;
265+ int ret;
266+ off_t working_sector;
267+ int cur_sector_offset;
268+ iso_directory_record_cd9660 temp_record;
269+ cd9660node *temp;
270+ int rv = 0;
271+
272+ /* Todo : clean up variables */
273+
274+ temp_file_name = ecalloc(CD9660MAXPATH + 1, 1);
275+ buf = emalloc(diskStructure->sectorSize);
276+ if ((writenode->level != 0) &&
277+ !(writenode->node->type & S_IFDIR)) {
278+ fsinode *inode = writenode->node->inode;
279+ /* Only attempt to write unwritten files that have length. */
280+ if ((inode->flags & FI_WRITTEN) != 0) {
281+ INODE_WARNX(("%s: skipping written inode %d", __func__,
282+ (int)inode->st.st_ino));
283+ } else if (writenode->fileDataLength > 0) {
284+ INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
285+ __func__, (int)inode->st.st_ino, inode->ino));
286+ inode->flags |= FI_WRITTEN;
287+ cd9660_compute_full_filename(writenode,
288+ temp_file_name);
289+ ret = cd9660_copy_file(diskStructure, fd,
290+ writenode->fileDataSector, temp_file_name);
291+ if (ret == 0)
292+ goto out;
293+ }
294+ } else {
295+ /*
296+ * Here is a new revelation that ECMA didnt explain
297+ * (at least not well).
298+ * ALL . and .. records store the name "\0" and "\1"
299+ * resepctively. So, for each directory, we have to
300+ * make a new node.
301+ *
302+ * This is where it gets kinda messy, since we have to
303+ * be careful of sector boundaries
304+ */
305+ cur_sector_offset = 0;
306+ working_sector = writenode->fileDataSector;
307+ if (fseeko(fd, working_sector * diskStructure->sectorSize,
308+ SEEK_SET) == -1)
309+ err(EXIT_FAILURE, "fseeko");
310+
311+ /*
312+ * Now loop over children, writing out their directory
313+ * records - beware of sector boundaries
314+ */
315+ TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
316+ /*
317+ * Copy the temporary record and adjust its size
318+ * if necessary
319+ */
320+ memcpy(&temp_record, temp->isoDirRecord,
321+ sizeof(iso_directory_record_cd9660));
322+
323+ temp_record.length[0] =
324+ cd9660_compute_record_size(diskStructure, temp);
325+
326+ if (temp_record.length[0] + cur_sector_offset >=
327+ diskStructure->sectorSize) {
328+ cur_sector_offset = 0;
329+ working_sector++;
330+
331+ /* Seek to the next sector. */
332+ if (fseeko(fd, working_sector *
333+ diskStructure->sectorSize, SEEK_SET) == -1)
334+ err(EXIT_FAILURE, "fseeko");
335+ }
336+ /* Write out the basic ISO directory record */
337+ (void)fwrite(&temp_record, 1,
338+ temp->isoDirRecord->length[0], fd);
339+ if (diskStructure->rock_ridge_enabled) {
340+ cd9660_write_rr(diskStructure, fd, temp,
341+ cur_sector_offset, working_sector);
342+ }
343+ if (fseeko(fd, working_sector *
344+ diskStructure->sectorSize + cur_sector_offset +
345+ temp_record.length[0] - temp->su_tail_size,
346+ SEEK_SET) == -1)
347+ err(EXIT_FAILURE, "fseeko");
348+ if (temp->su_tail_size > 0)
349+ fwrite(temp->su_tail_data, 1,
350+ temp->su_tail_size, fd);
351+ if (ferror(fd)) {
352+ warnx("%s: write error", __func__);
353+ goto out;
354+ }
355+ cur_sector_offset += temp_record.length[0];
356+
357+ }
358+
359+ /*
360+ * Recurse on children.
361+ */
362+ TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
363+ if ((ret = cd9660_write_file(diskStructure, fd, temp))
364+ == 0)
365+ goto out;
366+ }
367+ }
368+ rv = 1;
369+out:
370+ free(temp_file_name);
371+ free(buf);
372+ return rv;
373+}
374+
375+/*
376+ * Wrapper function to write a buffer (one sector) to disk.
377+ * Seeks and writes the buffer.
378+ * NOTE: You dont NEED to use this function, but it might make your
379+ * life easier if you have to write things that align to a sector
380+ * (such as volume descriptors).
381+ *
382+ * @param int fd Valid file descriptor
383+ * @param int sector Sector number to write to
384+ * @param const unsigned char* Buffer to write. This should be the
385+ * size of a sector, and if only a portion
386+ * is written, the rest should be set to 0.
387+ */
388+static int
389+cd9660_write_filedata(iso9660_disk *diskStructure, FILE *fd, off_t sector,
390+ const unsigned char *buf, int numsecs)
391+{
392+ off_t curpos;
393+ size_t success;
394+
395+ curpos = ftello(fd);
396+
397+ if (fseeko(fd, sector * diskStructure->sectorSize, SEEK_SET) == -1)
398+ err(EXIT_FAILURE, "fseeko");
399+
400+ success = fwrite(buf, diskStructure->sectorSize * numsecs, 1, fd);
401+
402+ if (fseeko(fd, curpos, SEEK_SET) == -1)
403+ err(EXIT_FAILURE, "fseeko");
404+
405+ if (success == 1)
406+ success = diskStructure->sectorSize * numsecs;
407+ return success;
408+}
409+
410+#if 0
411+static int
412+cd9660_write_buffered(FILE *fd, off_t offset, int buff_len,
413+ const unsigned char* buffer)
414+{
415+ static int working_sector = -1;
416+ static char buf[CD9660_SECTOR_SIZE];
417+
418+ return 0;
419+}
420+#endif
421+
422+int
423+cd9660_copy_file(iso9660_disk *diskStructure, FILE *fd, off_t start_sector,
424+ const char *filename)
425+{
426+ FILE *rf;
427+ int bytes_read;
428+ off_t sector = start_sector;
429+ int buf_size = diskStructure->sectorSize;
430+ char *buf;
431+
432+ buf = emalloc(buf_size);
433+ if ((rf = fopen(filename, "rb")) == NULL) {
434+ warn("%s: cannot open %s", __func__, filename);
435+ free(buf);
436+ return 0;
437+ }
438+
439+ if (diskStructure->verbose_level > 1)
440+ printf("Writing file: %s\n",filename);
441+
442+ if (fseeko(fd, start_sector * diskStructure->sectorSize, SEEK_SET) == -1)
443+ err(EXIT_FAILURE, "fseeko");
444+
445+ while (!feof(rf)) {
446+ bytes_read = fread(buf,1,buf_size,rf);
447+ if (ferror(rf)) {
448+ warn("%s: fread", __func__);
449+ free(buf);
450+ (void)fclose(rf);
451+ return 0;
452+ }
453+
454+ fwrite(buf,1,bytes_read,fd);
455+ if (ferror(fd)) {
456+ warn("%s: fwrite", __func__);
457+ free(buf);
458+ (void)fclose(rf);
459+ return 0;
460+ }
461+ sector++;
462+ }
463+
464+ fclose(rf);
465+ free(buf);
466+ return 1;
467+}
468+
469+static void
470+cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode,
471+ off_t offset, off_t sector)
472+{
473+ int in_ca = 0;
474+ struct ISO_SUSP_ATTRIBUTES *myattr;
475+
476+ offset += writenode->isoDirRecord->length[0];
477+ if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) ==
478+ -1)
479+ err(EXIT_FAILURE, "fseeko");
480+ /* Offset now points at the end of the record */
481+ TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
482+ fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
483+
484+ if (!in_ca) {
485+ offset += CD9660_SUSP_ENTRY_SIZE(myattr);
486+ if (myattr->last_in_suf) {
487+ /*
488+ * Point the offset to the start of this
489+ * record's CE area
490+ */
491+ if (fseeko(fd, ((off_t)diskStructure->
492+ susp_continuation_area_start_sector *
493+ diskStructure->sectorSize)
494+ + writenode->susp_entry_ce_start,
495+ SEEK_SET) == -1)
496+ err(EXIT_FAILURE, "fseeko");
497+ in_ca = 1;
498+ }
499+ }
500+ }
501+
502+ /*
503+ * If we had to go to the continuation area, head back to
504+ * where we should be.
505+ */
506+ if (in_ca)
507+ if (fseeko(fd, sector * diskStructure->sectorSize + offset,
508+ SEEK_SET) == -1)
509+ err(EXIT_FAILURE, "fseeko");
510+}
+827,
-0
1@@ -0,0 +1,827 @@
2+/* $NetBSD: iso9660_rrip.c,v 1.17 2025/02/17 22:56:46 andvar Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+/* This will hold all the function definitions
36+ * defined in iso9660_rrip.h
37+ */
38+
39+#include "makefs.h"
40+#include "cd9660.h"
41+#include "iso9660_rrip.h"
42+#include <sys/queue.h>
43+#include <stdio.h>
44+#include <util.h>
45+
46+#include <sys/cdefs.h>
47+#if defined(__RCSID) && !defined(__lint)
48+__RCSID("$NetBSD: iso9660_rrip.c,v 1.17 2025/02/17 22:56:46 andvar Exp $");
49+#endif /* !__lint */
50+
51+static void cd9660_rrip_initialize_inode(cd9660node *);
52+static int cd9660_susp_handle_continuation(iso9660_disk *, cd9660node *);
53+static int cd9660_susp_handle_continuation_common(iso9660_disk *, cd9660node *,
54+ int);
55+
56+int
57+cd9660_susp_initialize(iso9660_disk *diskStructure, cd9660node *node,
58+ cd9660node *parent, cd9660node *grandparent)
59+{
60+ cd9660node *cn;
61+ int r;
62+
63+ /* Make sure the node is not NULL. If it is, there are major problems */
64+ assert(node != NULL);
65+
66+ if (!(node->type & CD9660_TYPE_DOT) &&
67+ !(node->type & CD9660_TYPE_DOTDOT))
68+ TAILQ_INIT(&(node->head));
69+ if (node->dot_record != 0)
70+ TAILQ_INIT(&(node->dot_record->head));
71+ if (node->dot_dot_record != 0)
72+ TAILQ_INIT(&(node->dot_dot_record->head));
73+
74+ /* SUSP specific entries here */
75+ if ((r = cd9660_susp_initialize_node(diskStructure, node)) < 0)
76+ return r;
77+
78+ /* currently called cd9660node_rrip_init_links */
79+ r = cd9660_rrip_initialize_node(diskStructure, node, parent, grandparent);
80+ if (r < 0)
81+ return r;
82+
83+ /*
84+ * See if we need a CE record, and set all of the
85+ * associated counters.
86+ *
87+ * This should be called after all extensions. After
88+ * this is called, no new records should be added.
89+ */
90+ if ((r = cd9660_susp_handle_continuation(diskStructure, node)) < 0)
91+ return r;
92+
93+ /* Recurse on children. */
94+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
95+ if ((r = cd9660_susp_initialize(diskStructure, cn, node, parent)) < 0)
96+ return 0;
97+ }
98+ return 1;
99+}
100+
101+int
102+cd9660_susp_finalize(iso9660_disk *diskStructure, cd9660node *node)
103+{
104+ cd9660node *temp;
105+ int r;
106+
107+ assert(node != NULL);
108+
109+ if (node == diskStructure->rootNode)
110+ diskStructure->susp_continuation_area_current_free = 0;
111+
112+ if ((r = cd9660_susp_finalize_node(diskStructure, node)) < 0)
113+ return r;
114+ if ((r = cd9660_rrip_finalize_node(diskStructure, node)) < 0)
115+ return r;
116+
117+ TAILQ_FOREACH(temp, &node->cn_children, cn_next_child) {
118+ if ((r = cd9660_susp_finalize(diskStructure, temp)) < 0)
119+ return r;
120+ }
121+ return 1;
122+}
123+
124+/*
125+ * If we really wanted to speed things up, we could have some sort of
126+ * lookup table on the SUSP entry type that calls a functor. Or, we could
127+ * combine the functions. These functions are kept separate to allow
128+ * easier addition of other extensions.
129+
130+ * For the sake of simplicity and clarity, we won't be doing that for now.
131+ */
132+
133+/*
134+ * SUSP needs to update the following types:
135+ * CE (continuation area)
136+ */
137+int
138+cd9660_susp_finalize_node(iso9660_disk *diskStructure, cd9660node *node)
139+{
140+ struct ISO_SUSP_ATTRIBUTES *t;
141+
142+ /* Handle CE counters */
143+ if (node->susp_entry_ce_length > 0) {
144+ node->susp_entry_ce_start =
145+ diskStructure->susp_continuation_area_current_free;
146+ diskStructure->susp_continuation_area_current_free +=
147+ node->susp_entry_ce_length;
148+ }
149+
150+ TAILQ_FOREACH(t, &node->head, rr_ll) {
151+ if (t->susp_type != SUSP_TYPE_SUSP ||
152+ t->entry_type != SUSP_ENTRY_SUSP_CE)
153+ continue;
154+ cd9660_bothendian_dword(
155+ diskStructure->
156+ susp_continuation_area_start_sector,
157+ t->attr.su_entry.CE.ca_sector);
158+
159+ cd9660_bothendian_dword(
160+ diskStructure->
161+ susp_continuation_area_start_sector,
162+ t->attr.su_entry.CE.ca_sector);
163+ cd9660_bothendian_dword(node->susp_entry_ce_start,
164+ t->attr.su_entry.CE.offset);
165+ cd9660_bothendian_dword(node->susp_entry_ce_length,
166+ t->attr.su_entry.CE.length);
167+ }
168+ return 0;
169+}
170+
171+int
172+cd9660_rrip_finalize_node(iso9660_disk *diskStructure NETCOMPAT_UNUSED,
173+ cd9660node *node)
174+{
175+ struct ISO_SUSP_ATTRIBUTES *t;
176+
177+ TAILQ_FOREACH(t, &node->head, rr_ll) {
178+ if (t->susp_type != SUSP_TYPE_RRIP)
179+ continue;
180+ switch (t->entry_type) {
181+ case SUSP_ENTRY_RRIP_CL:
182+ /* Look at rr_relocated*/
183+ if (node->rr_relocated == NULL)
184+ return -1;
185+ cd9660_bothendian_dword(
186+ node->rr_relocated->fileDataSector,
187+ (unsigned char *)
188+ t->attr.rr_entry.CL.dir_loc);
189+ break;
190+ case SUSP_ENTRY_RRIP_PL:
191+ /* Look at rr_real_parent */
192+ if (node->parent == NULL ||
193+ node->parent->rr_real_parent == NULL)
194+ return -1;
195+ cd9660_bothendian_dword(
196+ node->parent->rr_real_parent->fileDataSector,
197+ (unsigned char *)
198+ t->attr.rr_entry.PL.dir_loc);
199+ break;
200+ }
201+ }
202+ return 0;
203+}
204+
205+static int
206+cd9660_susp_handle_continuation_common(iso9660_disk *diskStructure,
207+ cd9660node *node, int space)
208+{
209+ int ca_used, susp_used, susp_used_pre_ce, working;
210+ struct ISO_SUSP_ATTRIBUTES *temp, *pre_ce, *last, *CE, *ST;
211+
212+ pre_ce = last = NULL;
213+ working = 254 - space;
214+ if (node->su_tail_size > 0)
215+ /* Allow 4 bytes for "ST" record. */
216+ working -= node->su_tail_size + 4;
217+ /* printf("There are %i bytes to work with\n",working); */
218+
219+ susp_used_pre_ce = susp_used = 0;
220+ ca_used = 0;
221+ TAILQ_FOREACH(temp, &node->head, rr_ll) {
222+ if (working < 0)
223+ break;
224+ /*
225+ * printf("SUSP Entry found, length is %i\n",
226+ * CD9660_SUSP_ENTRY_SIZE(temp));
227+ */
228+ working -= CD9660_SUSP_ENTRY_SIZE(temp);
229+ if (working >= 0) {
230+ last = temp;
231+ susp_used += CD9660_SUSP_ENTRY_SIZE(temp);
232+ }
233+ if (working >= 28) {
234+ /*
235+ * Remember the last entry after which we
236+ * could insert a "CE" entry.
237+ */
238+ pre_ce = last;
239+ susp_used_pre_ce = susp_used;
240+ }
241+ }
242+
243+ /* A CE entry is needed */
244+ if (working <= 0) {
245+ CE = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
246+ SUSP_ENTRY_SUSP_CE, "CE", SUSP_LOC_ENTRY);
247+ cd9660_susp_ce(CE, node);
248+ /* This will automatically insert at the appropriate location */
249+ if (pre_ce != NULL)
250+ TAILQ_INSERT_AFTER(&node->head, pre_ce, CE, rr_ll);
251+ else
252+ TAILQ_INSERT_HEAD(&node->head, CE, rr_ll);
253+ last = CE;
254+ susp_used = susp_used_pre_ce + 28;
255+ /* Count how much CA data is necessary */
256+ for (temp = TAILQ_NEXT(last, rr_ll); temp != NULL;
257+ temp = TAILQ_NEXT(temp, rr_ll)) {
258+ ca_used += CD9660_SUSP_ENTRY_SIZE(temp);
259+ }
260+ }
261+
262+ /* An ST entry is needed */
263+ if (node->su_tail_size > 0) {
264+ ST = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
265+ SUSP_ENTRY_SUSP_ST, "ST", SUSP_LOC_ENTRY);
266+ cd9660_susp_st(ST, node);
267+ if (last != NULL)
268+ TAILQ_INSERT_AFTER(&node->head, last, ST, rr_ll);
269+ else
270+ TAILQ_INSERT_HEAD(&node->head, ST, rr_ll);
271+ last = ST;
272+ susp_used += 4;
273+ }
274+ if (last != NULL)
275+ last->last_in_suf = 1;
276+
277+ node->susp_entry_size = susp_used;
278+ node->susp_entry_ce_length = ca_used;
279+
280+ diskStructure->susp_continuation_area_size += ca_used;
281+ return 1;
282+}
283+
284+/* See if a continuation entry is needed for each of the different types */
285+static int
286+cd9660_susp_handle_continuation(iso9660_disk *diskStructure, cd9660node *node)
287+{
288+ assert (node != NULL);
289+
290+ /* Entry */
291+ if (cd9660_susp_handle_continuation_common(diskStructure,
292+ node,(int)(node->isoDirRecord->length[0])) < 0)
293+ return 0;
294+
295+ return 1;
296+}
297+
298+int
299+cd9660_susp_initialize_node(iso9660_disk *diskStructure, cd9660node *node)
300+{
301+ struct ISO_SUSP_ATTRIBUTES *temp;
302+
303+ /*
304+ * Requirements/notes:
305+ * CE: is added for us where needed
306+ * ST: not sure if it is even required, but if so, should be
307+ * handled by the CE code
308+ * PD: isnt needed (though might be added for testing)
309+ * SP: is stored ONLY on the . record of the root directory
310+ * ES: not sure
311+ */
312+
313+ /* Check for root directory, add SP and ER if needed. */
314+ if (node->type & CD9660_TYPE_DOT) {
315+ if (node->parent == diskStructure->rootNode) {
316+ temp = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
317+ SUSP_ENTRY_SUSP_SP, "SP", SUSP_LOC_DOT);
318+ cd9660_susp_sp(temp, node);
319+
320+ /* Should be first entry. */
321+ TAILQ_INSERT_HEAD(&node->head, temp, rr_ll);
322+ }
323+ }
324+ return 1;
325+}
326+
327+static void
328+cd9660_rrip_initialize_inode(cd9660node *node)
329+{
330+ struct ISO_SUSP_ATTRIBUTES *attr;
331+
332+ /*
333+ * Inode dependent values - this may change,
334+ * but for now virtual files and directories do
335+ * not have an inode structure
336+ */
337+
338+ if ((node->node != NULL) && (node->node->inode != NULL)) {
339+ /* PX - POSIX attributes */
340+ attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
341+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
342+ cd9660node_rrip_px(attr, node->node);
343+
344+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
345+
346+ /* TF - timestamp */
347+ attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
348+ SUSP_ENTRY_RRIP_TF, "TF", SUSP_LOC_ENTRY);
349+ cd9660node_rrip_tf(attr, node->node);
350+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
351+
352+ /* SL - Symbolic link */
353+ /* ?????????? Dan - why is this here? */
354+ if (TAILQ_EMPTY(&node->cn_children) &&
355+ node->node->inode != NULL &&
356+ S_ISLNK(node->node->inode->st.st_mode))
357+ cd9660_createSL(node);
358+
359+ /* PN - device number */
360+ if (node->node->inode != NULL &&
361+ ((S_ISCHR(node->node->inode->st.st_mode) ||
362+ S_ISBLK(node->node->inode->st.st_mode)))) {
363+ attr =
364+ cd9660node_susp_create_node(SUSP_TYPE_RRIP,
365+ SUSP_ENTRY_RRIP_PN, "PN",
366+ SUSP_LOC_ENTRY);
367+ cd9660node_rrip_pn(attr, node->node);
368+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
369+ }
370+ }
371+}
372+
373+int
374+cd9660_rrip_initialize_node(iso9660_disk *diskStructure, cd9660node *node,
375+ cd9660node *parent, cd9660node *grandparent)
376+{
377+ struct ISO_SUSP_ATTRIBUTES *current = NULL;
378+
379+ assert(node != NULL);
380+
381+ if (node->type & CD9660_TYPE_DOT) {
382+ /*
383+ * Handle ER - should be the only entry to appear on
384+ * a "." record
385+ */
386+ if (node->parent == diskStructure->rootNode) {
387+ cd9660_susp_ER(node, 1, SUSP_RRIP_ER_EXT_ID,
388+ SUSP_RRIP_ER_EXT_DES, SUSP_RRIP_ER_EXT_SRC);
389+ }
390+ if (parent != NULL && parent->node != NULL &&
391+ parent->node->inode != NULL) {
392+ /* PX - POSIX attributes */
393+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
394+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
395+ cd9660node_rrip_px(current, parent->node);
396+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
397+ }
398+ } else if (node->type & CD9660_TYPE_DOTDOT) {
399+ if (grandparent != NULL && grandparent->node != NULL &&
400+ grandparent->node->inode != NULL) {
401+ /* PX - POSIX attributes */
402+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
403+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
404+ cd9660node_rrip_px(current, grandparent->node);
405+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
406+ }
407+ /* Handle PL */
408+ if (parent != NULL && parent->rr_real_parent != NULL) {
409+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
410+ SUSP_ENTRY_RRIP_PL, "PL", SUSP_LOC_DOTDOT);
411+ cd9660_rrip_PL(current,node);
412+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
413+ }
414+ } else {
415+ cd9660_rrip_initialize_inode(node);
416+
417+ if (node == diskStructure->rr_moved_dir) {
418+ cd9660_rrip_add_NM(node, RRIP_DEFAULT_MOVE_DIR_NAME);
419+ } else if (node->node != NULL) {
420+ cd9660_rrip_NM(node);
421+ }
422+
423+ /* Rock ridge directory relocation code here. */
424+
425+ /* First handle the CL for the placeholder file. */
426+ if (node->rr_relocated != NULL) {
427+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
428+ SUSP_ENTRY_RRIP_CL, "CL", SUSP_LOC_ENTRY);
429+ cd9660_rrip_CL(current, node);
430+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
431+ }
432+
433+ /* Handle RE*/
434+ if (node->rr_real_parent != NULL) {
435+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
436+ SUSP_ENTRY_RRIP_RE, "RE", SUSP_LOC_ENTRY);
437+ cd9660_rrip_RE(current,node);
438+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
439+ }
440+ }
441+ return 1;
442+}
443+
444+struct ISO_SUSP_ATTRIBUTES*
445+cd9660node_susp_create_node(int susp_type, int entry_type, const char *type_id,
446+ int write_loc)
447+{
448+ struct ISO_SUSP_ATTRIBUTES* temp;
449+
450+ temp = emalloc(sizeof(*temp));
451+ temp->susp_type = susp_type;
452+ temp->entry_type = entry_type;
453+ temp->last_in_suf = 0;
454+ /* Phase this out */
455+ temp->type_of[0] = type_id[0];
456+ temp->type_of[1] = type_id[1];
457+ temp->write_location = write_loc;
458+
459+ /*
460+ * Since the first four bytes is common, lets go ahead and
461+ * set the type identifier, since we are passing that to this
462+ * function anyhow.
463+ */
464+ temp->attr.su_entry.SP.h.type[0] = type_id[0];
465+ temp->attr.su_entry.SP.h.type[1] = type_id[1];
466+ return temp;
467+}
468+
469+int
470+cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES* p, cd9660node *node NETCOMPAT_UNUSED)
471+{
472+ p->attr.rr_entry.PL.h.length[0] = 12;
473+ p->attr.rr_entry.PL.h.version[0] = 1;
474+ return 1;
475+}
476+
477+int
478+cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node NETCOMPAT_UNUSED)
479+{
480+ p->attr.rr_entry.CL.h.length[0] = 12;
481+ p->attr.rr_entry.CL.h.version[0] = 1;
482+ return 1;
483+}
484+
485+int
486+cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node NETCOMPAT_UNUSED)
487+{
488+ p->attr.rr_entry.RE.h.length[0] = 4;
489+ p->attr.rr_entry.RE.h.version[0] = 1;
490+ return 1;
491+}
492+
493+void
494+cd9660_createSL(cd9660node *node)
495+{
496+ struct ISO_SUSP_ATTRIBUTES* current;
497+ int path_count, dir_count, done, i, j, dir_copied;
498+ char temp_cr[255];
499+ char temp_sl[255]; /* used in copying continuation entry*/
500+ char* sl_ptr;
501+
502+ sl_ptr = node->node->symlink;
503+
504+ done = 0;
505+ path_count = 0;
506+ dir_count = 0;
507+ dir_copied = 0;
508+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
509+ SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
510+
511+ current->attr.rr_entry.SL.h.version[0] = 1;
512+ current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
513+
514+ if (*sl_ptr == '/') {
515+ temp_cr[0] = SL_FLAGS_ROOT;
516+ temp_cr[1] = 0;
517+ memcpy(current->attr.rr_entry.SL.component + path_count,
518+ temp_cr, 2);
519+ path_count += 2;
520+ sl_ptr++;
521+ }
522+
523+ for (i = 0; i < (dir_count + 2); i++)
524+ temp_cr[i] = '\0';
525+
526+ while (!done) {
527+ while ((*sl_ptr != '/') && (*sl_ptr != '\0')) {
528+ dir_copied = 1;
529+ if (*sl_ptr == '.') {
530+ if ((*(sl_ptr + 1) == '/') || (*(sl_ptr + 1)
531+ == '\0')) {
532+ temp_cr[0] = SL_FLAGS_CURRENT;
533+ sl_ptr++;
534+ } else if(*(sl_ptr + 1) == '.') {
535+ if ((*(sl_ptr + 2) == '/') ||
536+ (*(sl_ptr + 2) == '\0')) {
537+ temp_cr[0] = SL_FLAGS_PARENT;
538+ sl_ptr += 2;
539+ }
540+ } else {
541+ temp_cr[dir_count+2] = *sl_ptr;
542+ sl_ptr++;
543+ dir_count++;
544+ }
545+ } else {
546+ temp_cr[dir_count + 2] = *sl_ptr;
547+ sl_ptr++;
548+ dir_count++;
549+ }
550+ }
551+
552+ if ((path_count + dir_count) >= 249) {
553+ current->attr.rr_entry.SL.flags[0] |= SL_FLAGS_CONTINUE;
554+
555+ j = 0;
556+
557+ if (path_count <= 249) {
558+ while(j != (249 - path_count)) {
559+ temp_sl[j] = temp_cr[j];
560+ j++;
561+ }
562+ temp_sl[0] = SL_FLAGS_CONTINUE;
563+ temp_sl[1] = j - 2;
564+ memcpy(
565+ current->attr.rr_entry.SL.component +
566+ path_count,
567+ temp_sl, j);
568+ }
569+
570+ path_count += j;
571+ current->attr.rr_entry.SL.h.length[0] = path_count + 5;
572+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
573+ current= cd9660node_susp_create_node(SUSP_TYPE_RRIP,
574+ SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
575+ current->attr.rr_entry.SL.h.version[0] = 1;
576+ current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
577+
578+ path_count = 0;
579+
580+ if (dir_count > 2) {
581+ while (j != dir_count + 2) {
582+ current->attr.rr_entry.SL.component[
583+ path_count + 2] = temp_cr[j];
584+ j++;
585+ path_count++;
586+ }
587+ current->attr.rr_entry.SL.component[1]
588+ = path_count;
589+ path_count+= 2;
590+ } else {
591+ while(j != dir_count) {
592+ current->attr.rr_entry.SL.component[
593+ path_count+2] = temp_cr[j];
594+ j++;
595+ path_count++;
596+ }
597+ }
598+ } else {
599+ if (dir_copied == 1) {
600+ temp_cr[1] = dir_count;
601+ memcpy(current->attr.rr_entry.SL.component +
602+ path_count,
603+ temp_cr, dir_count + 2);
604+ path_count += dir_count + 2;
605+ }
606+ }
607+
608+ if (*sl_ptr == '\0') {
609+ done = 1;
610+ current->attr.rr_entry.SL.h.length[0] = path_count + 5;
611+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
612+ } else {
613+ sl_ptr++;
614+ dir_count = 0;
615+ dir_copied = 0;
616+ for(i = 0; i < 255; i++) {
617+ temp_cr[i] = '\0';
618+ }
619+ }
620+ }
621+}
622+
623+int
624+cd9660node_rrip_px(struct ISO_SUSP_ATTRIBUTES *v, fsnode *pxinfo)
625+{
626+ v->attr.rr_entry.PX.h.length[0] = 36;
627+ v->attr.rr_entry.PX.h.version[0] = 1;
628+ cd9660_bothendian_dword(pxinfo->inode->st.st_mode,
629+ v->attr.rr_entry.PX.mode);
630+ cd9660_bothendian_dword(pxinfo->inode->st.st_nlink,
631+ v->attr.rr_entry.PX.links);
632+ cd9660_bothendian_dword(pxinfo->inode->st.st_uid,
633+ v->attr.rr_entry.PX.uid);
634+ cd9660_bothendian_dword(pxinfo->inode->st.st_gid,
635+ v->attr.rr_entry.PX.gid);
636+
637+ /* Ignoring the serial number for now */
638+ return 1;
639+}
640+
641+int
642+cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *pn_field, fsnode *fnode)
643+{
644+ pn_field->attr.rr_entry.PN.h.length[0] = 20;
645+ pn_field->attr.rr_entry.PN.h.version[0] = 1;
646+
647+ if (sizeof (fnode->inode->st.st_rdev) > 4)
648+ cd9660_bothendian_dword(
649+ (uint64_t)fnode->inode->st.st_rdev >> 32,
650+ pn_field->attr.rr_entry.PN.high);
651+ else
652+ cd9660_bothendian_dword(0, pn_field->attr.rr_entry.PN.high);
653+
654+ cd9660_bothendian_dword(fnode->inode->st.st_rdev & 0xffffffff,
655+ pn_field->attr.rr_entry.PN.low);
656+ return 1;
657+}
658+
659+#if 0
660+int
661+cd9660node_rrip_nm(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *file_node)
662+{
663+ int nm_length = strlen(file_node->isoDirRecord->name) + 5;
664+ p->attr.rr_entry.NM.h.type[0] = 'N';
665+ p->attr.rr_entry.NM.h.type[1] = 'M';
666+ sprintf(p->attr.rr_entry.NM.altname, "%s", file_node->isoDirRecord->name);
667+ p->attr.rr_entry.NM.h.length[0] = (unsigned char)nm_length;
668+ p->attr.rr_entry.NM.h.version[0] = (unsigned char)1;
669+ p->attr.rr_entry.NM.flags[0] = (unsigned char) NM_PARENT;
670+ return 1;
671+}
672+#endif
673+
674+int
675+cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *p, fsnode *_node)
676+{
677+ p->attr.rr_entry.TF.flags[0] = TF_MODIFY | TF_ACCESS | TF_ATTRIBUTES;
678+ p->attr.rr_entry.TF.h.length[0] = 5;
679+ p->attr.rr_entry.TF.h.version[0] = 1;
680+
681+ /*
682+ * Need to add creation time, backup time,
683+ * expiration time, and effective time.
684+ */
685+
686+ cd9660_time_915(p->attr.rr_entry.TF.timestamp,
687+ _node->inode->st.st_mtime);
688+ p->attr.rr_entry.TF.h.length[0] += 7;
689+
690+ cd9660_time_915(p->attr.rr_entry.TF.timestamp + 7,
691+ _node->inode->st.st_atime);
692+ p->attr.rr_entry.TF.h.length[0] += 7;
693+
694+ cd9660_time_915(p->attr.rr_entry.TF.timestamp + 14,
695+ _node->inode->st.st_ctime);
696+ p->attr.rr_entry.TF.h.length[0] += 7;
697+ return 1;
698+}
699+
700+int
701+cd9660_susp_sp(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo NETCOMPAT_UNUSED)
702+{
703+ p->attr.su_entry.SP.h.length[0] = 7;
704+ p->attr.su_entry.SP.h.version[0] = 1;
705+ p->attr.su_entry.SP.check[0] = 0xBE;
706+ p->attr.su_entry.SP.check[1] = 0xEF;
707+ p->attr.su_entry.SP.len_skp[0] = 0;
708+ return 1;
709+}
710+
711+int
712+cd9660_susp_st(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *stinfo NETCOMPAT_UNUSED)
713+{
714+ p->attr.su_entry.ST.h.type[0] = 'S';
715+ p->attr.su_entry.ST.h.type[1] = 'T';
716+ p->attr.su_entry.ST.h.length[0] = 4;
717+ p->attr.su_entry.ST.h.version[0] = 1;
718+ return 1;
719+}
720+
721+int
722+cd9660_susp_ce(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo NETCOMPAT_UNUSED)
723+{
724+ p->attr.su_entry.CE.h.length[0] = 28;
725+ p->attr.su_entry.CE.h.version[0] = 1;
726+ /* Other attributes dont matter right now, will be updated later */
727+ return 1;
728+}
729+
730+int
731+cd9660_susp_pd(struct ISO_SUSP_ATTRIBUTES *p NETCOMPAT_UNUSED,
732+ int length NETCOMPAT_UNUSED)
733+{
734+ return 1;
735+}
736+
737+void
738+cd9660_rrip_add_NM(cd9660node *node, const char *name)
739+{
740+ int working,len;
741+ const char *p;
742+ struct ISO_SUSP_ATTRIBUTES *r;
743+
744+ /*
745+ * Each NM record has 254 bytes to work with. This means that
746+ * the name data itself only has 249 bytes to work with. So, a
747+ * name with 251 characters would require two nm records.
748+ */
749+ p = name;
750+ working = 1;
751+ while (working) {
752+ r = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
753+ SUSP_ENTRY_RRIP_NM, "NM", SUSP_LOC_ENTRY);
754+ r->attr.rr_entry.NM.h.version[0] = 1;
755+ r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_NONE;
756+ len = strlen(p);
757+
758+ if (len > 249) {
759+ len = 249;
760+ r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_CONTINUE;
761+ } else {
762+ working = 0;
763+ }
764+ memcpy(r->attr.rr_entry.NM.altname, p, len);
765+ r->attr.rr_entry.NM.h.length[0] = 5 + len;
766+
767+ TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
768+
769+ p += len;
770+ }
771+}
772+
773+void
774+cd9660_rrip_NM(cd9660node *node)
775+{
776+ cd9660_rrip_add_NM(node, node->node->name);
777+}
778+
779+struct ISO_SUSP_ATTRIBUTES*
780+cd9660_susp_ER(cd9660node *node,
781+ u_char ext_version, const char* ext_id, const char* ext_des,
782+ const char* ext_src)
783+{
784+ int l;
785+ struct ISO_SUSP_ATTRIBUTES *r;
786+
787+ r = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
788+ SUSP_ENTRY_SUSP_ER, "ER", SUSP_LOC_DOT);
789+
790+ /* Fixed data is 8 bytes */
791+ r->attr.su_entry.ER.h.length[0] = 8;
792+ r->attr.su_entry.ER.h.version[0] = 1;
793+
794+ r->attr.su_entry.ER.len_id[0] = (u_char)strlen(ext_id);
795+ r->attr.su_entry.ER.len_des[0] = (u_char)strlen(ext_des);
796+ r->attr.su_entry.ER.len_src[0] = (u_char)strlen(ext_src);
797+
798+ l = r->attr.su_entry.ER.len_id[0] +
799+ r->attr.su_entry.ER.len_src[0] +
800+ r->attr.su_entry.ER.len_des[0];
801+
802+ /* Everything must fit. */
803+ assert(l + r->attr.su_entry.ER.h.length[0] <= 254);
804+
805+ r->attr.su_entry.ER.h.length[0] += (u_char)l;
806+
807+
808+ r->attr.su_entry.ER.ext_ver[0] = ext_version;
809+ memcpy(r->attr.su_entry.ER.ext_data, ext_id,
810+ (int)r->attr.su_entry.ER.len_id[0]);
811+ l = (int) r->attr.su_entry.ER.len_id[0];
812+ memcpy(r->attr.su_entry.ER.ext_data + l,ext_des,
813+ (int)r->attr.su_entry.ER.len_des[0]);
814+
815+ l += (int)r->attr.su_entry.ER.len_des[0];
816+ memcpy(r->attr.su_entry.ER.ext_data + l,ext_src,
817+ (int)r->attr.su_entry.ER.len_src[0]);
818+
819+ TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
820+ return r;
821+}
822+
823+struct ISO_SUSP_ATTRIBUTES*
824+cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES *last NETCOMPAT_UNUSED,
825+ cd9660node *node NETCOMPAT_UNUSED)
826+{
827+ return NULL;
828+}
+292,
-0
1@@ -0,0 +1,292 @@
2+/* $NetBSD: iso9660_rrip.h,v 1.8 2023/04/18 22:58:14 christos Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
6+ * Perez-Rathke and Ram Vedam. All rights reserved.
7+ *
8+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
9+ * Alan Perez-Rathke and Ram Vedam.
10+ *
11+ * Redistribution and use in source and binary forms, with or
12+ * without modification, are permitted provided that the following
13+ * conditions are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above
17+ * copyright notice, this list of conditions and the following
18+ * disclaimer in the documentation and/or other materials provided
19+ * with the distribution.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
22+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
23+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
26+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
27+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33+ * OF SUCH DAMAGE.
34+ */
35+#ifndef __ISO9660_RRIP_H__
36+#define __ISO9660_RRIP_H__
37+
38+/*
39+ * This will hold all the functions needed to
40+ * write an ISO 9660 image with Rock Ridge Extensions
41+ */
42+
43+/* For writing must use ISO_RRIP_EXTREF structure */
44+
45+#include "makefs.h"
46+#include <cd9660_rrip.h>
47+#include "cd9660.h"
48+#include <sys/queue.h>
49+
50+#define PX_LENGTH 0x2C
51+#define PN_LENGTH 0x14
52+
53+#define TF_CREATION 0x01
54+#define TF_MODIFY 0x02
55+#define TF_ACCESS 0x04
56+#define TF_ATTRIBUTES 0x08
57+#define TF_BACKUP 0x10
58+#define TF_EXPIRATION 0x20
59+#define TF_EFFECTIVE 0x40
60+#define TF_LONGFORM 0x80
61+
62+#define NM_CONTINUE 0x01
63+#define NM_CURRENT 0x02
64+#define NM_PARENT 0x04
65+
66+
67+#define SUSP_LOC_ENTRY 0x01
68+#define SUSP_LOC_DOT 0x02
69+#define SUSP_LOC_DOTDOT 0x04
70+
71+#define SUSP_TYPE_SUSP 1
72+#define SUSP_TYPE_RRIP 2
73+
74+#define SUSP_ENTRY_SUSP_CE 1
75+#define SUSP_ENTRY_SUSP_PD 2
76+#define SUSP_ENTRY_SUSP_SP 3
77+#define SUSP_ENTRY_SUSP_ST 4
78+#define SUSP_ENTRY_SUSP_ER 5
79+#define SUSP_ENTRY_SUSP_ES 6
80+
81+#define SUSP_ENTRY_RRIP_PX 1
82+#define SUSP_ENTRY_RRIP_PN 2
83+#define SUSP_ENTRY_RRIP_SL 3
84+#define SUSP_ENTRY_RRIP_NM 4
85+#define SUSP_ENTRY_RRIP_CL 5
86+#define SUSP_ENTRY_RRIP_PL 6
87+#define SUSP_ENTRY_RRIP_RE 7
88+#define SUSP_ENTRY_RRIP_TF 8
89+#define SUSP_ENTRY_RRIP_SF 9
90+
91+#define SUSP_RRIP_ER_EXT_ID "IEEE_P1282"
92+#define SUSP_RRIP_ER_EXT_DES "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."
93+#define SUSP_RRIP_ER_EXT_SRC "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION."
94+
95+#define SL_FLAGS_NONE 0
96+#define SL_FLAGS_CONTINUE 1
97+#define SL_FLAGS_CURRENT 2
98+#define SL_FLAGS_PARENT 4
99+#define SL_FLAGS_ROOT 8
100+
101+typedef struct {
102+ ISO_SUSP_HEADER h;
103+ u_char mode [ISODCL(5,12)];
104+ u_char links [ISODCL(13,20)];
105+ u_char uid [ISODCL(21,28)];
106+ u_char gid [ISODCL(29,36)];
107+ u_char serial [ISODCL(37,44)];/* Not used */
108+} ISO_RRIP_PX;
109+
110+typedef struct {
111+ ISO_SUSP_HEADER h;
112+ u_char high [ISODCL(5,12)];
113+ u_char low [ISODCL(13,20)];
114+} ISO_RRIP_PN;
115+
116+typedef struct {
117+ ISO_SUSP_HEADER h;
118+ u_char flags [ISODCL ( 4, 4)];
119+ u_char component [ISODCL ( 4, 256)];
120+ u_int nBytes;
121+} ISO_RRIP_SL;
122+
123+typedef struct {
124+ ISO_SUSP_HEADER h;
125+ u_char flags [ISODCL ( 4, 4)];
126+ u_char timestamp [ISODCL ( 5, 256)];
127+} ISO_RRIP_TF;
128+
129+#define RRIP_NM_FLAGS_NONE 0x00
130+#define RRIP_NM_FLAGS_CONTINUE 0x01
131+#define RRIP_NM_FLAGS_CURRENT 0x02
132+#define RRIP_NM_FLAGS_PARENT 0x04
133+
134+typedef struct {
135+ ISO_SUSP_HEADER h;
136+ u_char flags [ISODCL ( 4, 4)];
137+ u_char altname [ISODCL ( 4, 256)];
138+} ISO_RRIP_NM;
139+
140+/* Note that this is the same structure as cd9660_rrip.h : ISO_RRIP_CONT */
141+typedef struct {
142+ ISO_SUSP_HEADER h;
143+ u_char ca_sector [ISODCL ( 5, 12)];
144+ u_char offset [ISODCL ( 13, 20)];
145+ u_char length [ISODCL ( 21, 28)];
146+} ISO_SUSP_CE;
147+
148+typedef struct {
149+ ISO_SUSP_HEADER h;
150+ u_char padding_area [ISODCL ( 4, 256)];
151+} ISO_SUSP_PD;
152+
153+typedef struct {
154+ ISO_SUSP_HEADER h;
155+ u_char check [ISODCL ( 4, 5)];
156+ u_char len_skp [ISODCL ( 6, 6)];
157+} ISO_SUSP_SP;
158+
159+typedef struct {
160+ ISO_SUSP_HEADER h;
161+} ISO_SUSP_ST;
162+
163+typedef struct {
164+ ISO_SUSP_HEADER h;
165+ u_char len_id [ISODCL ( 4, 4)];
166+ u_char len_des [ISODCL ( 5, 5)];
167+ u_char len_src [ISODCL ( 6, 6)];
168+ u_char ext_ver [ISODCL ( 7, 7)];
169+ u_char ext_data [ISODCL (8,256)];
170+/* u_char ext_id [ISODCL ( 8, 256)];
171+ u_char ext_des [ISODCL ( 257, 513)];
172+ u_char ext_src [ISODCL ( 514, 770)];*/
173+} ISO_SUSP_ER;
174+
175+typedef struct {
176+ ISO_SUSP_HEADER h;
177+ u_char ext_seq [ISODCL ( 4, 4)];
178+} ISO_SUSP_ES;
179+
180+typedef union {
181+ ISO_RRIP_PX PX;
182+ ISO_RRIP_PN PN;
183+ ISO_RRIP_SL SL;
184+ ISO_RRIP_NM NM;
185+ ISO_RRIP_CLINK CL;
186+ ISO_RRIP_PLINK PL;
187+ ISO_RRIP_RELDIR RE;
188+ ISO_RRIP_TF TF;
189+} rrip_entry;
190+
191+typedef union {
192+ ISO_SUSP_CE CE;
193+ ISO_SUSP_PD PD;
194+ ISO_SUSP_SP SP;
195+ ISO_SUSP_ST ST;
196+ ISO_SUSP_ER ER;
197+ ISO_SUSP_ES ES;
198+} susp_entry;
199+
200+typedef union {
201+ susp_entry su_entry;
202+ rrip_entry rr_entry;
203+} SUSP_ENTRIES;
204+
205+struct ISO_SUSP_ATTRIBUTES {
206+ SUSP_ENTRIES attr;
207+ int type;
208+ char type_of[2];
209+ char last_in_suf; /* last entry in the System Use Field? */
210+ /* Dan's addons - will merge later. This allows use of a switch */
211+ char susp_type; /* SUSP or RRIP */
212+ char entry_type; /* Record type */
213+ char write_location;
214+ TAILQ_ENTRY(ISO_SUSP_ATTRIBUTES) rr_ll;
215+};
216+
217+#define CD9660_SUSP_ENTRY_SIZE(entry)\
218+ ((int) ((entry)->attr.su_entry.SP.h.length[0]))
219+
220+/* Recursive function - move later to func pointer code*/
221+int cd9660_susp_finalize(iso9660_disk *, cd9660node *);
222+
223+/* These two operate on single nodes */
224+int cd9660_susp_finalize_node(iso9660_disk *, cd9660node *);
225+int cd9660_rrip_finalize_node(iso9660_disk *, cd9660node *);
226+
227+/* POSIX File attribute */
228+int cd9660node_rrip_px(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
229+
230+/* Device number */
231+int cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
232+
233+/* Symbolic link */
234+int cd9660node_rrip_SL(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
235+
236+/* Alternate Name function */
237+void cd9660_rrip_NM(cd9660node *);
238+void cd9660_rrip_add_NM(cd9660node *,const char *);
239+
240+/* Parent and child link function */
241+int cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
242+int cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
243+int cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
244+
245+int cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
246+
247+
248+
249+/*
250+ * Relocation directory function. I'm not quite sure what
251+ * sort of parameters are needed, but personally I don't think
252+ * any parameters are needed except for the memory address where
253+ * the information needs to be put in
254+ */
255+int cd9660node_rrip_re(void *, fsnode *);
256+
257+/*
258+ * Don't know if this function is needed because it apparently is an
259+ * optional feature that does not really need to be implemented but I
260+ * thought I should add it anyway.
261+ */
262+int cd9660_susp_ce (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
263+int cd9660_susp_pd (struct ISO_SUSP_ATTRIBUTES *, int);
264+int cd9660_susp_sp (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
265+int cd9660_susp_st (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
266+
267+struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ER(cd9660node *, u_char, const char *,
268+ const char *, const char *);
269+struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES*,
270+ cd9660node *);
271+
272+
273+/* Helper functions */
274+
275+/* Common SUSP/RRIP functions */
276+int cd9660_susp_initialize(iso9660_disk *, cd9660node *, cd9660node *,
277+ cd9660node *);
278+int cd9660_susp_initialize_node(iso9660_disk *, cd9660node *);
279+struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_create_node(int, int, const char *,
280+ int);
281+struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_add_entry(cd9660node *,
282+ struct ISO_SUSP_ATTRIBUTES *, struct ISO_SUSP_ATTRIBUTES *, int);
283+
284+/* RRIP specific functions */
285+int cd9660_rrip_initialize_node(iso9660_disk *, cd9660node *, cd9660node *,
286+ cd9660node *);
287+void cd9660_createSL(cd9660node *);
288+
289+/* Functions that probably can be removed */
290+/* int cd9660node_initialize_node(int, char *); */
291+
292+
293+#endif
+143,
-0
1@@ -0,0 +1,143 @@
2+/* $NetBSD: cd9660_rrip.h,v 1.3 2005/12/03 17:34:43 christos Exp $ */
3+
4+/*-
5+ * Copyright (c) 1993, 1994
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * This code is derived from software contributed to Berkeley
9+ * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
10+ * Support code is derived from software contributed to Berkeley
11+ * by Atsushi Murai (amurai@spec.co.jp).
12+ *
13+ * Redistribution and use in source and binary forms, with or without
14+ * modification, are permitted provided that the following conditions
15+ * are met:
16+ * 1. Redistributions of source code must retain the above copyright
17+ * notice, this list of conditions and the following disclaimer.
18+ * 2. Redistributions in binary form must reproduce the above copyright
19+ * notice, this list of conditions and the following disclaimer in the
20+ * documentation and/or other materials provided with the distribution.
21+ * 3. Neither the name of the University nor the names of its contributors
22+ * may be used to endorse or promote products derived from this software
23+ * without specific prior written permission.
24+ *
25+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35+ * SUCH DAMAGE.
36+ *
37+ * @(#)cd9660_rrip.h 8.2 (Berkeley) 12/5/94
38+ */
39+
40+#ifndef _ISOFS_CD9660_CD9660_RRIP_H_
41+#define _ISOFS_CD9660_CD9660_RRIP_H_
42+
43+typedef struct {
44+ char type [ISODCL ( 0, 1)];
45+ u_char length [ISODCL ( 2, 2)]; /* 711 */
46+ u_char version [ISODCL ( 3, 3)];
47+} ISO_SUSP_HEADER;
48+
49+typedef struct {
50+ ISO_SUSP_HEADER h;
51+ char mode [ISODCL ( 4, 11)]; /* 733 */
52+ char links [ISODCL ( 12, 19)]; /* 733 */
53+ char uid [ISODCL ( 20, 27)]; /* 733 */
54+ char gid [ISODCL ( 28, 35)]; /* 733 */
55+} ISO_RRIP_ATTR;
56+
57+typedef struct {
58+ ISO_SUSP_HEADER h;
59+ char dev_t_high [ISODCL ( 4, 11)]; /* 733 */
60+ char dev_t_low [ISODCL ( 12, 19)]; /* 733 */
61+} ISO_RRIP_DEVICE;
62+
63+#define ISO_SUSP_CFLAG_CONTINUE 0x01
64+#define ISO_SUSP_CFLAG_CURRENT 0x02
65+#define ISO_SUSP_CFLAG_PARENT 0x04
66+#define ISO_SUSP_CFLAG_ROOT 0x08
67+#define ISO_SUSP_CFLAG_VOLROOT 0x10
68+#define ISO_SUSP_CFLAG_HOST 0x20
69+
70+typedef struct {
71+ u_char cflag [ISODCL ( 1, 1)];
72+ u_char clen [ISODCL ( 2, 2)];
73+ u_char name [1]; /* XXX */
74+} ISO_RRIP_SLINK_COMPONENT;
75+#define ISO_RRIP_SLSIZ 2
76+
77+typedef struct {
78+ ISO_SUSP_HEADER h;
79+ u_char flags [ISODCL ( 4, 4)];
80+ u_char component [ISODCL ( 5, 5)];
81+} ISO_RRIP_SLINK;
82+
83+typedef struct {
84+ ISO_SUSP_HEADER h;
85+ char flags [ISODCL ( 4, 4)];
86+} ISO_RRIP_ALTNAME;
87+
88+typedef struct {
89+ ISO_SUSP_HEADER h;
90+ char dir_loc [ISODCL ( 4, 11)]; /* 733 */
91+} ISO_RRIP_CLINK;
92+
93+typedef struct {
94+ ISO_SUSP_HEADER h;
95+ char dir_loc [ISODCL ( 4, 11)]; /* 733 */
96+} ISO_RRIP_PLINK;
97+
98+typedef struct {
99+ ISO_SUSP_HEADER h;
100+} ISO_RRIP_RELDIR;
101+
102+#define ISO_SUSP_TSTAMP_FORM17 0x80
103+#define ISO_SUSP_TSTAMP_FORM7 0x00
104+#define ISO_SUSP_TSTAMP_CREAT 0x01
105+#define ISO_SUSP_TSTAMP_MODIFY 0x02
106+#define ISO_SUSP_TSTAMP_ACCESS 0x04
107+#define ISO_SUSP_TSTAMP_ATTR 0x08
108+#define ISO_SUSP_TSTAMP_BACKUP 0x10
109+#define ISO_SUSP_TSTAMP_EXPIRE 0x20
110+#define ISO_SUSP_TSTAMP_EFFECT 0x40
111+
112+typedef struct {
113+ ISO_SUSP_HEADER h;
114+ u_char flags [ISODCL ( 4, 4)];
115+ u_char time [ISODCL ( 5, 5)];
116+} ISO_RRIP_TSTAMP;
117+
118+typedef struct {
119+ ISO_SUSP_HEADER h;
120+ u_char flags [ISODCL ( 4, 4)];
121+} ISO_RRIP_IDFLAG;
122+
123+typedef struct {
124+ ISO_SUSP_HEADER h;
125+ char len_id [ISODCL ( 4, 4)];
126+ char len_des [ISODCL ( 5, 5)];
127+ char len_src [ISODCL ( 6, 6)];
128+ char version [ISODCL ( 7, 7)];
129+} ISO_RRIP_EXTREF;
130+
131+typedef struct {
132+ ISO_SUSP_HEADER h;
133+ char check [ISODCL ( 4, 5)];
134+ char skip [ISODCL ( 6, 6)];
135+} ISO_RRIP_OFFSET;
136+
137+typedef struct {
138+ ISO_SUSP_HEADER h;
139+ char location [ISODCL ( 4, 11)];
140+ char offset [ISODCL ( 12, 19)];
141+ char length [ISODCL ( 20, 27)];
142+} ISO_RRIP_CONT;
143+
144+#endif /* _ISOFS_CD9660_CD9660_RRIP_H_ */
+247,
-0
1@@ -0,0 +1,247 @@
2+/* $NetBSD: iso.h,v 1.11 2026/01/08 15:39:07 nia Exp $ */
3+
4+/*-
5+ * Copyright (c) 1994
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * This code is derived from software contributed to Berkeley
9+ * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
10+ * Support code is derived from software contributed to Berkeley
11+ * by Atsushi Murai (amurai@spec.co.jp).
12+ *
13+ * Redistribution and use in source and binary forms, with or without
14+ * modification, are permitted provided that the following conditions
15+ * are met:
16+ * 1. Redistributions of source code must retain the above copyright
17+ * notice, this list of conditions and the following disclaimer.
18+ * 2. Redistributions in binary form must reproduce the above copyright
19+ * notice, this list of conditions and the following disclaimer in the
20+ * documentation and/or other materials provided with the distribution.
21+ * 3. Neither the name of the University nor the names of its contributors
22+ * may be used to endorse or promote products derived from this software
23+ * without specific prior written permission.
24+ *
25+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35+ * SUCH DAMAGE.
36+ *
37+ * @(#)iso.h 8.6 (Berkeley) 5/10/95
38+ */
39+
40+/*
41+ * Definitions describing ISO9660 file system structure, as well as
42+ * the functions necessary to access fields of ISO9660 file system
43+ * structures.
44+ */
45+
46+#ifndef _ISOFS_CD9660_ISO_H_
47+#define _ISOFS_CD9660_ISO_H_
48+
49+#include <sys/endian.h>
50+
51+#define ISODCL(from, to) (to - from + 1)
52+
53+struct iso_volume_descriptor {
54+ char type[ISODCL(1,1)]; /* 711 */
55+ char id[ISODCL(2,6)];
56+ char version[ISODCL(7,7)];
57+ char data[ISODCL(8,2048)];
58+};
59+
60+/* volume descriptor types */
61+#define ISO_VD_PRIMARY 1
62+#define ISO_VD_SUPPLEMENTARY 2
63+#define ISO_VD_END 255
64+
65+#define ISO_STANDARD_ID "CD001"
66+#define ISO_ECMA_ID "CDW01"
67+
68+#define ISO_MAXNAMLEN 255
69+
70+struct iso_primary_descriptor {
71+ char type [ISODCL ( 1, 1)]; /* 711 */
72+ char id [ISODCL ( 2, 6)];
73+ char version [ISODCL ( 7, 7)]; /* 711 */
74+ char unused1 [ISODCL ( 8, 8)];
75+ char system_id [ISODCL ( 9, 40)]; /* achars */
76+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
77+ char unused2 [ISODCL ( 73, 80)];
78+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
79+ char unused3 [ISODCL ( 89, 120)];
80+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
81+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
82+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
83+ char path_table_size [ISODCL (133, 140)]; /* 733 */
84+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
85+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
86+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
87+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
88+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
89+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
90+ char publisher_id [ISODCL (319, 446)]; /* achars */
91+ char preparer_id [ISODCL (447, 574)]; /* achars */
92+ char application_id [ISODCL (575, 702)]; /* achars */
93+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
94+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
95+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
96+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
97+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
98+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
99+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
100+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
101+ char unused4 [ISODCL (883, 883)];
102+ char application_data [ISODCL (884, 1395)];
103+ char unused5 [ISODCL (1396, 2048)];
104+};
105+#define ISO_DEFAULT_BLOCK_SIZE 2048
106+
107+struct iso_supplementary_descriptor {
108+ char type [ISODCL ( 1, 1)]; /* 711 */
109+ char id [ISODCL ( 2, 6)];
110+ char version [ISODCL ( 7, 7)]; /* 711 */
111+ char flags [ISODCL ( 8, 8)]; /* 711? */
112+ char system_id [ISODCL ( 9, 40)]; /* achars */
113+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
114+ char unused2 [ISODCL ( 73, 80)];
115+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
116+ char escape [ISODCL ( 89, 120)];
117+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
118+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
119+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
120+ char path_table_size [ISODCL (133, 140)]; /* 733 */
121+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
122+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
123+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
124+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
125+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
126+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
127+ char publisher_id [ISODCL (319, 446)]; /* achars */
128+ char preparer_id [ISODCL (447, 574)]; /* achars */
129+ char application_id [ISODCL (575, 702)]; /* achars */
130+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
131+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
132+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
133+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
134+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
135+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
136+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
137+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
138+ char unused4 [ISODCL (883, 883)];
139+ char application_data [ISODCL (884, 1395)];
140+ char unused5 [ISODCL (1396, 2048)];
141+};
142+
143+struct iso_directory_record {
144+ char length [ISODCL (1, 1)]; /* 711 */
145+ char ext_attr_length [ISODCL (2, 2)]; /* 711 */
146+ u_char extent [ISODCL (3, 10)]; /* 733 */
147+ u_char size [ISODCL (11, 18)]; /* 733 */
148+ char date [ISODCL (19, 25)]; /* 7 by 711 */
149+ char flags [ISODCL (26, 26)];
150+ char file_unit_size [ISODCL (27, 27)]; /* 711 */
151+ char interleave [ISODCL (28, 28)]; /* 711 */
152+ char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
153+ char name_len [ISODCL (33, 33)]; /* 711 */
154+ char name [1]; /* XXX */
155+};
156+/* can't take sizeof(iso_directory_record), because of possible alignment
157+ of the last entry (34 instead of 33) */
158+#define ISO_DIRECTORY_RECORD_SIZE 33
159+
160+struct iso_extended_attributes {
161+ u_char owner [ISODCL (1, 4)]; /* 723 */
162+ u_char group [ISODCL (5, 8)]; /* 723 */
163+ u_char perm [ISODCL (9, 10)]; /* 9.5.3 */
164+ char ctime [ISODCL (11, 27)]; /* 8.4.26.1 */
165+ char mtime [ISODCL (28, 44)]; /* 8.4.26.1 */
166+ char xtime [ISODCL (45, 61)]; /* 8.4.26.1 */
167+ char ftime [ISODCL (62, 78)]; /* 8.4.26.1 */
168+ char recfmt [ISODCL (79, 79)]; /* 711 */
169+ char recattr [ISODCL (80, 80)]; /* 711 */
170+ u_char reclen [ISODCL (81, 84)]; /* 723 */
171+ char system_id [ISODCL (85, 116)]; /* achars */
172+ char system_use [ISODCL (117, 180)];
173+ char version [ISODCL (181, 181)]; /* 711 */
174+ char len_esc [ISODCL (182, 182)]; /* 711 */
175+ char reserved [ISODCL (183, 246)];
176+ u_char len_au [ISODCL (247, 250)]; /* 723 */
177+};
178+
179+/* 7.1.1: unsigned char */
180+static __inline NETCOMPAT_UNUSED int
181+isonum_711(const u_char *p)
182+{
183+ return *p;
184+}
185+
186+/* 7.1.2: signed char */
187+static __inline NETCOMPAT_UNUSED int
188+isonum_712(const u_char *p)
189+{
190+ return (signed char) *p;
191+}
192+
193+/* 7.2.1: unsigned little-endian 16-bit value. NOT USED IN KERNEL. */
194+static __inline NETCOMPAT_UNUSED uint16_t
195+isonum_721(const u_char *p)
196+{
197+ return le16dec(p);
198+}
199+
200+/* 7.2.2: unsigned big-endian 16-bit value. NOT USED IN KERNEL. */
201+static __inline NETCOMPAT_UNUSED uint16_t
202+isonum_722(const u_char *p)
203+{
204+ return be16dec(p);
205+}
206+
207+/* 7.2.3: unsigned both-endian (little, then big) 16-bit value */
208+static __inline NETCOMPAT_UNUSED uint16_t
209+isonum_723(const u_char *p)
210+{
211+#if BYTE_ORDER == BIG_ENDIAN
212+ return be16dec(p + 2);
213+#else
214+ return le16dec(p);
215+#endif
216+}
217+
218+/* 7.3.1: unsigned little-endian 32-bit value. NOT USED IN KERNEL. */
219+static __inline NETCOMPAT_UNUSED uint32_t
220+isonum_731(const u_char *p)
221+{
222+ return le32dec(p);
223+}
224+
225+/* 7.3.2: unsigned big-endian 32-bit value. NOT USED IN KERNEL. */
226+static __inline NETCOMPAT_UNUSED uint32_t
227+isonum_732(const u_char *p)
228+{
229+ return be32dec(p);
230+}
231+
232+/* 7.3.3: unsigned both-endian (little, then big) 32-bit value */
233+static __inline NETCOMPAT_UNUSED uint32_t
234+isonum_733(const u_char *p)
235+{
236+#if BYTE_ORDER == BIG_ENDIAN
237+ return be32dec(p + 4);
238+#else
239+ return le32dec(p);
240+#endif
241+}
242+
243+/*
244+ * Associated files have a leading '='.
245+ */
246+#define ASSOCCHAR '='
247+
248+#endif /* _ISOFS_CD9660_ISO_H_ */
+85,
-0
1@@ -0,0 +1,85 @@
2+/* $NetBSD: iso_rrip.h,v 1.4 2005/12/03 17:34:43 christos Exp $ */
3+
4+/*-
5+ * Copyright (c) 1993, 1994
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * This code is derived from software contributed to Berkeley
9+ * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
10+ * Support code is derived from software contributed to Berkeley
11+ * by Atsushi Murai (amurai@spec.co.jp).
12+ *
13+ * Redistribution and use in source and binary forms, with or without
14+ * modification, are permitted provided that the following conditions
15+ * are met:
16+ * 1. Redistributions of source code must retain the above copyright
17+ * notice, this list of conditions and the following disclaimer.
18+ * 2. Redistributions in binary form must reproduce the above copyright
19+ * notice, this list of conditions and the following disclaimer in the
20+ * documentation and/or other materials provided with the distribution.
21+ * 3. Neither the name of the University nor the names of its contributors
22+ * may be used to endorse or promote products derived from this software
23+ * without specific prior written permission.
24+ *
25+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35+ * SUCH DAMAGE.
36+ *
37+ * @(#)iso_rrip.h 8.2 (Berkeley) 1/23/94
38+ */
39+
40+#ifndef _ISOFS_CD9660_ISO_RRIP_H_
41+#define _ISOFS_CD9660_ISO_RRIP_H_
42+
43+/*
44+ * Analyze function flag (similar to RR field bits)
45+ */
46+#define ISO_SUSP_ATTR 0x0001
47+#define ISO_SUSP_DEVICE 0x0002
48+#define ISO_SUSP_SLINK 0x0004
49+#define ISO_SUSP_ALTNAME 0x0008
50+#define ISO_SUSP_CLINK 0x0010
51+#define ISO_SUSP_PLINK 0x0020
52+#define ISO_SUSP_RELDIR 0x0040
53+#define ISO_SUSP_TSTAMP 0x0080
54+#define ISO_SUSP_IDFLAG 0x0100
55+#define ISO_SUSP_EXTREF 0x0200
56+#define ISO_SUSP_CONT 0x0400
57+#define ISO_SUSP_OFFSET 0x0800
58+#define ISO_SUSP_STOP 0x1000
59+#define ISO_SUSP_UNKNOWN 0x8000
60+
61+typedef struct {
62+ struct iso_node *inop;
63+ int fields; /* interesting fields in this analysis */
64+ daddr_t iso_ce_blk; /* block of continuation area */
65+ off_t iso_ce_off; /* offset of continuation area */
66+ int iso_ce_len; /* length of continuation area */
67+ struct iso_mnt *imp; /* mount structure */
68+ ino_t *inump; /* inode number pointer */
69+ char *outbuf; /* name/symbolic link output area */
70+ u_short *outlen; /* length of above */
71+ u_short maxlen; /* maximum length of above */
72+ int cont; /* continuation of above */
73+} ISO_RRIP_ANALYZE;
74+
75+int cd9660_rrip_analyze(struct iso_directory_record *isodir,
76+ struct iso_node *inop, struct iso_mnt *imp);
77+int cd9660_rrip_getname(struct iso_directory_record *isodir,
78+ char *outbuf, u_short *outlen,
79+ ino_t *inump, struct iso_mnt *imp);
80+int cd9660_rrip_getsymname(struct iso_directory_record *isodir,
81+ char *outbuf, u_short *outlen,
82+ struct iso_mnt *imp);
83+int cd9660_rrip_offset(struct iso_directory_record *isodir,
84+ struct iso_mnt *imp);
85+
86+#endif /* _ISOFS_CD9660_ISO_RRIP_H_ */
+648,
-0
1@@ -0,0 +1,648 @@
2+.\" $NetBSD: makefs.8,v 1.74 2026/01/10 08:58:47 tsutsui Exp $
3+.\"
4+.\" Copyright (c) 2001-2003 Wasabi Systems, Inc.
5+.\" All rights reserved.
6+.\"
7+.\" Written by Luke Mewburn for Wasabi Systems, Inc.
8+.\"
9+.\" Redistribution and use in source and binary forms, with or without
10+.\" modification, are permitted provided that the following conditions
11+.\" are met:
12+.\" 1. Redistributions of source code must retain the above copyright
13+.\" notice, this list of conditions and the following disclaimer.
14+.\" 2. Redistributions in binary form must reproduce the above copyright
15+.\" notice, this list of conditions and the following disclaimer in the
16+.\" documentation and/or other materials provided with the distribution.
17+.\" 3. All advertising materials mentioning features or use of this software
18+.\" must display the following acknowledgement:
19+.\" This product includes software developed for the NetBSD Project by
20+.\" Wasabi Systems, Inc.
21+.\" 4. The name of Wasabi Systems, Inc. may not be used to endorse
22+.\" or promote products derived from this software without specific prior
23+.\" written permission.
24+.\"
25+.\" THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35+.\" POSSIBILITY OF SUCH DAMAGE.
36+.\"
37+.Dd January 10, 2026
38+.Dt MAKEFS 8
39+.Os
40+.Sh NAME
41+.Nm makefs
42+.Nd create a file system image from a directory tree
43+.Sh SYNOPSIS
44+.Nm
45+.Op Fl LrxZ
46+.Op Fl B Ar endian
47+.Op Fl b Ar free-blocks
48+.Op Fl d Ar debug-mask
49+.Op Fl F Ar mtree-specfile
50+.Op Fl f Ar free-files
51+.Op Fl M Ar minimum-size
52+.Op Fl m Ar maximum-size
53+.Op Fl N Ar userdb-dir
54+.Op Fl O Ar offset
55+.Op Fl o Ar fs-options
56+.Op Fl S Ar sector-size
57+.Op Fl s Ar image-size
58+.Op Fl T Ar timestamp
59+.Op Fl t Ar fs-type
60+.Ar image-file
61+.Ar directory
62+.Op Ar extra-directory ...
63+.Sh DESCRIPTION
64+The utility
65+.Nm
66+creates a file system image into
67+.Ar image-file
68+from the directory tree
69+.Ar directory .
70+If any optional directory trees are passed in the
71+.Ar extra-directory
72+arguments, then the directory tree of each argument will be merged
73+into the
74+.Ar directory
75+first before creating
76+.Ar image-file .
77+No special devices or privileges are required to perform this task.
78+.Pp
79+The options are as follows:
80+.Bl -tag -width flag
81+.It Fl B Ar endian
82+Set the byte order of the image to
83+.Ar endian .
84+Valid byte orders are
85+.Ql 4321 ,
86+.Ql big ,
87+or
88+.Ql be
89+for big endian, and
90+.Ql 1234 ,
91+.Ql little ,
92+or
93+.Ql le
94+for little endian.
95+Some file systems may have a fixed byte order; in those cases this
96+argument will be ignored.
97+.It Fl b Ar free-blocks
98+Ensure that a minimum of
99+.Ar free-blocks
100+free blocks exist in the image.
101+An optional
102+.Ql %
103+suffix may be provided to indicate that
104+.Ar free-blocks
105+indicates a percentage of the calculated image size.
106+.It Fl d Ar debug-mask | comma-separated-debug-option
107+Enable various levels of debugging, depending upon which bits are
108+set in
109+.Ar debug-mask .
110+The mask can also be set by specifying a comma separated list of debugging
111+options.
112+These are:
113+.Bl -tag -width X -offset indent -compact
114+.It Ar debug_time
115+Print the time it takes to perform each step.
116+.It Ar debug_walk_dir
117+Print each directory as it gets processed.
118+.It Ar debug_walk_dir_node
119+Print each file as it gets processed.
120+.It Ar debug_walk_dir_linkcheck
121+Print file information for files that have a link count > 1.
122+.It Ar debug_dump_fsnodes
123+Dump information about the filesystem nodes.
124+.It Ar debug_dump_fsnodes_verbose
125+Enable more detail if
126+.Dv debug_dump_fsnodes
127+is enabled.
128+.It Ar debug_fs_parse_opts
129+Print debugging information about specific filesystem option parsing.
130+.It Ar debug_fs_makefs
131+Print nodes as they are created and enable buffer consistency checks.
132+.It Ar debug_fs_validate
133+Enable file-system specific validation (ffs only).
134+.It Ar debug_fs_create_image
135+Print image file creation stats (ffs only).
136+.It Ar debug_fs_size_dir
137+Print directory size information (ffs only).
138+.It Ar debug_fs_size_dir_node
139+Print directory size information per node (ffs only).
140+.It Ar debug_fs_size_dir_add_dirent
141+Print directory size information as entries are added (ffs only).
142+.It Ar debug_fs_populate
143+Print information at each directory population pass (ffs only).
144+.It Ar debug_fs_populate_dirbuf
145+Dump the directory buffer (ffs only).
146+.It Ar debug_fs_populate_node
147+Print information about each file during directory population (ffs only).
148+.It Ar debug_fs_write_file
149+Print buffer informaion when writing files (ffs only).
150+.It Ar debug_fs_write_file_block
151+Print block information when writing files (ffs only).
152+.It Ar debug_fs_make_dirbuf
153+Print directory buffer information (ffs only).
154+.It Ar debug_fs_write_inode
155+Print inode information (ffs only).
156+.It Ar debug_buf_bread
157+Print block buffer information (ffs only).
158+.It Ar debug_buf_bwrite
159+Print block write information (ffs only).
160+.It Ar debug_buf_getblk
161+Print block allocaion information (ffs only).
162+.It Ar debug_apply_specfile
163+Print information about each directory in the specfile.
164+.It Ar debug_apply_specentry
165+Print information about each entry in the specfile.
166+.It Ar debug_apply_speconly
167+Debug the
168+.Fl x
169+special file exclusion.
170+.El
171+.It Fl F Ar mtree-specfile
172+Use
173+.Ar mtree-specfile
174+as an
175+.Xr mtree 8
176+.Sq specfile
177+specification.
178+.Pp
179+If a specfile entry exists in the underlying file system, its
180+permissions and modification time will be used unless specifically
181+overridden by the specfile.
182+An error will be raised if the type of entry in the specfile
183+conflicts with that of an existing entry.
184+.Pp
185+In the opposite case (where a specfile entry does not have an entry
186+in the underlying file system) the following occurs:
187+If the specfile entry is marked
188+.Sy optional ,
189+the specfile entry is ignored.
190+Otherwise, the entry will be created in the image, and it is
191+necessary to specify at least the following parameters in the
192+specfile:
193+.Sy type ,
194+.Sy mode ,
195+.Sy gname ,
196+or
197+.Sy gid ,
198+and
199+.Sy uname
200+or
201+.Sy uid ,
202+.Sy device
203+(in the case of block or character devices), and
204+.Sy link
205+(in the case of symbolic links).
206+If
207+.Sy time
208+isn't provided, the current time will be used.
209+If
210+.Sy flags
211+isn't provided, the current file flags will be used.
212+Missing regular file entries will be created as zero-length files.
213+.It Fl f Ar free-files
214+Ensure that a minimum of
215+.Ar free-files
216+free files (inodes) exist in the image.
217+An optional
218+.Ql %
219+suffix may be provided to indicate that
220+.Ar free-files
221+indicates a percentage of the calculated image size.
222+.It Fl L
223+All symbolic links are followed.
224+.It Fl M Ar minimum-size
225+Set the minimum size of the file system image to
226+.Ar minimum-size .
227+.It Fl m Ar maximum-size
228+Set the maximum size of the file system image to
229+.Ar maximum-size .
230+An error will be raised if the target file system needs to be larger
231+than this to accommodate the provided directory tree.
232+.It Fl N Ar userdb-dir
233+Use the user database text file
234+.Pa master.passwd
235+and group database text file
236+.Pa group
237+from
238+.Ar userdb-dir ,
239+rather than using the results from the system's
240+.Xr getpwnam 3
241+and
242+.Xr getgrnam 3
243+(and related) library calls.
244+.It Fl O Ar offset
245+Instead of creating the file system at the beginning of the file, start
246+at offset.
247+Valid only for
248+.Sy ffs
249+and
250+.Sy msdos .
251+.It Fl o Ar fs-options
252+Set file system specific options.
253+.Ar fs-options
254+is a comma separated list of options.
255+Valid file system specific options are detailed below.
256+.It Fl r
257+When merging multiple directories replace duplicate files with the last found.
258+.It Fl S Ar sector-size
259+Set the file system sector size to
260+.Ar sector-size .
261+Defaults to 512 for most file systems, but is 2048 for
262+.Sy cd9660
263+and
264+.Sy udf
265+for CD/DVD/BD optical media types.
266+.It Fl s Ar image-size
267+Set the size of the file system image to
268+.Ar image-size .
269+This is equivalent of setting both the minimum
270+.Fl ( M )
271+and the maximum
272+.Fl ( m )
273+sizes to
274+.Ar image-size .
275+For
276+.Sy ffs
277+and
278+.Sy msdos
279+the
280+.Ar offset
281+is not included on that size.
282+.It Fl T Ar timestamp
283+Specify a timestamp to be set for all file system files and directories
284+created so that repeatable builds are possible.
285+The
286+.Ar timestamp
287+can be a
288+.Pa pathname ,
289+where the timestamps are derived from that file, a parseable date
290+for
291+.Xr parsedate 3
292+(this option is not yet available in the tools build), or an integer
293+value interpreted as the number of seconds from the Epoch.
294+Note that timestamps specified in an
295+.Xr mtree 5
296+spec file, override the default timestamp.
297+When this option is enabled, file systems that regularly use
298+.Xr localtime 3
299+to convert times to the native format (such as udf and cd9660), use
300+.Xr gmtime 3
301+instead with the specified timestamps so that they are immune to
302+timezone changes and get consistent timestamps.
303+.It Fl t Ar fs-type
304+Create an
305+.Ar fs-type
306+file system image.
307+The following file system types are supported:
308+.Bl -tag -width cd9660 -offset indent
309+.It Sy cd9660
310+ISO 9660 file system.
311+.It Sy chfs
312+Chip flash file system.
313+.It Sy ffs
314+BSD fast file system (default).
315+.It Sy msdos
316+FAT12, FAT16, or FAT32 file system.
317+.It Sy udf
318+ISO/Ecma UDF file system.
319+.It Sy v7fs
320+7th Edition(V7) file system.
321+.El
322+.It Fl x
323+Exclude file system nodes not explicitly listed in the specfile.
324+Repeating this flag causes
325+.Nm
326+to print a warning for each missing system nodes and exit with an error code
327+if there are any missing.
328+.It Fl Z
329+Create a sparse file for
330+.Sy ffs .
331+This is useful for virtual machine images.
332+.El
333+.Pp
334+Where sizes are specified, a decimal number of bytes is expected.
335+Two or more numbers may be separated by an
336+.Sq x
337+to indicate a product.
338+Each number may have one of the following optional suffixes:
339+.Bl -tag -width 3n -offset indent -compact
340+.It b
341+Block; multiply by 512
342+.It k
343+Kibi; multiply by 1024 (1 KiB)
344+.It m
345+Mebi; multiply by 1048576 (1 MiB)
346+.It g
347+Gibi; multiply by 1073741824 (1 GiB)
348+.It t
349+Tebi; multiply by 1099511627776 (1 TiB)
350+.It w
351+Word; multiply by the number of bytes in an integer
352+.El
353+.\"
354+.\"
355+.Ss FFS-specific options
356+.Sy ffs
357+images have ffs-specific optional parameters that may be provided.
358+Each of the options consists of a keyword, an equal sign
359+.Pq Ql = ,
360+and a value.
361+The following keywords are supported:
362+.Pp
363+.Bl -tag -width optimization -offset indent -compact
364+.It Sy avgfilesize
365+Expected average file size.
366+.It Sy avgfpdir
367+Expected number of files per directory.
368+.It Sy bsize
369+Block size.
370+.It Sy density
371+Bytes per inode.
372+.It Sy extattr
373+UFS2 with extended attributes.
374+.It Sy extent
375+Maximum extent size.
376+.It Sy fsize
377+Fragment size.
378+.It Sy label
379+Label name of the image.
380+.It Sy maxbpcg
381+Maximum total number of blocks in a cylinder group.
382+.It Sy maxbpg
383+Maximum blocks per file in a cylinder group.
384+.It Sy minfree
385+Minimum % free.
386+.It Sy optimization
387+Optimization preference; one of
388+.Ql space
389+or
390+.Ql time .
391+.It Sy version
392+File system format version, compatible with the
393+.Fl O
394+option of
395+.Xr newfs 8 .
396+0 for FFSv1 with the old level 1 format.
397+1 for FFSv1 (default, level 4), and
398+2 for FFSv2 (UFS2).
399+.El
400+.Ss CD9660-specific options
401+.Sy cd9660
402+images have ISO9660-specific optional parameters that may be
403+provided.
404+The arguments consist of a keyword and, optionally, an equal sign
405+.Pq Ql = ,
406+and a value.
407+The following keywords are supported:
408+.Pp
409+.Bl -tag -width omit-trailing-period -offset indent -compact
410+.It Sy allow-deep-trees
411+Allow the directory structure to exceed the maximum specified in
412+the spec.
413+.\" .It Sy allow-illegal-chars
414+.\" Unknown
415+.\" .It Sy allow-lowercase
416+.\" Unknown
417+.It Sy allow-max-name
418+Allow 37 instead of 33 characters for filenames by omitting the
419+version ID.
420+.It Sy allow-multidot
421+Allow multiple dots in a filename.
422+.It Sy applicationid
423+Application ID of the image.
424+.It Sy archimedes
425+Use the
426+.Ql ARCHIMEDES
427+extension to encode
428+.Tn RISC OS
429+metadata.
430+.It Sy boot-load-segment
431+Set load segment for the boot image.
432+.It Sy bootimage
433+Filename of a boot image in the format
434+.Dq sysid;filename ,
435+where
436+.Dq sysid
437+is one of
438+.Ql efi ,
439+.Ql i386 ,
440+.Ql mac68k ,
441+.Ql macppc ,
442+or
443+.Ql powerpc .
444+.It Sy chrp-boot
445+Write an MBR partition table to the image to allow older CHRP hardware to
446+boot.
447+.It Sy generic-bootimage
448+Load a generic boot image into the first 32K of the cd9660 image.
449+.It Sy hard-disk-boot
450+Boot image is a hard disk image.
451+.It Sy keep-bad-images
452+Don't throw away images whose write was aborted due to an error.
453+For debugging purposes.
454+.It Sy label
455+Label name of the image.
456+.It Sy no-boot
457+Boot image is not bootable.
458+.It Sy no-emul-boot
459+Boot image is a
460+.Dq no emulation
461+ElTorito image.
462+.It Sy no-trailing-padding
463+Do not pad the image (apparently Linux needs the padding).
464+.\" .It Sy omit-trailing-period
465+.\" Unknown
466+.It Sy platformid
467+Set platform ID of section header entry of the boot image.
468+.It Sy preparer
469+Preparer ID of the image.
470+.It Sy publisher
471+Publisher ID of the image.
472+.It Sy rockridge
473+Use RockRidge extensions (for longer filenames, etc.).
474+.It Sy volumeid
475+Volume set identifier of the image.
476+.El
477+.Ss CHFS-specific options
478+.Sy chfs
479+images have chfs-specific optional parameters that may be provided.
480+Each of the options consists of a keyword, an equal sign
481+.Pq Ql = ,
482+and a value.
483+The following keywords are supported:
484+.Pp
485+.Bl -tag -width optimization -offset indent -compact
486+.It Sy pagesize
487+Pagesize.
488+.It Sy erasesize
489+Erase block size of the media.
490+.It Sy mediatype
491+Type of the media.
492+NOR: 0 or NAND: 1.
493+.El
494+.Ss msdos-specific options
495+.Sy msdos
496+images have MS-DOS-specific optional parameters that may be
497+provided.
498+The arguments consist of a keyword, an equal sign
499+.Pq Ql = ,
500+and a value.
501+The following keywords are supported (see
502+.Xr newfs_msdos 8
503+for more details):
504+.Pp
505+.Bl -tag -width omit-trailing-period -offset indent -compact
506+.It Cm backup_sector
507+Location of the backup boot sector.
508+.It Cm block_size
509+Block size.
510+.It Cm bootstrap
511+Bootstrap file.
512+.It Cm bytes_per_sector
513+Bytes per sector.
514+.It Cm create_size
515+Create file size.
516+.It Cm directory_entries
517+Directory entries.
518+.It Cm drive_heads
519+Drive heads.
520+.It Cm fat_type
521+FAT type (12, 16, or 32).
522+.It Cm floppy
523+Preset drive parameters for standard format floppy disks
524+(160, 180, 320, 360, 640, 720, 1200, 1232, 1440, or 2880).
525+.It Cm hidden_sectors
526+Hidden sectors.
527+.It Cm info_sector
528+Location of the info sector.
529+.It Cm media_descriptor
530+Media descriptor.
531+.It Cm num_FAT
532+Number of FATs.
533+.It Cm OEM_string
534+OEM string.
535+.It Cm offset
536+Offset in device.
537+.It Cm reserved_sectors
538+Reserved sectors.
539+.It Cm sectors_per_cluster
540+Sectors per cluster.
541+.It Cm sectors_per_fat
542+Sectors per FAT.
543+.It Cm sectors_per_track
544+Sectors per track.
545+.It Cm size
546+File System size.
547+.It Cm volume_id
548+Volume ID.
549+.It Cm volume_label
550+Volume Label.
551+.El
552+.Ss V7FS-specific options
553+The following keywords are supported:
554+.Pp
555+.Bl -tag -width optimization -offset indent -compact
556+.It Sy pdp
557+PDP endian.
558+.It Sy progress
559+Display a progress meter for the file system construction and file
560+population.
561+.El
562+.Ss UDF-specific options
563+.Nm
564+supports besides writing to image files also direct formatting of disc
565+partitions and optical media.
566+Optical media will auto configure settings.
567+The following udf-specific optional parameters may be provided.
568+Each of the options consists of a keyword, an equal sign
569+.Pq Ql = ,
570+and a value.
571+The following keywords are supported:
572+.Pp
573+.Bl -tag -width optimization -offset indent -compact
574+.It Sy disctype
575+This can have the following values:
576+.Bl -tag -width cdromXdvdromXbdromXXX -compact
577+.It Sy cdrom , Sy dvdrom , Sy bdrom
578+create a read-only fs
579+.It Sy dvdram , Sy bdre , Sy disk
580+create a rewritable fs without sparing for defective sectors
581+.It Sy cdr , Sy dvdr , Sy bdr
582+create a rewritable fs on once recordable media using a VAT
583+.It Sy cdrw , Sy dvdrw
584+create a rewritable fs with sparing for defective sectors
585+.El
586+The sectorsize is set for the selected media and the default maximum disc size
587+is assumed unless overridden.
588+For CD-ROM, DVD-ROM and BD-ROM images, the disc
589+size is the minimum size needed.
590+Note that the size estimator can
591+under-estimate in some cases; specify extra free blocks if encountering this.
592+.It Sy loglabel
593+Set the logical volume label of the disc to the specified argument.
594+.It Sy discid
595+Set the physical volume label of the disc to the specified argument.
596+Prepend the physical volume label with a volumeset label separated
597+with a ':' if wanted.
598+For strict conformance and interchange, don't set the volumeset label
599+manually unless it has an unique hex number in the first 8 character
600+positions.
601+.It Sy minver
602+Set the minimum UDF version to be used.
603+Choose UDF version numbers from 0x102, 0x150, 0x200, 0x201, and 0x250.
604+Version 0x260 is currently not supported
605+in
606+.Nm .
607+.It Sy maxver
608+Set the maximum UDF version to be used.
609+Choose UDF version numbers from 0x102, 0x150, 0x200, 0x201, and 0x250.
610+Version 0x260 is currently not supported
611+in
612+.Nm .
613+.It Sy metaperc
614+Set the minimum amount of free metadata space.
615+This is only applicable on UDF 0x250 on rewritable media.
616+.It Sy checksurface
617+Check the surface of non error-free rewritable media for remapping.
618+Note this is a destructive test and can take quite a while!
619+.It Sy forceformat
620+Force formatting on non-empty recordable media.
621+.El
622+.Sh SEE ALSO
623+.Xr strsuftoll 3 ,
624+.Xr installboot 8 ,
625+.Xr mtree 8 ,
626+.Xr newfs 8
627+.Sh HISTORY
628+The
629+.Nm
630+utility appeared in
631+.Nx 1.6 .
632+.Sh AUTHORS
633+.An Luke Mewburn
634+.Aq lukem@NetBSD.org
635+(original program),
636+.An Daniel Watt ,
637+.An Walter Deignan ,
638+.An Ryan Gabrys ,
639+.An Alan Perez-Rathke ,
640+.An Ram Vedam
641+(cd9660 support),
642+.An UCHIYAMA Yasushi
643+(v7fs support),
644+.An Tamas Toth
645+(chfs support),
646+.An Christos Zoulas
647+(msdos support),
648+.An Reinoud Zandijk
649+(udf support).
+561,
-0
1@@ -0,0 +1,561 @@
2+/* $NetBSD: makefs.c,v 1.59 2024/10/27 18:35:52 christos Exp $ */
3+
4+/*
5+ * Copyright (c) 2001-2003 Wasabi Systems, Inc.
6+ * All rights reserved.
7+ *
8+ * Written by Luke Mewburn for Wasabi Systems, Inc.
9+ *
10+ * Redistribution and use in source and binary forms, with or without
11+ * modification, are permitted provided that the following conditions
12+ * are met:
13+ * 1. Redistributions of source code must retain the above copyright
14+ * notice, this list of conditions and the following disclaimer.
15+ * 2. Redistributions in binary form must reproduce the above copyright
16+ * notice, this list of conditions and the following disclaimer in the
17+ * documentation and/or other materials provided with the distribution.
18+ * 3. All advertising materials mentioning features or use of this software
19+ * must display the following acknowledgement:
20+ * This product includes software developed for the NetBSD Project by
21+ * Wasabi Systems, Inc.
22+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23+ * or promote products derived from this software without specific prior
24+ * written permission.
25+ *
26+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36+ * POSSIBILITY OF SUCH DAMAGE.
37+ */
38+
39+#if HAVE_NBTOOL_CONFIG_H
40+#include "nbtool_config.h"
41+#endif
42+
43+#include <sys/cdefs.h>
44+#if defined(__RCSID) && !defined(__lint)
45+__RCSID("$NetBSD: makefs.c,v 1.59 2024/10/27 18:35:52 christos Exp $");
46+#endif /* !__lint */
47+
48+#include <assert.h>
49+#include <ctype.h>
50+#include <errno.h>
51+#include <limits.h>
52+#include <stdio.h>
53+#include <stdlib.h>
54+#include <string.h>
55+#include <unistd.h>
56+#include <stdbool.h>
57+#include <util.h>
58+
59+#include "makefs.h"
60+#include "mtree.h"
61+#include "cd9660.h"
62+
63+/*
64+ * list of supported file systems and dispatch functions
65+ */
66+typedef struct {
67+ const char *type;
68+ void (*prepare_options)(fsinfo_t *);
69+ int (*parse_options)(const char *, fsinfo_t *);
70+ void (*cleanup_options)(fsinfo_t *);
71+ void (*make_fs)(const char *, const char *, fsnode *,
72+ fsinfo_t *);
73+} fstype_t;
74+
75+static fstype_t fstypes[] = {
76+#define ENTRY(name) { \
77+ # name, name ## _prep_opts, name ## _parse_opts, \
78+ name ## _cleanup_opts, name ## _makefs \
79+}
80+ ENTRY(cd9660),
81+ { .type = NULL },
82+};
83+
84+u_int debug;
85+struct timespec start_time;
86+struct stat stampst;
87+
88+static fstype_t *get_fstype(const char *);
89+static int get_tstamp(const char *, struct stat *);
90+static void usage(fstype_t *, fsinfo_t *) __dead;
91+static u_int parse_debug(char *);
92+
93+int
94+main(int argc, char *argv[])
95+{
96+ struct timeval start;
97+ fstype_t *fstype;
98+ fsinfo_t fsoptions;
99+ fsnode *root;
100+ int ch, i;
101+ size_t len;
102+ char *specfile;
103+
104+ setprogname(argv[0]);
105+
106+ debug = 0;
107+ if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
108+ errx(EXIT_FAILURE,
109+ "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
110+
111+ /* set default fsoptions */
112+ (void)memset(&fsoptions, 0, sizeof(fsoptions));
113+ fsoptions.fd = -1;
114+ fsoptions.sectorsize = -1;
115+
116+ if (fstype->prepare_options)
117+ fstype->prepare_options(&fsoptions);
118+
119+ specfile = NULL;
120+#ifdef CLOCK_REALTIME
121+ ch = clock_gettime(CLOCK_REALTIME, &start_time);
122+#else
123+ ch = gettimeofday(&start, NULL);
124+ start_time.tv_sec = start.tv_sec;
125+ start_time.tv_nsec = start.tv_usec * 1000;
126+#endif
127+ if (ch == -1)
128+ err(EXIT_FAILURE, "Unable to get system time");
129+
130+
131+ while ((ch = getopt(argc, argv, "B:b:d:f:F:LM:m:N:O:o:rs:S:t:T:xZ")) != -1) {
132+ switch (ch) {
133+
134+ case 'B':
135+ if (strcmp(optarg, "be") == 0 ||
136+ strcmp(optarg, "4321") == 0 ||
137+ strcmp(optarg, "big") == 0) {
138+#if BYTE_ORDER == LITTLE_ENDIAN
139+ fsoptions.needswap = 1;
140+#endif
141+ } else if (strcmp(optarg, "le") == 0 ||
142+ strcmp(optarg, "1234") == 0 ||
143+ strcmp(optarg, "little") == 0) {
144+#if BYTE_ORDER == BIG_ENDIAN
145+ fsoptions.needswap = 1;
146+#endif
147+ } else {
148+ warnx("Invalid endian `%s'.", optarg);
149+ usage(fstype, &fsoptions);
150+ }
151+ break;
152+
153+ case 'b':
154+ len = strlen(optarg) - 1;
155+ if (optarg[len] == '%') {
156+ optarg[len] = '\0';
157+ fsoptions.freeblockpc = (int)
158+ strsuftoll("free block percentage",
159+ optarg, 0, 99);
160+ } else {
161+ fsoptions.freeblocks =
162+ strsuftoll("free blocks",
163+ optarg, 0, LLONG_MAX);
164+ }
165+ break;
166+
167+ case 'd':
168+ debug = parse_debug(optarg);
169+ break;
170+
171+ case 'f':
172+ len = strlen(optarg) - 1;
173+ if (optarg[len] == '%') {
174+ optarg[len] = '\0';
175+ fsoptions.freefilepc = (int)
176+ strsuftoll("free file percentage",
177+ optarg, 0, 99);
178+ } else {
179+ fsoptions.freefiles =
180+ strsuftoll("free files",
181+ optarg, 0, LLONG_MAX);
182+ }
183+ break;
184+
185+ case 'F':
186+ specfile = optarg;
187+ break;
188+
189+ case 'L':
190+ fsoptions.follow = true;
191+ break;
192+
193+ case 'M':
194+ fsoptions.minsize =
195+ strsuftoll("minimum size", optarg, 1LL, LLONG_MAX);
196+ break;
197+
198+ case 'N':
199+ if (! setup_getid(optarg))
200+ errx(EXIT_FAILURE,
201+ "Unable to use user and group databases in `%s'",
202+ optarg);
203+ break;
204+
205+ case 'm':
206+ fsoptions.maxsize =
207+ strsuftoll("maximum size", optarg, 1LL, LLONG_MAX);
208+ break;
209+
210+ case 'O':
211+ fsoptions.offset =
212+ strsuftoll("offset", optarg, 0LL, LLONG_MAX);
213+ break;
214+
215+ case 'o':
216+ {
217+ char *p;
218+
219+ while ((p = strsep(&optarg, ",")) != NULL) {
220+ if (*p == '\0')
221+ errx(EXIT_FAILURE, "Empty option");
222+ if (! fstype->parse_options(p, &fsoptions))
223+ usage(fstype, &fsoptions);
224+ }
225+ break;
226+ }
227+
228+ case 'r':
229+ fsoptions.replace = 1;
230+ break;
231+
232+ case 's':
233+ fsoptions.minsize = fsoptions.maxsize =
234+ strsuftoll("size", optarg, 1LL, LLONG_MAX);
235+ break;
236+
237+ case 'S':
238+ fsoptions.sectorsize =
239+ (int)strsuftoll("sector size", optarg,
240+ 1LL, INT_MAX);
241+ break;
242+
243+ case 't':
244+ /* Check current one and cleanup if necessary. */
245+ if (fstype->cleanup_options)
246+ fstype->cleanup_options(&fsoptions);
247+ fsoptions.fs_specific = NULL;
248+ if ((fstype = get_fstype(optarg)) == NULL)
249+ errx(EXIT_FAILURE,
250+ "Unknown fs type `%s'.", optarg);
251+ fstype->prepare_options(&fsoptions);
252+ break;
253+
254+ case 'T':
255+ if (get_tstamp(optarg, &stampst) == -1)
256+ errx(EXIT_FAILURE,
257+ "Cannot get timestamp from `%s'", optarg);
258+ break;
259+
260+ case 'x':
261+ fsoptions.onlyspec++;
262+ break;
263+
264+ case 'Z':
265+ fsoptions.sparse = 1;
266+ break;
267+
268+ case '?':
269+ default:
270+ usage(fstype, &fsoptions);
271+ /* NOTREACHED */
272+
273+ }
274+ }
275+ if (debug) {
276+ printf("debug mask: 0x%08x\n", debug);
277+ printf("start time: %ld.%ld, %s",
278+ (long)start_time.tv_sec, (long)start_time.tv_nsec,
279+ ctime(&start_time.tv_sec));
280+ }
281+ argc -= optind;
282+ argv += optind;
283+
284+ if (argc < 2)
285+ usage(fstype, &fsoptions);
286+
287+ /* -x must be accompanied by -F */
288+ if (fsoptions.onlyspec != 0 && specfile == NULL)
289+ errx(EXIT_FAILURE, "-x requires -F mtree-specfile.");
290+
291+ /* walk the tree */
292+ TIMER_START(start);
293+ root = walk_dir(argv[1], ".", NULL, NULL, fsoptions.replace,
294+ fsoptions.follow);
295+ TIMER_RESULTS(start, "walk_dir");
296+
297+ /* append extra directory */
298+ for (i = 2; i < argc; i++) {
299+ struct stat sb;
300+ if (stat(argv[i], &sb) == -1)
301+ err(EXIT_FAILURE, "Can't stat `%s'", argv[i]);
302+ if (!S_ISDIR(sb.st_mode))
303+ errx(EXIT_FAILURE, "%s: not a directory", argv[i]);
304+ TIMER_START(start);
305+ root = walk_dir(argv[i], ".", NULL, root, fsoptions.replace,
306+ fsoptions.follow);
307+ TIMER_RESULTS(start, "walk_dir2");
308+ }
309+
310+ if (specfile) { /* apply a specfile */
311+ TIMER_START(start);
312+ apply_specfile(specfile, argv[1], root, fsoptions.onlyspec);
313+ TIMER_RESULTS(start, "apply_specfile");
314+ }
315+
316+ if (debug & DEBUG_DUMP_FSNODES) {
317+ printf("\nparent: %s\n", argv[1]);
318+ dump_fsnodes(root);
319+ putchar('\n');
320+ }
321+
322+ /* build the file system */
323+ TIMER_START(start);
324+ fstype->make_fs(argv[0], argv[1], root, &fsoptions);
325+ TIMER_RESULTS(start, "make_fs");
326+
327+ free_fsnodes(root);
328+
329+ exit(EXIT_SUCCESS);
330+ /* NOTREACHED */
331+}
332+
333+int
334+set_option(const option_t *options, const char *option, char *buf, size_t len)
335+{
336+ char *var, *val;
337+ int retval;
338+
339+ assert(option != NULL);
340+
341+ var = estrdup(option);
342+ for (val = var; *val; val++)
343+ if (*val == '=') {
344+ *val++ = '\0';
345+ break;
346+ }
347+ retval = set_option_var(options, var, val, buf, len);
348+ free(var);
349+ return retval;
350+}
351+
352+void
353+print_options(FILE *fp, const option_t *options)
354+{
355+ for (size_t i = 0; options[i].name != NULL; i++) {
356+ fprintf(fp, "%s=", options[i].name);
357+ switch (options[i].type) {
358+ case OPT_BOOL:
359+ fputs(*(bool *)options[i].value ? "true\n" : "false\n",
360+ fp);
361+ break;
362+ case OPT_STRARRAY:
363+ case OPT_STRPTR:
364+ case OPT_STRBUF:
365+ fprintf(fp, "%s\n", *(const char **)options[i].value);
366+ break;
367+ case OPT_INT64:
368+ fprintf(fp, "%" PRIu64 "\n",
369+ *(uint64_t *)options[i].value);
370+ break;
371+ case OPT_INT32:
372+ fprintf(fp, "%" PRIu32 "\n",
373+ *(uint32_t *)options[i].value);
374+ break;
375+ case OPT_INT16:
376+ fprintf(fp, "%" PRIu16 "\n",
377+ *(uint16_t *)options[i].value);
378+ break;
379+ case OPT_INT8:
380+ fprintf(fp, "%" PRIu8 "\n",
381+ *(uint8_t *)options[i].value);
382+ break;
383+ default:
384+ warnx("Unknown type %d in option %s", options[i].type,
385+ options[i].name);
386+ return;
387+ }
388+ }
389+}
390+
391+int
392+set_option_var(const option_t *options, const char *var, const char *val,
393+ char *buf, size_t len)
394+{
395+ char *s;
396+ size_t i;
397+
398+#define NUM(type) \
399+ if (!*val) { \
400+ *(type *)options[i].value = 1; \
401+ break; \
402+ } \
403+ *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \
404+ options[i].minimum, options[i].maximum); break
405+
406+ for (i = 0; options[i].name != NULL; i++) {
407+ if (var[1] == '\0') {
408+ if (options[i].letter != var[0])
409+ continue;
410+ } else if (strcmp(options[i].name, var) != 0)
411+ continue;
412+ switch (options[i].type) {
413+ case OPT_BOOL:
414+ *(bool *)options[i].value = 1;
415+ break;
416+ case OPT_STRARRAY:
417+ strlcpy((void *)options[i].value, val, (size_t)
418+ options[i].maximum);
419+ break;
420+ case OPT_STRPTR:
421+ s = estrdup(val);
422+ *(char **)options[i].value = s;
423+ break;
424+ case OPT_STRBUF:
425+ if (buf == NULL)
426+ abort();
427+ strlcpy(buf, val, len);
428+ break;
429+ case OPT_INT64:
430+ NUM(uint64_t);
431+ case OPT_INT32:
432+ NUM(uint32_t);
433+ case OPT_INT16:
434+ NUM(uint16_t);
435+ case OPT_INT8:
436+ NUM(uint8_t);
437+ default:
438+ warnx("Unknown type %d in option %s", options[i].type,
439+ val);
440+ return 0;
441+ }
442+ return (int)i;
443+ }
444+ warnx("Unknown option `%s'", var);
445+ return -1;
446+}
447+
448+
449+static fstype_t *
450+get_fstype(const char *type)
451+{
452+ int i;
453+
454+ for (i = 0; fstypes[i].type != NULL; i++)
455+ if (strcmp(fstypes[i].type, type) == 0)
456+ return (&fstypes[i]);
457+ return (NULL);
458+}
459+
460+option_t *
461+copy_opts(const option_t *o)
462+{
463+ size_t i;
464+ for (i = 0; o[i].name; i++)
465+ continue;
466+ i++;
467+ return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o));
468+}
469+
470+static int
471+get_tstamp(const char *b, struct stat *st)
472+{
473+ time_t when;
474+ char *eb;
475+ long long l;
476+
477+ if (stat(b, st) != -1)
478+ return 0;
479+
480+#ifndef HAVE_NBTOOL_CONFIG_H
481+ errno = 0;
482+ if ((when = parsedate(b, NULL, NULL)) == -1 && errno != 0)
483+#endif
484+ {
485+ errno = 0;
486+ l = strtoll(b, &eb, 0);
487+ if (b == eb || *eb || errno)
488+ return -1;
489+ when = (time_t)l;
490+ }
491+
492+ st->st_ino = 1;
493+#if HAVE_STRUCT_STAT_BIRTHTIME
494+ st->st_birthtime =
495+#endif
496+ st->st_mtime = st->st_ctime = st->st_atime = when;
497+ return 0;
498+}
499+
500+static struct {
501+ const char *n;
502+ u_int v;
503+} nv[] = {
504+ DEBUG_STRINGS
505+};
506+
507+static void
508+usage(fstype_t *fstype, fsinfo_t *fsoptions)
509+{
510+ const char *prog;
511+
512+ prog = getprogname();
513+ fprintf(stderr,
514+"Usage: %s [-rxZ] [-B endian] [-b free-blocks] [-d debug-mask|comma-separated-option]\n"
515+"\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n"
516+"\t[-N userdb-dir] [-O offset] [-o fs-options] [-S sector-size]\n"
517+"\t[-s image-size] [-T <timestamp/file>] [-t fs-type]"
518+" image-file directory [extra-directory ...]\n",
519+ prog);
520+
521+ fprintf(stderr, "\nDebugging options:\n");
522+ for (size_t i = 0; i < __arraycount(nv); i++)
523+ fprintf(stderr, "\t0x%8.8x\t%s\n", nv[i].v, nv[i].n);
524+
525+ if (fstype) {
526+ size_t i;
527+ option_t *o = fsoptions->fs_options;
528+
529+ fprintf(stderr, "\n%s specific options:\n", fstype->type);
530+ for (i = 0; o[i].name != NULL; i++)
531+ fprintf(stderr, "\t%c%c%20.20s\t%s\n",
532+ o[i].letter ? o[i].letter : ' ',
533+ o[i].letter ? ',' : ' ',
534+ o[i].name, o[i].desc);
535+ }
536+ exit(EXIT_FAILURE);
537+}
538+
539+
540+static u_int
541+parse_debug(char *str)
542+{
543+ char *ep;
544+ u_int d;
545+ size_t i;
546+
547+ errno = 0;
548+ d = (u_int)strtoul(str, &ep, 0);
549+ if (str != ep && !*ep && errno == 0)
550+ return d;
551+ d = 0;
552+ for (char *a = strtok(str, ","); a != NULL; a = strtok(NULL, ",")) {
553+ for (i = 0; i < __arraycount(nv); i++)
554+ if (strcmp(nv[i].n, a) == 0) {
555+ d |= nv[i].v;
556+ break;
557+ }
558+ if (i == __arraycount(nv))
559+ errx(EXIT_FAILURE, "Unknown debug option `%s'", a);
560+ }
561+ return d;
562+}
+303,
-0
1@@ -0,0 +1,303 @@
2+/* $nEtBSD: makefs.h,v 1.38 2022/04/09 10:05:35 riastradh Exp $ */
3+
4+/*
5+ * Copyright (c) 2001 Wasabi Systems, Inc.
6+ * All rights reserved.
7+ *
8+ * Written by Luke Mewburn for Wasabi Systems, Inc.
9+ *
10+ * Redistribution and use in source and binary forms, with or without
11+ * modification, are permitted provided that the following conditions
12+ * are met:
13+ * 1. Redistributions of source code must retain the above copyright
14+ * notice, this list of conditions and the following disclaimer.
15+ * 2. Redistributions in binary form must reproduce the above copyright
16+ * notice, this list of conditions and the following disclaimer in the
17+ * documentation and/or other materials provided with the distribution.
18+ * 3. All advertising materials mentioning features or use of this software
19+ * must display the following acknowledgement:
20+ * This product includes software developed for the NetBSD Project by
21+ * Wasabi Systems, Inc.
22+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23+ * or promote products derived from this software without specific prior
24+ * written permission.
25+ *
26+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36+ * POSSIBILITY OF SUCH DAMAGE.
37+ */
38+
39+#ifndef _MAKEFS_H
40+#define _MAKEFS_H
41+
42+#if HAVE_NBTOOL_CONFIG_H
43+#include "nbtool_config.h"
44+#else
45+#define HAVE_STRUCT_STAT_ST_FLAGS 1
46+#define HAVE_STRUCT_STAT_ST_GEN 1
47+#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1
48+#define HAVE_STRUCT_STATVFS_F_IOSIZE 1
49+#define HAVE_STRUCT_STAT_BIRTHTIME 1
50+#define HAVE_FSTATVFS 1
51+#endif
52+
53+#include <stdio.h>
54+#include <sys/stat.h>
55+#include <err.h>
56+
57+/*
58+ * fsnode -
59+ * a component of the tree; contains a filename, a pointer to
60+ * fsinode, optional symlink name, and tree pointers
61+ *
62+ * fsinode -
63+ * equivalent to an inode, containing target file system inode number,
64+ * refcount (nlink), and stat buffer
65+ *
66+ * A tree of fsnodes looks like this:
67+ *
68+ * name "." "bin" "netbsd"
69+ * type S_IFDIR S_IFDIR S_IFREG
70+ * next > > NULL
71+ * parent NULL NULL NULL
72+ * child NULL v
73+ *
74+ * name "." "ls"
75+ * type S_IFDIR S_IFREG
76+ * next > NULL
77+ * parent ^ ^ (to "bin")
78+ * child NULL NULL
79+ *
80+ * Notes:
81+ * - first always points to first entry, at current level, which
82+ * must be "." when the tree has been built; during build it may
83+ * not be if "." hasn't yet been found by readdir(2).
84+ */
85+
86+enum fi_flags {
87+ FI_SIZED = 1<<0, /* inode sized */
88+ FI_ALLOCATED = 1<<1, /* fsinode->ino allocated */
89+ FI_WRITTEN = 1<<2, /* inode written */
90+};
91+
92+typedef struct {
93+ uint64_t ino; /* inode number used on target fs */
94+ uint32_t nlink; /* number of links to this entry */
95+ enum fi_flags flags; /* flags used by fs specific code */
96+ struct stat st; /* stat entry */
97+ void *fsuse; /* for storing FS dependent info */
98+#if !HAVE_STRUCT_STAT_ST_FLAGS
99+ uint32_t st_flags; /* stand-in for st.st_flags */
100+#endif
101+} fsinode;
102+
103+#if HAVE_STRUCT_STAT_ST_FLAGS
104+#define FSINODE_ST_FLAGS(inode) (inode).st.st_flags
105+#else
106+#define FSINODE_ST_FLAGS(inode) (inode).st_flags
107+#endif
108+
109+typedef struct _fsnode {
110+ struct _fsnode *parent; /* parent (NULL if root) */
111+ struct _fsnode *child; /* child (if type == S_IFDIR) */
112+ struct _fsnode *next; /* next */
113+ struct _fsnode *first; /* first node of current level (".") */
114+ uint32_t type; /* type of entry */
115+ fsinode *inode; /* actual inode data */
116+ char *symlink; /* symlink target */
117+ const char *root; /* root path */
118+ char *path; /* directory name */
119+ char *name; /* file name */
120+ int flags; /* misc flags */
121+} fsnode;
122+
123+#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */
124+
125+/*
126+ * option_t - contains option name, description, pointer to location to store
127+ * result, and range checks for the result. Used to simplify fs specific
128+ * option setting
129+ */
130+typedef enum {
131+ OPT_STRARRAY,
132+ OPT_STRPTR,
133+ OPT_STRBUF,
134+ OPT_BOOL,
135+ OPT_INT8,
136+ OPT_INT16,
137+ OPT_INT32,
138+ OPT_INT64
139+} opttype_t;
140+
141+typedef struct {
142+ char letter; /* option letter NUL for none */
143+ const char *name; /* option name */
144+ void *value; /* where to stuff the value */
145+ opttype_t type; /* type of entry */
146+ long long minimum; /* minimum for value */
147+ long long maximum; /* maximum for value */
148+ const char *desc; /* option description */
149+} option_t;
150+
151+/*
152+ * fsinfo_t - contains various settings and parameters pertaining to
153+ * the image, including current settings, global options, and fs
154+ * specific options
155+ */
156+typedef struct makefs_fsinfo {
157+ /* current settings */
158+ off_t size; /* total size */
159+ off_t inodes; /* number of inodes */
160+ uint32_t curinode; /* current inode */
161+
162+ /* image settings */
163+ int fd; /* file descriptor of image */
164+ void *superblock; /* superblock */
165+ int onlyspec; /* only add entries in specfile */
166+
167+
168+ /* global options */
169+ off_t minsize; /* minimum size image should be */
170+ off_t maxsize; /* maximum size image can be */
171+ off_t freefiles; /* free file entries to leave */
172+ off_t freeblocks; /* free blocks to leave */
173+ off_t offset; /* offset from start of file */
174+ int freefilepc; /* free file % */
175+ int freeblockpc; /* free block % */
176+ int needswap; /* non-zero if byte swapping needed */
177+ int sectorsize; /* sector size */
178+ int sparse; /* sparse image, don't fill it with zeros */
179+ int replace; /* replace files when merging */
180+ int follow; /* follow symlinks */
181+
182+ void *fs_specific; /* File system specific additions. */
183+ option_t *fs_options; /* File system specific options */
184+} fsinfo_t;
185+
186+
187+
188+
189+void apply_specfile(const char *, const char *, fsnode *, int);
190+void dump_fsnodes(fsnode *);
191+const char * inode_type(mode_t);
192+int set_option(const option_t *, const char *, char *, size_t);
193+void print_options(FILE *, const option_t *);
194+int set_option_var(const option_t *, const char *, const char *,
195+ char *, size_t);
196+fsnode * walk_dir(const char *, const char *, fsnode *, fsnode *, int,
197+ int);
198+void free_fsnodes(fsnode *);
199+option_t * copy_opts(const option_t *);
200+
201+#define DECLARE_FUN(fs) \
202+void fs ## _prep_opts(fsinfo_t *); \
203+int fs ## _parse_opts(const char *, fsinfo_t *); \
204+void fs ## _cleanup_opts(fsinfo_t *); \
205+void fs ## _makefs(const char *, const char *, fsnode *, fsinfo_t *)
206+
207+DECLARE_FUN(cd9660);
208+
209+extern u_int debug;
210+extern struct timespec start_time;
211+extern struct stat stampst;
212+
213+/*
214+ * If -x is specified, we want to exclude nodes which do not appear
215+ * in the spec file.
216+ */
217+#define FSNODE_EXCLUDE_P(opts, fsnode) \
218+ ((opts)->onlyspec != 0 && ((fsnode)->flags & FSNODE_F_HASSPEC) == 0)
219+
220+#define DEBUG_TIME 0x00000001
221+ /* debug bits 1..3 unused at this time */
222+#define DEBUG_WALK_DIR 0x00000010
223+#define DEBUG_WALK_DIR_NODE 0x00000020
224+#define DEBUG_WALK_DIR_LINKCHECK 0x00000040
225+#define DEBUG_DUMP_FSNODES 0x00000080
226+#define DEBUG_DUMP_FSNODES_VERBOSE 0x00000100
227+#define DEBUG_FS_PARSE_OPTS 0x00000200
228+#define DEBUG_FS_MAKEFS 0x00000400
229+#define DEBUG_FS_VALIDATE 0x00000800
230+#define DEBUG_FS_CREATE_IMAGE 0x00001000
231+#define DEBUG_FS_SIZE_DIR 0x00002000
232+#define DEBUG_FS_SIZE_DIR_NODE 0x00004000
233+#define DEBUG_FS_SIZE_DIR_ADD_DIRENT 0x00008000
234+#define DEBUG_FS_POPULATE 0x00010000
235+#define DEBUG_FS_POPULATE_DIRBUF 0x00020000
236+#define DEBUG_FS_POPULATE_NODE 0x00040000
237+#define DEBUG_FS_WRITE_FILE 0x00080000
238+#define DEBUG_FS_WRITE_FILE_BLOCK 0x00100000
239+#define DEBUG_FS_MAKE_DIRBUF 0x00200000
240+#define DEBUG_FS_WRITE_INODE 0x00400000
241+#define DEBUG_BUF_BREAD 0x00800000
242+#define DEBUG_BUF_BWRITE 0x01000000
243+#define DEBUG_BUF_GETBLK 0x02000000
244+#define DEBUG_APPLY_SPECFILE 0x04000000
245+#define DEBUG_APPLY_SPECENTRY 0x08000000
246+#define DEBUG_APPLY_SPECONLY 0x10000000
247+
248+#define DEBUG_STRINGS \
249+ { "time", DEBUG_TIME }, \
250+ { "walk_dir", DEBUG_WALK_DIR }, \
251+ { "walk_dir_node", DEBUG_WALK_DIR_NODE }, \
252+ { "walk_dir_linkcheck", DEBUG_WALK_DIR_LINKCHECK }, \
253+ { "dump_fsnodes", DEBUG_DUMP_FSNODES }, \
254+ { "dump_fsnodes_verbose", DEBUG_DUMP_FSNODES_VERBOSE }, \
255+ { "fs_parse_opts", DEBUG_FS_PARSE_OPTS }, \
256+ { "fs_makefs", DEBUG_FS_MAKEFS }, \
257+ { "fs_validate", DEBUG_FS_VALIDATE }, \
258+ { "fs_create_image", DEBUG_FS_CREATE_IMAGE }, \
259+ { "fs_size_dir", DEBUG_FS_SIZE_DIR }, \
260+ { "fs_size_dir_node", DEBUG_FS_SIZE_DIR_NODE }, \
261+ { "fs_size_dir_add_dirent", DEBUG_FS_SIZE_DIR_ADD_DIRENT }, \
262+ { "fs_populate", DEBUG_FS_POPULATE }, \
263+ { "fs_populate_dirbuf", DEBUG_FS_POPULATE_DIRBUF }, \
264+ { "fs_populate_node", DEBUG_FS_POPULATE_NODE }, \
265+ { "fs_write_file", DEBUG_FS_WRITE_FILE }, \
266+ { "fs_write_file_block", DEBUG_FS_WRITE_FILE_BLOCK }, \
267+ { "fs_make_dirbuf", DEBUG_FS_MAKE_DIRBUF }, \
268+ { "fs_write_inode", DEBUG_FS_WRITE_INODE }, \
269+ { "buf_bread", DEBUG_BUF_BREAD }, \
270+ { "buf_bwrite", DEBUG_BUF_BWRITE }, \
271+ { "buf_getblk", DEBUG_BUF_GETBLK }, \
272+ { "apply_specfile", DEBUG_APPLY_SPECFILE }, \
273+ { "apply_specentry", DEBUG_APPLY_SPECENTRY }, \
274+ { "apply_speconly", DEBUG_APPLY_SPECONLY },
275+
276+#define TIMER_START(x) \
277+ if (debug & DEBUG_TIME) \
278+ gettimeofday(&(x), NULL)
279+
280+#define TIMER_RESULTS(x,d) \
281+ if (debug & DEBUG_TIME) { \
282+ struct timeval end, td; \
283+ gettimeofday(&end, NULL); \
284+ timersub(&end, &(x), &td); \
285+ printf("%s took %lld.%06ld seconds\n", \
286+ (d), (long long)td.tv_sec, \
287+ (long)td.tv_usec); \
288+ }
289+
290+
291+#ifndef DEFAULT_FSTYPE
292+#define DEFAULT_FSTYPE "cd9660"
293+#endif
294+
295+
296+/*
297+ * ffs specific settings
298+ * ---------------------
299+ */
300+
301+#define FFS_EI /* for opposite endian support in ffs headers */
302+
303+
304+#endif /* _MAKEFS_H */
+97,
-0
1@@ -0,0 +1,97 @@
2+/* $NetBSD: extern.h,v 1.41 2024/12/05 17:17:43 christos Exp $ */
3+
4+/*-
5+ * Copyright (c) 1991, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ *
32+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
33+ */
34+
35+#include "mtree.h"
36+
37+#if HAVE_NBTOOL_CONFIG_H
38+#include "nbtool_config.h"
39+#else
40+#define HAVE_STRUCT_STAT_ST_FLAGS 1
41+#endif
42+
43+#include <err.h>
44+#include <fts.h>
45+#include <util.h>
46+#include <stdbool.h>
47+
48+#if HAVE_NETDB_H
49+/* For MAXHOSTNAMELEN on some platforms. */
50+#include <netdb.h>
51+#endif
52+
53+#if defined(__FreeBSD__) && !defined(HAVE_NBTOOL_CONFIG_H)
54+#define FTS_CONST const
55+#else
56+#define FTS_CONST
57+#endif
58+
59+#ifndef MAXHOSTNAMELEN
60+#define MAXHOSTNAMELEN 256
61+#endif
62+
63+enum flavor {
64+ F_MTREE,
65+ F_FREEBSD9,
66+ F_NETBSD6
67+};
68+
69+void addtag(slist_t *, char *);
70+int check_excludes(const char *, const char *);
71+int compare(NODE *, FTSENT *);
72+int crc(int, uint32_t *, uint32_t *);
73+void cwalk(FILE *);
74+int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
75+void dump_nodes(FILE *, const char *, NODE *, int);
76+void init_excludes(void);
77+int matchtags(NODE *);
78+__dead __printflike(1,2) void mtree_err(const char *, ...);
79+const char *nodetype(u_int);
80+u_int parsekey(const char *, int *);
81+void parsetags(slist_t *, char *);
82+u_int parsetype(const char *);
83+void read_excludes_file(const char *);
84+const char *rlink(const char *);
85+int verify(FILE *);
86+void load_only(const char *fname);
87+bool find_only(const char *path);
88+
89+extern int bflag, dflag, eflag, iflag, jflag, lflag, mflag,
90+ nflag, qflag, rflag, sflag, tflag, uflag;
91+extern int mtree_Mflag, mtree_Sflag, mtree_Wflag;
92+extern size_t mtree_lineno;
93+extern enum flavor flavor;
94+extern uint32_t crc_total;
95+extern int ftsoptions, keys;
96+extern char fullpath[];
97+extern slist_t includetags, excludetags;
98+
+446,
-0
1@@ -0,0 +1,446 @@
2+/* $NetBSD: getid.c,v 1.10 2014/10/27 21:46:45 christos Exp $ */
3+/* from: NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp */
4+/* from: NetBSD: getgrent.c,v 1.41 2002/01/12 23:51:30 lukem Exp */
5+
6+/*
7+ * Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995
8+ * The Regents of the University of California. All rights reserved.
9+ *
10+ * Redistribution and use in source and binary forms, with or without
11+ * modification, are permitted provided that the following conditions
12+ * are met:
13+ * 1. Redistributions of source code must retain the above copyright
14+ * notice, this list of conditions and the following disclaimer.
15+ * 2. Redistributions in binary form must reproduce the above copyright
16+ * notice, this list of conditions and the following disclaimer in the
17+ * documentation and/or other materials provided with the distribution.
18+ * 3. Neither the name of the University nor the names of its contributors
19+ * may be used to endorse or promote products derived from this software
20+ * without specific prior written permission.
21+ *
22+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32+ * SUCH DAMAGE.
33+ */
34+
35+/*-
36+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
37+ * All rights reserved.
38+ *
39+ * This code is derived from software contributed to The NetBSD Foundation
40+ * by Luke Mewburn of Wasabi Systems.
41+ *
42+ * Redistribution and use in source and binary forms, with or without
43+ * modification, are permitted provided that the following conditions
44+ * are met:
45+ * 1. Redistributions of source code must retain the above copyright
46+ * notice, this list of conditions and the following disclaimer.
47+ * 2. Redistributions in binary form must reproduce the above copyright
48+ * notice, this list of conditions and the following disclaimer in the
49+ * documentation and/or other materials provided with the distribution.
50+ *
51+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
52+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
55+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61+ * POSSIBILITY OF SUCH DAMAGE.
62+ */
63+
64+#if HAVE_NBTOOL_CONFIG_H
65+#include "nbtool_config.h"
66+#endif
67+
68+#include <sys/cdefs.h>
69+__RCSID("$NetBSD: getid.c,v 1.10 2014/10/27 21:46:45 christos Exp $");
70+
71+#include <sys/param.h>
72+
73+#include <grp.h>
74+#include <limits.h>
75+#include <pwd.h>
76+#include <stdlib.h>
77+#include <stdio.h>
78+#include <string.h>
79+#include <time.h>
80+#include <unistd.h>
81+
82+#include "extern.h"
83+
84+static struct group * gi_getgrnam(const char *);
85+static struct group * gi_getgrgid(gid_t);
86+static int gi_setgroupent(int);
87+static void gi_endgrent(void);
88+static int grstart(void);
89+static int grscan(int, gid_t, const char *);
90+static int grmatchline(int, gid_t, const char *);
91+
92+static struct passwd * gi_getpwnam(const char *);
93+static struct passwd * gi_getpwuid(uid_t);
94+static int gi_setpassent(int);
95+static void gi_endpwent(void);
96+static int pwstart(void);
97+static int pwscan(int, uid_t, const char *);
98+static int pwmatchline(int, uid_t, const char *);
99+
100+#define MAXGRP 200
101+#define MAXLINELENGTH 1024
102+
103+static FILE *_gr_fp;
104+static struct group _gr_group;
105+static int _gr_stayopen;
106+static int _gr_filesdone;
107+static FILE *_pw_fp;
108+static struct passwd _pw_passwd; /* password structure */
109+static int _pw_stayopen; /* keep fd's open */
110+static int _pw_filesdone;
111+
112+static char grfile[MAXPATHLEN];
113+static char pwfile[MAXPATHLEN];
114+
115+static char *members[MAXGRP];
116+static char grline[MAXLINELENGTH];
117+static char pwline[MAXLINELENGTH];
118+
119+int
120+setup_getid(const char *dir)
121+{
122+ if (dir == NULL)
123+ return (0);
124+
125+ /* close existing databases */
126+ gi_endgrent();
127+ gi_endpwent();
128+
129+ /* build paths to new databases */
130+ snprintf(grfile, sizeof(grfile), "%s/group", dir);
131+ snprintf(pwfile, sizeof(pwfile), "%s/master.passwd", dir);
132+
133+ /* try to open new databases */
134+ if (!grstart() || !pwstart())
135+ return (0);
136+
137+ /* switch pwcache(3) lookup functions */
138+ if (pwcache_groupdb(gi_setgroupent, gi_endgrent,
139+ gi_getgrnam, gi_getgrgid) == -1
140+ || pwcache_userdb(gi_setpassent, gi_endpwent,
141+ gi_getpwnam, gi_getpwuid) == -1)
142+ return (0);
143+
144+ return (1);
145+}
146+
147+
148+/*
149+ * group lookup functions
150+ */
151+
152+static struct group *
153+gi_getgrnam(const char *name)
154+{
155+ int rval;
156+
157+ if (!grstart())
158+ return NULL;
159+ rval = grscan(1, 0, name);
160+ if (!_gr_stayopen)
161+ endgrent();
162+ return (rval) ? &_gr_group : NULL;
163+}
164+
165+static struct group *
166+gi_getgrgid(gid_t gid)
167+{
168+ int rval;
169+
170+ if (!grstart())
171+ return NULL;
172+ rval = grscan(1, gid, NULL);
173+ if (!_gr_stayopen)
174+ endgrent();
175+ return (rval) ? &_gr_group : NULL;
176+}
177+
178+static int
179+gi_setgroupent(int stayopen)
180+{
181+
182+ if (!grstart())
183+ return 0;
184+ _gr_stayopen = stayopen;
185+ return 1;
186+}
187+
188+static void
189+gi_endgrent(void)
190+{
191+
192+ _gr_filesdone = 0;
193+ if (_gr_fp) {
194+ (void)fclose(_gr_fp);
195+ _gr_fp = NULL;
196+ }
197+}
198+
199+static int
200+grstart(void)
201+{
202+
203+ _gr_filesdone = 0;
204+ if (_gr_fp) {
205+ rewind(_gr_fp);
206+ return 1;
207+ }
208+ if (grfile[0] == '\0') /* sanity check */
209+ return 0;
210+
211+ _gr_fp = fopen(grfile, "r");
212+ if (_gr_fp != NULL)
213+ return 1;
214+ warn("Can't open `%s'", grfile);
215+ return 0;
216+}
217+
218+
219+static int
220+grscan(int search, gid_t gid, const char *name)
221+{
222+
223+ if (_gr_filesdone)
224+ return 0;
225+ for (;;) {
226+ if (!fgets(grline, sizeof(grline), _gr_fp)) {
227+ if (!search)
228+ _gr_filesdone = 1;
229+ return 0;
230+ }
231+ /* skip lines that are too big */
232+ if (!strchr(grline, '\n')) {
233+ int ch;
234+
235+ while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
236+ ;
237+ continue;
238+ }
239+ /* skip comments */
240+ if (grline[0] == '#')
241+ continue;
242+ if (grmatchline(search, gid, name))
243+ return 1;
244+ }
245+ /* NOTREACHED */
246+}
247+
248+static int
249+grmatchline(int search, gid_t gid, const char *name)
250+{
251+ unsigned long id;
252+ char **m;
253+ char *cp, *bp, *ep;
254+
255+ /* name may be NULL if search is nonzero */
256+
257+ bp = grline;
258+ memset(&_gr_group, 0, sizeof(_gr_group));
259+ _gr_group.gr_name = strsep(&bp, ":\n");
260+ if (search && name && strcmp(_gr_group.gr_name, name))
261+ return 0;
262+ _gr_group.gr_passwd = strsep(&bp, ":\n");
263+ if (!(cp = strsep(&bp, ":\n")))
264+ return 0;
265+ id = strtoul(cp, &ep, 10);
266+ if (id > GID_MAX || *ep != '\0')
267+ return 0;
268+ _gr_group.gr_gid = (gid_t)id;
269+ if (search && name == NULL && _gr_group.gr_gid != gid)
270+ return 0;
271+ cp = NULL;
272+ if (bp == NULL)
273+ return 0;
274+ for (_gr_group.gr_mem = m = members;; bp++) {
275+ if (m == &members[MAXGRP - 1])
276+ break;
277+ if (*bp == ',') {
278+ if (cp) {
279+ *bp = '\0';
280+ *m++ = cp;
281+ cp = NULL;
282+ }
283+ } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
284+ if (cp) {
285+ *bp = '\0';
286+ *m++ = cp;
287+ }
288+ break;
289+ } else if (cp == NULL)
290+ cp = bp;
291+ }
292+ *m = NULL;
293+ return 1;
294+}
295+
296+
297+/*
298+ * user lookup functions
299+ */
300+
301+static struct passwd *
302+gi_getpwnam(const char *name)
303+{
304+ int rval;
305+
306+ if (!pwstart())
307+ return NULL;
308+ rval = pwscan(1, 0, name);
309+ if (!_pw_stayopen)
310+ endpwent();
311+ return (rval) ? &_pw_passwd : NULL;
312+}
313+
314+static struct passwd *
315+gi_getpwuid(uid_t uid)
316+{
317+ int rval;
318+
319+ if (!pwstart())
320+ return NULL;
321+ rval = pwscan(1, uid, NULL);
322+ if (!_pw_stayopen)
323+ endpwent();
324+ return (rval) ? &_pw_passwd : NULL;
325+}
326+
327+static int
328+gi_setpassent(int stayopen)
329+{
330+
331+ if (!pwstart())
332+ return 0;
333+ _pw_stayopen = stayopen;
334+ return 1;
335+}
336+
337+static void
338+gi_endpwent(void)
339+{
340+
341+ _pw_filesdone = 0;
342+ if (_pw_fp) {
343+ (void)fclose(_pw_fp);
344+ _pw_fp = NULL;
345+ }
346+}
347+
348+static int
349+pwstart(void)
350+{
351+
352+ _pw_filesdone = 0;
353+ if (_pw_fp) {
354+ rewind(_pw_fp);
355+ return 1;
356+ }
357+ if (pwfile[0] == '\0') /* sanity check */
358+ return 0;
359+ _pw_fp = fopen(pwfile, "r");
360+ if (_pw_fp != NULL)
361+ return 1;
362+ warn("Can't open `%s'", pwfile);
363+ return 0;
364+}
365+
366+
367+static int
368+pwscan(int search, uid_t uid, const char *name)
369+{
370+
371+ if (_pw_filesdone)
372+ return 0;
373+ for (;;) {
374+ if (!fgets(pwline, sizeof(pwline), _pw_fp)) {
375+ if (!search)
376+ _pw_filesdone = 1;
377+ return 0;
378+ }
379+ /* skip lines that are too big */
380+ if (!strchr(pwline, '\n')) {
381+ int ch;
382+
383+ while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
384+ ;
385+ continue;
386+ }
387+ /* skip comments */
388+ if (pwline[0] == '#')
389+ continue;
390+ if (pwmatchline(search, uid, name))
391+ return 1;
392+ }
393+ /* NOTREACHED */
394+}
395+
396+static int
397+pwmatchline(int search, uid_t uid, const char *name)
398+{
399+ unsigned long id;
400+ char *cp, *bp, *ep;
401+
402+ /* name may be NULL if search is nonzero */
403+
404+ bp = pwline;
405+ memset(&_pw_passwd, 0, sizeof(_pw_passwd));
406+ _pw_passwd.pw_name = strsep(&bp, ":\n"); /* name */
407+ if (search && name && strcmp(_pw_passwd.pw_name, name))
408+ return 0;
409+
410+ _pw_passwd.pw_passwd = strsep(&bp, ":\n"); /* passwd */
411+
412+ if (!(cp = strsep(&bp, ":\n"))) /* uid */
413+ return 0;
414+ id = strtoul(cp, &ep, 10);
415+ if (id > UID_MAX || *ep != '\0')
416+ return 0;
417+ _pw_passwd.pw_uid = (uid_t)id;
418+ if (search && name == NULL && _pw_passwd.pw_uid != uid)
419+ return 0;
420+
421+ if (!(cp = strsep(&bp, ":\n"))) /* gid */
422+ return 0;
423+ id = strtoul(cp, &ep, 10);
424+ if (id > GID_MAX || *ep != '\0')
425+ return 0;
426+ _pw_passwd.pw_gid = (gid_t)id;
427+
428+ if (!(ep = strsep(&bp, ":"))) /* class */
429+ return 0;
430+ if (!(ep = strsep(&bp, ":"))) /* change */
431+ return 0;
432+ if (!(ep = strsep(&bp, ":"))) /* expire */
433+ return 0;
434+
435+ if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n"))) /* gecos */
436+ return 0;
437+ if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n"))) /* directory */
438+ return 0;
439+ if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n"))) /* shell */
440+ return 0;
441+
442+ if (strchr(bp, ':') != NULL)
443+ return 0;
444+
445+ return 1;
446+}
447+
+312,
-0
1@@ -0,0 +1,312 @@
2+/* $NetBSD: misc.c,v 1.35 2024/12/05 17:17:43 christos Exp $ */
3+
4+/*-
5+ * Copyright (c) 1991, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ *
32+ * @(#)misc.c 8.1 (Berkeley) 6/6/93
33+ */
34+
35+#if HAVE_NBTOOL_CONFIG_H
36+#include "nbtool_config.h"
37+#endif
38+
39+#include <sys/cdefs.h>
40+#if defined(__RCSID) && !defined(lint)
41+__RCSID("$NetBSD: misc.c,v 1.35 2024/12/05 17:17:43 christos Exp $");
42+#endif /* not lint */
43+
44+#include <sys/types.h>
45+#include <sys/stat.h>
46+
47+#include <stdarg.h>
48+#include <stdio.h>
49+#include <stdlib.h>
50+#include <string.h>
51+
52+#include "extern.h"
53+
54+enum flavor flavor = F_MTREE;
55+
56+typedef struct _key {
57+ const char *name; /* key name */
58+ u_int val; /* value */
59+
60+#define NEEDVALUE 0x01
61+ u_int flags;
62+} KEY;
63+
64+/* NB: the following tables must be sorted lexically. */
65+static KEY keylist[] = {
66+ {"cksum", F_CKSUM, NEEDVALUE},
67+ {"device", F_DEV, NEEDVALUE},
68+ {"flags", F_FLAGS, NEEDVALUE},
69+ {"gid", F_GID, NEEDVALUE},
70+ {"gname", F_GNAME, NEEDVALUE},
71+ {"ignore", F_IGN, 0},
72+ {"link", F_SLINK, NEEDVALUE},
73+ {"md5", F_MD5, NEEDVALUE},
74+ {"md5digest", F_MD5, NEEDVALUE},
75+ {"mode", F_MODE, NEEDVALUE},
76+ {"nlink", F_NLINK, NEEDVALUE},
77+ {"nochange", F_NOCHANGE, 0},
78+ {"optional", F_OPT, 0},
79+ {"ripemd160digest", F_RMD160, NEEDVALUE},
80+ {"rmd160", F_RMD160, NEEDVALUE},
81+ {"rmd160digest",F_RMD160, NEEDVALUE},
82+ {"sha1", F_SHA1, NEEDVALUE},
83+ {"sha1digest", F_SHA1, NEEDVALUE},
84+ {"sha256", F_SHA256, NEEDVALUE},
85+ {"sha256digest",F_SHA256, NEEDVALUE},
86+ {"sha384", F_SHA384, NEEDVALUE},
87+ {"sha384digest",F_SHA384, NEEDVALUE},
88+ {"sha512", F_SHA512, NEEDVALUE},
89+ {"sha512digest",F_SHA512, NEEDVALUE},
90+ {"size", F_SIZE, NEEDVALUE},
91+ {"tags", F_TAGS, NEEDVALUE},
92+ {"time", F_TIME, NEEDVALUE},
93+ {"type", F_TYPE, NEEDVALUE},
94+ {"uid", F_UID, NEEDVALUE},
95+ {"uname", F_UNAME, NEEDVALUE}
96+};
97+
98+static KEY typelist[] = {
99+ {"block", F_BLOCK, 0},
100+ {"char", F_CHAR, 0},
101+ {"dir", F_DIR, 0},
102+#ifdef S_IFDOOR
103+ {"door", F_DOOR, 0},
104+#endif
105+ {"fifo", F_FIFO, 0},
106+ {"file", F_FILE, 0},
107+ {"link", F_LINK, 0},
108+ {"socket", F_SOCK, 0},
109+};
110+
111+slist_t excludetags, includetags;
112+int keys = KEYDEFAULT;
113+
114+
115+static int keycompare(const void *, const void *);
116+
117+u_int
118+parsekey(const char *name, int *needvaluep)
119+{
120+ static int allbits;
121+ KEY *k, tmp;
122+
123+ if (allbits == 0) {
124+ size_t i;
125+
126+ for (i = 0; i < sizeof(keylist) / sizeof(KEY); i++)
127+ allbits |= keylist[i].val;
128+ }
129+ tmp.name = name;
130+ if (strcmp(name, "all") == 0)
131+ return (allbits);
132+ k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
133+ sizeof(KEY), keycompare);
134+ if (k == NULL)
135+ mtree_err("unknown keyword `%s'", name);
136+
137+ if (needvaluep)
138+ *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
139+
140+ return (k->val);
141+}
142+
143+u_int
144+parsetype(const char *name)
145+{
146+ KEY *k, tmp;
147+
148+ tmp.name = name;
149+ k = (KEY *)bsearch(&tmp, typelist, sizeof(typelist) / sizeof(KEY),
150+ sizeof(KEY), keycompare);
151+ if (k == NULL)
152+ mtree_err("unknown file type `%s'", name);
153+
154+ return (k->val);
155+}
156+
157+static int
158+keycompare(const void *a, const void *b)
159+{
160+
161+ return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name));
162+}
163+
164+void
165+mtree_err(const char *fmt, ...)
166+{
167+ va_list ap;
168+
169+ va_start(ap, fmt);
170+ vwarnx(fmt, ap);
171+ va_end(ap);
172+ if (mtree_lineno)
173+ warnx("failed at line %lu of the specification",
174+ (u_long) mtree_lineno);
175+ exit(1);
176+ /* NOTREACHED */
177+}
178+
179+void
180+addtag(slist_t *list, char *elem)
181+{
182+
183+#define TAG_CHUNK 20
184+
185+ if ((list->count % TAG_CHUNK) == 0) {
186+ char **new;
187+
188+ new = (char **)realloc(list->list, (list->count + TAG_CHUNK)
189+ * sizeof(char *));
190+ if (new == NULL)
191+ mtree_err("memory allocation error");
192+ list->list = new;
193+ }
194+ list->list[list->count] = elem;
195+ list->count++;
196+}
197+
198+void
199+parsetags(slist_t *list, char *args)
200+{
201+ char *p, *e;
202+ size_t len;
203+
204+ if (args == NULL) {
205+ addtag(list, NULL);
206+ return;
207+ }
208+ while ((p = strsep(&args, ",")) != NULL) {
209+ if (*p == '\0')
210+ continue;
211+ len = strlen(p) + 3; /* "," + p + ",\0" */
212+ if ((e = malloc(len)) == NULL)
213+ mtree_err("memory allocation error");
214+ snprintf(e, len, ",%s,", p);
215+ addtag(list, e);
216+ }
217+}
218+
219+/*
220+ * matchtags
221+ * returns 0 if there's a match from the exclude list in the node's tags,
222+ * or there's an include list and no match.
223+ * return 1 otherwise.
224+ */
225+int
226+matchtags(NODE *node)
227+{
228+ int i;
229+
230+ if (node->tags) {
231+ for (i = 0; i < excludetags.count; i++)
232+ if (strstr(node->tags, excludetags.list[i]))
233+ break;
234+ if (i < excludetags.count)
235+ return (0);
236+
237+ for (i = 0; i < includetags.count; i++)
238+ if (strstr(node->tags, includetags.list[i]))
239+ break;
240+ if (i > 0 && i == includetags.count)
241+ return (0);
242+ } else if (includetags.count > 0) {
243+ return (0);
244+ }
245+ return (1);
246+}
247+
248+u_int
249+nodetoino(u_int type)
250+{
251+
252+ switch (type) {
253+ case F_BLOCK:
254+ return S_IFBLK;
255+ case F_CHAR:
256+ return S_IFCHR;
257+ case F_DIR:
258+ return S_IFDIR;
259+ case F_FIFO:
260+ return S_IFIFO;
261+ case F_FILE:
262+ return S_IFREG;
263+ case F_LINK:
264+ return S_IFLNK;
265+#ifdef S_IFSOCK
266+ case F_SOCK:
267+ return S_IFSOCK;
268+#endif
269+ default:
270+ printf("unknown type %d", type);
271+ abort();
272+ }
273+ /* NOTREACHED */
274+}
275+
276+const char *
277+nodetype(u_int type)
278+{
279+
280+ return (inotype(nodetoino(type)));
281+}
282+
283+
284+const char *
285+inotype(u_int type)
286+{
287+
288+ switch (type & S_IFMT) {
289+ case S_IFBLK:
290+ return ("block");
291+ case S_IFCHR:
292+ return ("char");
293+ case S_IFDIR:
294+ return ("dir");
295+ case S_IFIFO:
296+ return ("fifo");
297+ case S_IFREG:
298+ return ("file");
299+ case S_IFLNK:
300+ return ("link");
301+#ifdef S_IFSOCK
302+ case S_IFSOCK:
303+ return ("socket");
304+#endif
305+#ifdef S_IFDOOR
306+ case S_IFDOOR:
307+ return ("door");
308+#endif
309+ default:
310+ return ("unknown");
311+ }
312+ /* NOTREACHED */
313+}
+158,
-0
1@@ -0,0 +1,158 @@
2+/* $NetBSD: mtree.h,v 1.31 2012/10/05 09:17:29 wiz Exp $ */
3+
4+/*-
5+ * Copyright (c) 1990, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ *
32+ * @(#)mtree.h 8.1 (Berkeley) 6/6/93
33+ */
34+
35+#ifndef _MTREE_H_
36+#define _MTREE_H_
37+
38+#define KEYDEFAULT (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | \
39+ F_TIME | F_TYPE | F_UID | F_FLAGS)
40+
41+#define MISMATCHEXIT 2
42+
43+typedef struct _node {
44+ struct _node *parent, *child; /* up, down */
45+ struct _node *prev, *next; /* left, right */
46+ off_t st_size; /* size */
47+ struct timespec st_mtimespec; /* last modification time */
48+ char *slink; /* symbolic link reference */
49+ uid_t st_uid; /* uid */
50+ gid_t st_gid; /* gid */
51+#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
52+ mode_t st_mode; /* mode */
53+ dev_t st_rdev; /* device type */
54+ u_long st_flags; /* flags */
55+ nlink_t st_nlink; /* link count */
56+ u_long cksum; /* check sum */
57+ char *md5digest; /* MD5 digest */
58+ char *rmd160digest; /* RMD-160 digest */
59+ char *sha1digest; /* SHA1 digest */
60+ char *sha256digest; /* SHA256 digest */
61+ char *sha384digest; /* SHA384 digest */
62+ char *sha512digest; /* SHA512 digest */
63+ char *tags; /* tags, comma delimited,
64+ * also with leading and
65+ * trailing commas */
66+ size_t lineno; /* line # entry came from */
67+
68+#define F_CKSUM 0x00000001 /* cksum(1) check sum */
69+#define F_DEV 0x00000002 /* device type */
70+#define F_DONE 0x00000004 /* directory done */
71+#define F_FLAGS 0x00000008 /* file flags */
72+#define F_GID 0x00000010 /* gid */
73+#define F_GNAME 0x00000020 /* group name */
74+#define F_IGN 0x00000040 /* ignore */
75+#define F_MAGIC 0x00000080 /* name has magic chars */
76+#define F_MD5 0x00000100 /* MD5 digest */
77+#define F_MODE 0x00000200 /* mode */
78+#define F_NLINK 0x00000400 /* number of links */
79+#define F_OPT 0x00000800 /* existence optional */
80+#define F_RMD160 0x00001000 /* RMD-160 digest */
81+#define F_SHA1 0x00002000 /* SHA1 digest */
82+#define F_SIZE 0x00004000 /* size */
83+#define F_SLINK 0x00008000 /* symbolic link */
84+#define F_TAGS 0x00010000 /* tags */
85+#define F_TIME 0x00020000 /* modification time */
86+#define F_TYPE 0x00040000 /* file type */
87+#define F_UID 0x00080000 /* uid */
88+#define F_UNAME 0x00100000 /* user name */
89+#define F_VISIT 0x00200000 /* file visited */
90+#define F_NOCHANGE 0x00400000 /* check existence, but not */
91+ /* other properties */
92+#define F_SHA256 0x00800000 /* SHA256 digest */
93+#define F_SHA384 0x01000000 /* SHA384 digest */
94+#define F_SHA512 0x02000000 /* SHA512 digest */
95+
96+ int flags; /* items set */
97+
98+#define F_BLOCK 0x001 /* block special */
99+#define F_CHAR 0x002 /* char special */
100+#define F_DIR 0x004 /* directory */
101+#define F_FIFO 0x008 /* fifo */
102+#define F_FILE 0x010 /* regular file */
103+#define F_LINK 0x020 /* symbolic link */
104+#define F_SOCK 0x040 /* socket */
105+#define F_DOOR 0x080 /* door */
106+ int type; /* file type */
107+
108+ char name[1]; /* file name (must be last) */
109+} NODE;
110+
111+
112+typedef struct {
113+ char **list;
114+ int count;
115+} slist_t;
116+
117+
118+/*
119+ * prototypes for functions published to other programs which want to use
120+ * the specfile parser but don't want to pull in all of "extern.h"
121+ */
122+const char *inotype(u_int);
123+u_int nodetoino(u_int);
124+int setup_getid(const char *);
125+NODE *spec(FILE *);
126+int mtree_specspec(FILE *, FILE *);
127+void free_nodes(NODE *);
128+char *vispath(const char *);
129+
130+#ifdef __FreeBSD__
131+#define KEY_DIGEST "digest"
132+#else
133+#define KEY_DIGEST
134+#endif
135+
136+#define MD5KEY "md5" KEY_DIGEST
137+#ifdef __FreeBSD__
138+#define RMD160KEY "ripemd160" KEY_DIGEST
139+#else
140+#define RMD160KEY "rmd160" KEY_DIGEST
141+#endif
142+#define SHA1KEY "sha1" KEY_DIGEST
143+#define SHA256KEY "sha256" KEY_DIGEST
144+#define SHA384KEY "sha384"
145+#define SHA512KEY "sha512"
146+
147+#define RP(p) \
148+ ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
149+ (p)->fts_path + 2 : (p)->fts_path)
150+
151+#define UF_MASK ((UF_NODUMP | UF_IMMUTABLE | \
152+ UF_APPEND | UF_OPAQUE) \
153+ & UF_SETTABLE) /* user settable flags */
154+#define SF_MASK ((SF_ARCHIVED | SF_IMMUTABLE | \
155+ SF_APPEND) & SF_SETTABLE) /* root settable flags */
156+#define CH_MASK (UF_MASK | SF_MASK) /* all settable flags */
157+#define SP_FLGS (SF_IMMUTABLE | SF_APPEND) /* special flags */
158+
159+#endif /* _MTREE_H_ */
+290,
-0
1@@ -0,0 +1,290 @@
2+/* $NetBSD: pack_dev.c,v 1.12 2013/06/14 16:28:20 tsutsui Exp $ */
3+
4+/*-
5+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
6+ * All rights reserved.
7+ *
8+ * This code is derived from software contributed to The NetBSD Foundation
9+ * by Charles M. Hannum.
10+ *
11+ * Redistribution and use in source and binary forms, with or without
12+ * modification, are permitted provided that the following conditions
13+ * are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above copyright
17+ * notice, this list of conditions and the following disclaimer in the
18+ * documentation and/or other materials provided with the distribution.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+ * POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if HAVE_NBTOOL_CONFIG_H
34+#include "nbtool_config.h"
35+#endif
36+
37+#include <sys/cdefs.h>
38+#if !defined(lint)
39+__RCSID("$NetBSD: pack_dev.c,v 1.12 2013/06/14 16:28:20 tsutsui Exp $");
40+#endif /* not lint */
41+
42+#include <sys/types.h>
43+#include <sys/stat.h>
44+
45+#include <limits.h>
46+#include <stdio.h>
47+#include <stdlib.h>
48+#include <string.h>
49+#include <unistd.h>
50+
51+#include "pack_dev.h"
52+
53+static pack_t pack_netbsd;
54+static pack_t pack_freebsd;
55+static pack_t pack_8_8;
56+static pack_t pack_12_20;
57+static pack_t pack_14_18;
58+static pack_t pack_8_24;
59+static pack_t pack_bsdos;
60+static int compare_format(const void *, const void *);
61+
62+static const char iMajorError[] = "invalid major number";
63+static const char iMinorError[] = "invalid minor number";
64+static const char tooManyFields[] = "too many fields for format";
65+
66+ /* exported */
67+dev_t
68+pack_native(int n, u_long numbers[], const char **error)
69+{
70+ dev_t dev = 0;
71+
72+ if (n == 2) {
73+ dev = makedev(numbers[0], numbers[1]);
74+ if ((u_long)major(dev) != numbers[0])
75+ *error = iMajorError;
76+ else if ((u_long)minor(dev) != numbers[1])
77+ *error = iMinorError;
78+ } else
79+ *error = tooManyFields;
80+ return (dev);
81+}
82+
83+
84+static dev_t
85+pack_netbsd(int n, u_long numbers[], const char **error)
86+{
87+ dev_t dev = 0;
88+
89+ if (n == 2) {
90+ dev = makedev_netbsd(numbers[0], numbers[1]);
91+ if ((u_long)major_netbsd(dev) != numbers[0])
92+ *error = iMajorError;
93+ else if ((u_long)minor_netbsd(dev) != numbers[1])
94+ *error = iMinorError;
95+ } else
96+ *error = tooManyFields;
97+ return (dev);
98+}
99+
100+
101+#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
102+#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0))
103+#define makedev_freebsd(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
104+ (((y) << 0) & 0xffff00ff)))
105+
106+static dev_t
107+pack_freebsd(int n, u_long numbers[], const char **error)
108+{
109+ dev_t dev = 0;
110+
111+ if (n == 2) {
112+ dev = makedev_freebsd(numbers[0], numbers[1]);
113+ if ((u_long)major_freebsd(dev) != numbers[0])
114+ *error = iMajorError;
115+ if ((u_long)minor_freebsd(dev) != numbers[1])
116+ *error = iMinorError;
117+ } else
118+ *error = tooManyFields;
119+ return (dev);
120+}
121+
122+
123+#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
124+#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
125+#define makedev_8_8(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
126+ (((y) << 0) & 0x000000ff)))
127+
128+static dev_t
129+pack_8_8(int n, u_long numbers[], const char **error)
130+{
131+ dev_t dev = 0;
132+
133+ if (n == 2) {
134+ dev = makedev_8_8(numbers[0], numbers[1]);
135+ if ((u_long)major_8_8(dev) != numbers[0])
136+ *error = iMajorError;
137+ if ((u_long)minor_8_8(dev) != numbers[1])
138+ *error = iMinorError;
139+ } else
140+ *error = tooManyFields;
141+ return (dev);
142+}
143+
144+
145+#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20))
146+#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0))
147+#define makedev_12_20(x,y) ((dev_t)((((x) << 20) & 0xfff00000) | \
148+ (((y) << 0) & 0x000fffff)))
149+
150+static dev_t
151+pack_12_20(int n, u_long numbers[], const char **error)
152+{
153+ dev_t dev = 0;
154+
155+ if (n == 2) {
156+ dev = makedev_12_20(numbers[0], numbers[1]);
157+ if ((u_long)major_12_20(dev) != numbers[0])
158+ *error = iMajorError;
159+ if ((u_long)minor_12_20(dev) != numbers[1])
160+ *error = iMinorError;
161+ } else
162+ *error = tooManyFields;
163+ return (dev);
164+}
165+
166+
167+#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18))
168+#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0))
169+#define makedev_14_18(x,y) ((dev_t)((((x) << 18) & 0xfffc0000) | \
170+ (((y) << 0) & 0x0003ffff)))
171+
172+static dev_t
173+pack_14_18(int n, u_long numbers[], const char **error)
174+{
175+ dev_t dev = 0;
176+
177+ if (n == 2) {
178+ dev = makedev_14_18(numbers[0], numbers[1]);
179+ if ((u_long)major_14_18(dev) != numbers[0])
180+ *error = iMajorError;
181+ if ((u_long)minor_14_18(dev) != numbers[1])
182+ *error = iMinorError;
183+ } else
184+ *error = tooManyFields;
185+ return (dev);
186+}
187+
188+
189+#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24))
190+#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0))
191+#define makedev_8_24(x,y) ((dev_t)((((x) << 24) & 0xff000000) | \
192+ (((y) << 0) & 0x00ffffff)))
193+
194+static dev_t
195+pack_8_24(int n, u_long numbers[], const char **error)
196+{
197+ dev_t dev = 0;
198+
199+ if (n == 2) {
200+ dev = makedev_8_24(numbers[0], numbers[1]);
201+ if ((u_long)major_8_24(dev) != numbers[0])
202+ *error = iMajorError;
203+ if ((u_long)minor_8_24(dev) != numbers[1])
204+ *error = iMinorError;
205+ } else
206+ *error = tooManyFields;
207+ return (dev);
208+}
209+
210+
211+#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20))
212+#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8))
213+#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
214+#define makedev_12_12_8(x,y,z) ((dev_t)((((x) << 20) & 0xfff00000) | \
215+ (((y) << 8) & 0x000fff00) | \
216+ (((z) << 0) & 0x000000ff)))
217+
218+static dev_t
219+pack_bsdos(int n, u_long numbers[], const char **error)
220+{
221+ dev_t dev = 0;
222+
223+ if (n == 2) {
224+ dev = makedev_12_20(numbers[0], numbers[1]);
225+ if ((u_long)major_12_20(dev) != numbers[0])
226+ *error = iMajorError;
227+ if ((u_long)minor_12_20(dev) != numbers[1])
228+ *error = iMinorError;
229+ } else if (n == 3) {
230+ dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);
231+ if ((u_long)major_12_12_8(dev) != numbers[0])
232+ *error = iMajorError;
233+ if ((u_long)unit_12_12_8(dev) != numbers[1])
234+ *error = "invalid unit number";
235+ if ((u_long)subunit_12_12_8(dev) != numbers[2])
236+ *error = "invalid subunit number";
237+ } else
238+ *error = tooManyFields;
239+ return (dev);
240+}
241+
242+
243+ /* list of formats and pack functions */
244+ /* this list must be sorted lexically */
245+static struct format {
246+ const char *name;
247+ pack_t *pack;
248+} formats[] = {
249+ {"386bsd", pack_8_8},
250+ {"4bsd", pack_8_8},
251+ {"bsdos", pack_bsdos},
252+ {"freebsd", pack_freebsd},
253+ {"hpux", pack_8_24},
254+ {"isc", pack_8_8},
255+ {"linux", pack_8_8},
256+ {"native", pack_native},
257+ {"netbsd", pack_netbsd},
258+ {"osf1", pack_12_20},
259+ {"sco", pack_8_8},
260+ {"solaris", pack_14_18},
261+ {"sunos", pack_8_8},
262+ {"svr3", pack_8_8},
263+ {"svr4", pack_14_18},
264+ {"ultrix", pack_8_8},
265+};
266+
267+static int
268+compare_format(const void *key, const void *element)
269+{
270+ const char *name;
271+ const struct format *format;
272+
273+ name = key;
274+ format = element;
275+
276+ return (strcmp(name, format->name));
277+}
278+
279+
280+pack_t *
281+pack_find(const char *name)
282+{
283+ struct format *format;
284+
285+ format = bsearch(name, formats,
286+ sizeof(formats)/sizeof(formats[0]),
287+ sizeof(formats[0]), compare_format);
288+ if (format == 0)
289+ return (NULL);
290+ return (format->pack);
291+}
+47,
-0
1@@ -0,0 +1,47 @@
2+/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */
3+
4+/*-
5+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
6+ * All rights reserved.
7+ *
8+ * This code is derived from software contributed to The NetBSD Foundation
9+ * by Charles M. Hannum.
10+ *
11+ * Redistribution and use in source and binary forms, with or without
12+ * modification, are permitted provided that the following conditions
13+ * are met:
14+ * 1. Redistributions of source code must retain the above copyright
15+ * notice, this list of conditions and the following disclaimer.
16+ * 2. Redistributions in binary form must reproduce the above copyright
17+ * notice, this list of conditions and the following disclaimer in the
18+ * documentation and/or other materials provided with the distribution.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+ * POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#ifndef _PACK_DEV_H
34+#define _PACK_DEV_H
35+
36+typedef dev_t pack_t(int, u_long [], const char **);
37+
38+pack_t *pack_find(const char *);
39+pack_t pack_native;
40+
41+#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
42+#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
43+ (((x) & 0x000000ff) >> 0)))
44+#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \
45+ (((y) << 12) & 0xfff00000) | \
46+ (((y) << 0) & 0x000000ff)))
47+
48+#endif /* _PACK_DEV_H */
+878,
-0
1@@ -0,0 +1,878 @@
2+/* $NetBSD: spec.c,v 1.94 2025/12/18 14:05:41 christos Exp $ */
3+
4+/*-
5+ * Copyright (c) 1989, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ */
32+
33+/*-
34+ * Copyright (c) 2001-2004 The NetBSD Foundation, Inc.
35+ * All rights reserved.
36+ *
37+ * This code is derived from software contributed to The NetBSD Foundation
38+ * by Luke Mewburn of Wasabi Systems.
39+ *
40+ * Redistribution and use in source and binary forms, with or without
41+ * modification, are permitted provided that the following conditions
42+ * are met:
43+ * 1. Redistributions of source code must retain the above copyright
44+ * notice, this list of conditions and the following disclaimer.
45+ * 2. Redistributions in binary form must reproduce the above copyright
46+ * notice, this list of conditions and the following disclaimer in the
47+ * documentation and/or other materials provided with the distribution.
48+ *
49+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
50+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
51+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
53+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
54+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
55+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59+ * POSSIBILITY OF SUCH DAMAGE.
60+ */
61+
62+#if HAVE_NBTOOL_CONFIG_H
63+#include "nbtool_config.h"
64+#endif
65+
66+#include <sys/cdefs.h>
67+#if defined(__RCSID) && !defined(lint)
68+#if 0
69+static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95";
70+#else
71+__RCSID("$NetBSD: spec.c,v 1.94 2025/12/18 14:05:41 christos Exp $");
72+#endif
73+#endif /* not lint */
74+
75+#include <sys/param.h>
76+#include <sys/stat.h>
77+
78+#include <assert.h>
79+#include <ctype.h>
80+#include <errno.h>
81+#include <grp.h>
82+#include <pwd.h>
83+#include <stdarg.h>
84+#include <stdio.h>
85+#include <stdint.h>
86+#include <stdlib.h>
87+#include <string.h>
88+#include <unistd.h>
89+#include <vis.h>
90+#include <util.h>
91+
92+#include "extern.h"
93+#include "pack_dev.h"
94+
95+size_t mtree_lineno; /* Current spec line number */
96+int mtree_Mflag; /* Merge duplicate entries */
97+int mtree_Wflag; /* Don't "whack" permissions */
98+int mtree_Sflag; /* Sort entries */
99+
100+static dev_t parsedev(char *);
101+static void replacenode(NODE *, NODE *);
102+static void set(char *, NODE *);
103+static void unset(char *, NODE *);
104+static NODE *addchild(NODE *, NODE *);
105+static int nodecmp(const NODE *, const NODE *);
106+static int appendfield(FILE *, int, const char *, ...) __printflike(3, 4);
107+
108+#define REPLACEPTR(x,v) do { if ((x)) free((x)); (x) = (v); } while (0)
109+
110+NODE *
111+spec(FILE *fp)
112+{
113+ NODE *centry, *last, *pathparent, *cur;
114+ char *p, *e, *next;
115+ NODE ginfo, *root;
116+ char *buf, *tname, *ntname;
117+ size_t tnamelen, plen;
118+
119+ root = NULL;
120+ centry = last = NULL;
121+ tname = NULL;
122+ tnamelen = 0;
123+ memset(&ginfo, 0, sizeof(ginfo));
124+ for (mtree_lineno = 0;
125+ (buf = fparseln(fp, NULL, &mtree_lineno, NULL,
126+ FPARSELN_UNESCCOMM));
127+ free(buf)) {
128+ /* Skip leading whitespace. */
129+ for (p = buf; *p && isspace((unsigned char)*p); ++p)
130+ continue;
131+
132+ /* If nothing but whitespace, continue. */
133+ if (!*p)
134+ continue;
135+
136+#ifdef DEBUG
137+ fprintf(stderr, "line %lu: {%s}\n",
138+ (u_long)mtree_lineno, p);
139+#endif
140+ /* Grab file name, "$", "set", or "unset". */
141+ next = buf;
142+ while ((p = strsep(&next, " \t")) != NULL && *p == '\0')
143+ continue;
144+ if (p == NULL)
145+ mtree_err("missing field");
146+
147+ if (p[0] == '/') {
148+ if (strcmp(p + 1, "set") == 0)
149+ set(next, &ginfo);
150+ else if (strcmp(p + 1, "unset") == 0)
151+ unset(next, &ginfo);
152+ else
153+ mtree_err("invalid specification `%s'", p);
154+ continue;
155+ }
156+
157+ if (strcmp(p, "..") == 0) {
158+ /* Don't go up, if haven't gone down. */
159+ if (root == NULL)
160+ goto noparent;
161+ if (last->type != F_DIR || last->flags & F_DONE) {
162+ if (last == root)
163+ goto noparent;
164+ last = last->parent;
165+ }
166+ last->flags |= F_DONE;
167+ continue;
168+
169+noparent: mtree_err("no parent node");
170+ }
171+
172+ plen = strlen(p) + 1;
173+ if (plen > tnamelen) {
174+ if ((ntname = realloc(tname, plen)) == NULL)
175+ mtree_err("realloc: %s", strerror(errno));
176+ tname = ntname;
177+ tnamelen = plen;
178+ }
179+ if (strunvis(tname, p) == -1)
180+ mtree_err("strunvis failed on `%s'", p);
181+ p = tname;
182+
183+ pathparent = NULL;
184+ if (strchr(p, '/') != NULL) {
185+ cur = root;
186+ for (; (e = strchr(p, '/')) != NULL; p = e+1) {
187+ if (p == e)
188+ continue; /* handle // */
189+ *e = '\0';
190+ if (strcmp(p, ".") != 0) {
191+ while (cur &&
192+ strcmp(cur->name, p) != 0) {
193+ cur = cur->next;
194+ }
195+ }
196+ if (cur == NULL || cur->type != F_DIR) {
197+ mtree_err("%s: %s", tname,
198+ "missing directory in specification");
199+ }
200+ *e = '/';
201+ pathparent = cur;
202+ cur = cur->child;
203+ }
204+ if (*p == '\0')
205+ mtree_err("%s: empty leaf element", tname);
206+ }
207+
208+ if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
209+ mtree_err("%s", strerror(errno));
210+ *centry = ginfo;
211+ centry->lineno = mtree_lineno;
212+ strcpy(centry->name, p);
213+#define MAGIC "?*["
214+ if (strpbrk(p, MAGIC))
215+ centry->flags |= F_MAGIC;
216+ set(next, centry);
217+
218+ if (root == NULL) {
219+ /*
220+ * empty tree
221+ */
222+ /*
223+ * Allow a bare "." root node by forcing it to
224+ * type=dir for compatibility with FreeBSD.
225+ */
226+ if (strcmp(centry->name, ".") == 0 && centry->type == 0)
227+ centry->type = F_DIR;
228+ if (strcmp(centry->name, ".") != 0)
229+ mtree_err(
230+ "root node must be the directory `.',"
231+ " found `%s'", centry->name);
232+ if (centry->type != F_DIR)
233+ mtree_err(
234+ "root node must type %#x != %#x",
235+ F_DIR, centry->type);
236+ last = root = centry;
237+ root->parent = root;
238+ } else if (pathparent != NULL) {
239+ /*
240+ * full path entry; add or replace
241+ */
242+ centry->parent = pathparent;
243+ last = addchild(pathparent, centry);
244+ } else if (strcmp(centry->name, ".") == 0) {
245+ /*
246+ * duplicate "." entry; always replace
247+ */
248+ replacenode(root, centry);
249+ } else if (last->type == F_DIR && !(last->flags & F_DONE)) {
250+ /*
251+ * new relative child in current dir;
252+ * add or replace
253+ */
254+ centry->parent = last;
255+ last = addchild(last, centry);
256+ } else {
257+ /*
258+ * new relative child in parent dir
259+ * (after encountering ".." entry);
260+ * add or replace
261+ */
262+ centry->parent = last->parent;
263+ last = addchild(last->parent, centry);
264+ }
265+ }
266+ return (root);
267+}
268+
269+void
270+free_nodes(NODE *root)
271+{
272+ NODE *cur, *next;
273+
274+ if (root == NULL)
275+ return;
276+
277+ next = NULL;
278+ for (cur = root; cur != NULL; cur = next) {
279+ next = cur->next;
280+ free_nodes(cur->child);
281+ REPLACEPTR(cur->slink, NULL);
282+ REPLACEPTR(cur->md5digest, NULL);
283+ REPLACEPTR(cur->rmd160digest, NULL);
284+ REPLACEPTR(cur->sha1digest, NULL);
285+ REPLACEPTR(cur->sha256digest, NULL);
286+ REPLACEPTR(cur->sha384digest, NULL);
287+ REPLACEPTR(cur->sha512digest, NULL);
288+ REPLACEPTR(cur->tags, NULL);
289+ REPLACEPTR(cur, NULL);
290+ }
291+}
292+
293+/*
294+ * appendfield --
295+ * Like fprintf(), but output a space either before or after
296+ * the regular output, according to the pathlast flag.
297+ */
298+static int
299+appendfield(FILE *fp, int pathlast, const char *fmt, ...)
300+{
301+ va_list ap;
302+ int result;
303+
304+ va_start(ap, fmt);
305+ if (!pathlast)
306+ fprintf(fp, " ");
307+ result = vprintf(fmt, ap);
308+ if (pathlast)
309+ fprintf(fp, " ");
310+ va_end(ap);
311+ return result;
312+}
313+
314+/*
315+ * dump_nodes --
316+ * dump the NODEs from `cur', based in the directory `dir'.
317+ * if pathlast is none zero, print the path last, otherwise print
318+ * it first.
319+ */
320+void
321+dump_nodes(FILE *fp, const char *dir, NODE *root, int pathlast)
322+{
323+ NODE *cur;
324+ char path[MAXPATHLEN];
325+ const char *name;
326+ char *str;
327+ char *p, *q;
328+
329+ for (cur = root; cur != NULL; cur = cur->next) {
330+ if (cur->type != F_DIR && !matchtags(cur))
331+ continue;
332+
333+ if (snprintf(path, sizeof(path), "%s%s%s",
334+ dir, *dir ? "/" : "", cur->name)
335+ >= (int)sizeof(path))
336+ mtree_err("Pathname too long.");
337+
338+ if (!pathlast)
339+ fprintf(fp, "%s", vispath(path));
340+
341+#define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f)))
342+ if (MATCHFLAG(F_TYPE))
343+ appendfield(fp, pathlast, "type=%s",
344+ nodetype(cur->type));
345+ if (MATCHFLAG(F_UID | F_UNAME)) {
346+ if (keys & F_UNAME &&
347+ (name = user_from_uid(cur->st_uid, 1)) != NULL)
348+ appendfield(fp, pathlast, "uname=%s", name);
349+ else
350+ appendfield(fp, pathlast, "uid=%u",
351+ cur->st_uid);
352+ }
353+ if (MATCHFLAG(F_GID | F_GNAME)) {
354+ if (keys & F_GNAME &&
355+ (name = group_from_gid(cur->st_gid, 1)) != NULL)
356+ appendfield(fp, pathlast, "gname=%s", name);
357+ else
358+ appendfield(fp, pathlast, "gid=%u",
359+ cur->st_gid);
360+ }
361+ if (MATCHFLAG(F_MODE))
362+ appendfield(fp, pathlast, "mode=%#o", cur->st_mode);
363+ if (MATCHFLAG(F_DEV) &&
364+ (cur->type == F_BLOCK || cur->type == F_CHAR))
365+ appendfield(fp, pathlast, "device=%#jx",
366+ (uintmax_t)cur->st_rdev);
367+ if (MATCHFLAG(F_NLINK))
368+ appendfield(fp, pathlast, "nlink=%ju",
369+ (uintmax_t)cur->st_nlink);
370+ if (MATCHFLAG(F_SLINK))
371+ appendfield(fp, pathlast, "link=%s",
372+ vispath(cur->slink));
373+ if (MATCHFLAG(F_SIZE))
374+ appendfield(fp, pathlast, "size=%ju",
375+ (uintmax_t)cur->st_size);
376+ if (MATCHFLAG(F_TIME))
377+ appendfield(fp, pathlast, "time=%jd.%09ld",
378+ (intmax_t)cur->st_mtimespec.tv_sec,
379+ cur->st_mtimespec.tv_nsec);
380+ if (MATCHFLAG(F_CKSUM))
381+ appendfield(fp, pathlast, "cksum=%lu", cur->cksum);
382+ if (MATCHFLAG(F_MD5))
383+ appendfield(fp, pathlast, "%s=%s", MD5KEY,
384+ cur->md5digest);
385+ if (MATCHFLAG(F_RMD160))
386+ appendfield(fp, pathlast, "%s=%s", RMD160KEY,
387+ cur->rmd160digest);
388+ if (MATCHFLAG(F_SHA1))
389+ appendfield(fp, pathlast, "%s=%s", SHA1KEY,
390+ cur->sha1digest);
391+ if (MATCHFLAG(F_SHA256))
392+ appendfield(fp, pathlast, "%s=%s", SHA256KEY,
393+ cur->sha256digest);
394+ if (MATCHFLAG(F_SHA384))
395+ appendfield(fp, pathlast, "%s=%s", SHA384KEY,
396+ cur->sha384digest);
397+ if (MATCHFLAG(F_SHA512))
398+ appendfield(fp, pathlast, "%s=%s", SHA512KEY,
399+ cur->sha512digest);
400+ if (MATCHFLAG(F_FLAGS)) {
401+ str = flags_to_string(cur->st_flags, "none");
402+ appendfield(fp, pathlast, "flags=%s", str);
403+ free(str);
404+ }
405+ if (MATCHFLAG(F_IGN))
406+ appendfield(fp, pathlast, "ignore");
407+ if (MATCHFLAG(F_OPT))
408+ appendfield(fp, pathlast, "optional");
409+ if (MATCHFLAG(F_TAGS)) {
410+ /* don't output leading or trailing commas */
411+ p = cur->tags;
412+ while (*p == ',')
413+ p++;
414+ q = p + strlen(p);
415+ while(q > p && q[-1] == ',')
416+ q--;
417+ appendfield(fp, pathlast, "tags=%.*s", (int)(q - p), p);
418+ }
419+ puts(pathlast ? vispath(path) : "");
420+
421+ if (cur->child)
422+ dump_nodes(fp, path, cur->child, pathlast);
423+ }
424+}
425+
426+/*
427+ * vispath --
428+ * strsvis(3) encodes path, which must not be longer than MAXPATHLEN
429+ * characters long, and returns a pointer to a static buffer containing
430+ * the result.
431+ */
432+char *
433+vispath(const char *path)
434+{
435+ static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
436+ static const char extra_glob[] = { ' ', '\t', '\n', '\\', '#', '*',
437+ '?', '[', '\0' };
438+ static char pathbuf[4*MAXPATHLEN + 1];
439+
440+ if (flavor == F_NETBSD6)
441+ strsvis(pathbuf, path, VIS_CSTYLE, extra);
442+ else
443+ strsvis(pathbuf, path, VIS_OCTAL, extra_glob);
444+ return pathbuf;
445+}
446+
447+
448+static dev_t
449+parsedev(char *arg)
450+{
451+#define MAX_PACK_ARGS 3
452+ u_long numbers[MAX_PACK_ARGS];
453+ char *p, *ep, *dev;
454+ int argc;
455+ pack_t *pack;
456+ dev_t result;
457+ const char *error = NULL;
458+
459+ if ((dev = strchr(arg, ',')) != NULL) {
460+ *dev++='\0';
461+ if ((pack = pack_find(arg)) == NULL)
462+ mtree_err("unknown format `%s'", arg);
463+ argc = 0;
464+ while ((p = strsep(&dev, ",")) != NULL) {
465+ if (*p == '\0')
466+ mtree_err("missing number");
467+ numbers[argc++] = strtoul(p, &ep, 0);
468+ if (*ep != '\0')
469+ mtree_err("invalid number `%s'",
470+ p);
471+ if (argc > MAX_PACK_ARGS)
472+ mtree_err("too many arguments");
473+ }
474+ if (argc < 2)
475+ mtree_err("not enough arguments");
476+ result = (*pack)(argc, numbers, &error);
477+ if (error != NULL)
478+ mtree_err("%s", error);
479+ } else {
480+ result = (dev_t)strtoul(arg, &ep, 0);
481+ if (*ep != '\0')
482+ mtree_err("invalid device `%s'", arg);
483+ }
484+ return (result);
485+}
486+
487+static void
488+replacenode(NODE *cur, NODE *new)
489+{
490+
491+#define REPLACE(x) cur->x = new->x
492+#define REPLACESTR(x) REPLACEPTR(cur->x,new->x)
493+
494+ if (cur->type != new->type) {
495+ if (mtree_Mflag) {
496+ /*
497+ * merge entries with different types; we
498+ * don't want children retained in this case.
499+ */
500+ REPLACE(type);
501+ free_nodes(cur->child);
502+ cur->child = NULL;
503+ } else {
504+ mtree_err(
505+ "existing entry for `%s', type `%s'"
506+ " does not match type `%s'",
507+ cur->name, nodetype(cur->type),
508+ nodetype(new->type));
509+ }
510+ }
511+
512+ REPLACE(st_size);
513+ REPLACE(st_mtimespec);
514+ REPLACESTR(slink);
515+ if (cur->slink != NULL) {
516+ if ((cur->slink = strdup(new->slink)) == NULL)
517+ mtree_err("memory allocation error");
518+ if (strunvis(cur->slink, new->slink) == -1)
519+ mtree_err("strunvis failed on `%s'", new->slink);
520+ free(new->slink);
521+ }
522+ REPLACE(st_uid);
523+ REPLACE(st_gid);
524+ REPLACE(st_mode);
525+ REPLACE(st_rdev);
526+ REPLACE(st_flags);
527+ REPLACE(st_nlink);
528+ REPLACE(cksum);
529+ REPLACESTR(md5digest);
530+ REPLACESTR(rmd160digest);
531+ REPLACESTR(sha1digest);
532+ REPLACESTR(sha256digest);
533+ REPLACESTR(sha384digest);
534+ REPLACESTR(sha512digest);
535+ REPLACESTR(tags);
536+ REPLACE(lineno);
537+ REPLACE(flags);
538+ free(new);
539+}
540+
541+static void
542+set(char *t, NODE *ip)
543+{
544+ int type, value;
545+ size_t len;
546+ gid_t gid;
547+ uid_t uid;
548+ char *kw, *val, *md, *ep;
549+ void *m;
550+
551+ while ((kw = strsep(&t, "= \t")) != NULL) {
552+ if (*kw == '\0')
553+ continue;
554+ if (strcmp(kw, "all") == 0)
555+ mtree_err("invalid keyword `all'");
556+ ip->flags |= type = parsekey(kw, &value);
557+ if (!value)
558+ /* Just set flag bit (F_IGN and F_OPT) */
559+ continue;
560+ while ((val = strsep(&t, " \t")) != NULL && *val == '\0')
561+ continue;
562+ if (val == NULL)
563+ mtree_err("missing value");
564+ switch (type) {
565+ case F_CKSUM:
566+ ip->cksum = strtoul(val, &ep, 10);
567+ if (*ep)
568+ mtree_err("invalid checksum `%s'", val);
569+ break;
570+ case F_DEV:
571+ ip->st_rdev = parsedev(val);
572+ break;
573+ case F_FLAGS:
574+ if (strcmp("none", val) == 0)
575+ ip->st_flags = 0;
576+ else if (string_to_flags(&val, &ip->st_flags, NULL)
577+ != 0)
578+ mtree_err("invalid flag `%s'", val);
579+ break;
580+ case F_GID:
581+ ip->st_gid = (gid_t)strtoul(val, &ep, 10);
582+ if (*ep)
583+ mtree_err("invalid gid `%s'", val);
584+ break;
585+ case F_GNAME:
586+ if (mtree_Wflag) /* don't parse if whacking */
587+ break;
588+ if (gid_from_group(val, &gid) == -1)
589+ mtree_err("unknown group `%s'", val);
590+ ip->st_gid = gid;
591+ break;
592+ case F_MD5:
593+ if (val[0]=='0' && val[1]=='x')
594+ md=&val[2];
595+ else
596+ md=val;
597+ if ((ip->md5digest = strdup(md)) == NULL)
598+ mtree_err("memory allocation error");
599+ break;
600+ case F_MODE:
601+ if ((m = setmode(val)) == NULL)
602+ mtree_err("cannot set file mode `%s' (%s)",
603+ val, strerror(errno));
604+ ip->st_mode = getmode(m, 0);
605+ free(m);
606+ break;
607+ case F_NLINK:
608+ ip->st_nlink = (nlink_t)strtoul(val, &ep, 10);
609+ if (*ep)
610+ mtree_err("invalid link count `%s'", val);
611+ break;
612+ case F_RMD160:
613+ if (val[0]=='0' && val[1]=='x')
614+ md=&val[2];
615+ else
616+ md=val;
617+ if ((ip->rmd160digest = strdup(md)) == NULL)
618+ mtree_err("memory allocation error");
619+ break;
620+ case F_SHA1:
621+ if (val[0]=='0' && val[1]=='x')
622+ md=&val[2];
623+ else
624+ md=val;
625+ if ((ip->sha1digest = strdup(md)) == NULL)
626+ mtree_err("memory allocation error");
627+ break;
628+ case F_SIZE:
629+ ip->st_size = (off_t)strtoll(val, &ep, 10);
630+ if (*ep)
631+ mtree_err("invalid size `%s'", val);
632+ break;
633+ case F_SLINK:
634+ if ((ip->slink = strdup(val)) == NULL)
635+ mtree_err("memory allocation error");
636+ if (strunvis(ip->slink, val) == -1)
637+ mtree_err("strunvis failed on `%s'", val);
638+ break;
639+ case F_TAGS:
640+ len = strlen(val) + 3; /* "," + str + ",\0" */
641+ if ((ip->tags = malloc(len)) == NULL)
642+ mtree_err("memory allocation error");
643+ snprintf(ip->tags, len, ",%s,", val);
644+ break;
645+ case F_TIME:
646+ ip->st_mtimespec.tv_sec =
647+ (time_t)strtoll(val, &ep, 10);
648+ if (*ep != '.')
649+ mtree_err("invalid time `%s'", val);
650+ val = ep + 1;
651+ ip->st_mtimespec.tv_nsec = strtol(val, &ep, 10);
652+ if (*ep)
653+ mtree_err("invalid time `%s'", val);
654+ break;
655+ case F_TYPE:
656+ ip->type = parsetype(val);
657+ break;
658+ case F_UID:
659+ ip->st_uid = (uid_t)strtoul(val, &ep, 10);
660+ if (*ep)
661+ mtree_err("invalid uid `%s'", val);
662+ break;
663+ case F_UNAME:
664+ if (mtree_Wflag) /* don't parse if whacking */
665+ break;
666+ if (uid_from_user(val, &uid) == -1)
667+ mtree_err("unknown user `%s'", val);
668+ ip->st_uid = uid;
669+ break;
670+ case F_SHA256:
671+ if (val[0]=='0' && val[1]=='x')
672+ md=&val[2];
673+ else
674+ md=val;
675+ if ((ip->sha256digest = strdup(md)) == NULL)
676+ mtree_err("memory allocation error");
677+ break;
678+ case F_SHA384:
679+ if (val[0]=='0' && val[1]=='x')
680+ md=&val[2];
681+ else
682+ md=val;
683+ if ((ip->sha384digest = strdup(md)) == NULL)
684+ mtree_err("memory allocation error");
685+ break;
686+ case F_SHA512:
687+ if (val[0]=='0' && val[1]=='x')
688+ md=&val[2];
689+ else
690+ md=val;
691+ if ((ip->sha512digest = strdup(md)) == NULL)
692+ mtree_err("memory allocation error");
693+ break;
694+ default:
695+ mtree_err(
696+ "set(): unsupported key type 0x%x (INTERNAL ERROR)",
697+ type);
698+ /* NOTREACHED */
699+ }
700+ }
701+}
702+
703+static void
704+unset(char *t, NODE *ip)
705+{
706+ char *p;
707+
708+ while ((p = strsep(&t, " \t")) != NULL) {
709+ if (*p == '\0')
710+ continue;
711+ ip->flags &= ~parsekey(p, NULL);
712+ }
713+}
714+
715+/*
716+ * addchild --
717+ * Add the centry node as a child of the pathparent node. If
718+ * centry is a duplicate, call replacenode(). If centry is not
719+ * a duplicate, insert it into the linked list referenced by
720+ * pathparent->child. Keep the list sorted if Sflag is set.
721+ */
722+static NODE *
723+addchild(NODE *pathparent, NODE *centry)
724+{
725+ NODE *samename; /* node with the same name as centry */
726+ NODE *replacepos; /* if non-NULL, centry should replace this node */
727+ NODE *insertpos; /* if non-NULL, centry should be inserted
728+ * after this node */
729+ NODE *cur; /* for stepping through the list */
730+ NODE *last; /* the last node in the list */
731+ int cmp;
732+
733+ samename = NULL;
734+ replacepos = NULL;
735+ insertpos = NULL;
736+ last = NULL;
737+ cur = pathparent->child;
738+ if (cur == NULL) {
739+ /* centry is pathparent's first and only child node so far */
740+ pathparent->child = centry;
741+ return centry;
742+ }
743+
744+ /*
745+ * pathparent already has at least one other child, so add the
746+ * centry node to the list.
747+ *
748+ * We first scan through the list looking for an existing node
749+ * with the same name (setting samename), and also looking
750+ * for the correct position to replace or insert the new node
751+ * (setting replacepos and/or insertpos).
752+ */
753+ for (; cur != NULL; last = cur, cur = cur->next) {
754+ if (strcmp(centry->name, cur->name) == 0) {
755+ samename = cur;
756+ }
757+ if (mtree_Sflag) {
758+ cmp = nodecmp(centry, cur);
759+ if (cmp == 0) {
760+ replacepos = cur;
761+ } else if (cmp > 0) {
762+ insertpos = cur;
763+ }
764+ }
765+ }
766+ if (! mtree_Sflag) {
767+ if (samename != NULL) {
768+ /* replace node with same name */
769+ replacepos = samename;
770+ } else {
771+ /* add new node at end of list */
772+ insertpos = last;
773+ }
774+ }
775+
776+ if (samename != NULL) {
777+ /*
778+ * We found a node with the same name above. Call
779+ * replacenode(), which will either exit with an error,
780+ * or replace the information in the samename node and
781+ * free the information in the centry node.
782+ */
783+ replacenode(samename, centry);
784+ if (samename == replacepos) {
785+ /* The just-replaced node was in the correct position */
786+ return samename;
787+ }
788+ if (samename == insertpos || samename->prev == insertpos) {
789+ /*
790+ * We thought the new node should be just before
791+ * or just after the replaced node, but that would
792+ * be equivalent to just retaining the replaced node.
793+ */
794+ return samename;
795+ }
796+
797+ /*
798+ * The just-replaced node is in the wrong position in
799+ * the list. This can happen if sort order depends on
800+ * criteria other than the node name.
801+ *
802+ * Make centry point to the just-replaced node. Unlink
803+ * the just-replaced node from the list, and allow it to
804+ * be inserted in the correct position later.
805+ */
806+ centry = samename;
807+ if (centry->prev)
808+ centry->prev->next = centry->next;
809+ else {
810+ /* centry->next is the new head of the list */
811+ pathparent->child = centry->next;
812+ assert(centry->next != NULL);
813+ }
814+ if (centry->next)
815+ centry->next->prev = centry->prev;
816+ centry->prev = NULL;
817+ centry->next = NULL;
818+ }
819+
820+ if (insertpos == NULL) {
821+ /* insert centry at the beginning of the list */
822+ pathparent->child->prev = centry;
823+ centry->next = pathparent->child;
824+ centry->prev = NULL;
825+ pathparent->child = centry;
826+ } else {
827+ /* insert centry into the list just after insertpos */
828+ centry->next = insertpos->next;
829+ insertpos->next = centry;
830+ centry->prev = insertpos;
831+ if (centry->next)
832+ centry->next->prev = centry;
833+ }
834+ return centry;
835+}
836+
837+/*
838+ * nodecmp --
839+ * used as a comparison function by addchild() to control the order
840+ * in which entries appear within a list of sibling nodes. We make
841+ * directories sort after non-directories, but otherwise sort in
842+ * strcmp() order.
843+ *
844+ * Keep this in sync with dcmp() below.
845+ */
846+static int
847+nodecmp(const NODE *a, const NODE *b)
848+{
849+
850+ if ((a->type & F_DIR) != 0) {
851+ if ((b->type & F_DIR) == 0)
852+ return 1;
853+ } else if ((b->type & F_DIR) != 0) {
854+ return -1;
855+ }
856+ return strcmp(a->name, b->name);
857+}
858+
859+/*
860+ * dcmp --
861+ * used as a comparison function passed to fts_open() to control
862+ * the order in which fts_read() returns results. We make
863+ * directories sort after non-directories, but otherwise sort in
864+ * strcmp() order.
865+ *
866+ * Keep this in sync with nodecmp() above.
867+ */
868+int
869+dcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *b)
870+{
871+
872+ if (S_ISDIR((*a)->fts_statp->st_mode)) {
873+ if (!S_ISDIR((*b)->fts_statp->st_mode))
874+ return 1;
875+ } else if (S_ISDIR((*b)->fts_statp->st_mode)) {
876+ return -1;
877+ }
878+ return strcmp((*a)->fts_name, (*b)->fts_name);
879+}
+186,
-0
1@@ -0,0 +1,186 @@
2+/* $NetBSD: stat_flags.c,v 1.3 2022/04/19 20:32:17 rillig Exp $ */
3+
4+/*-
5+ * Copyright (c) 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ */
32+
33+#if HAVE_NBTOOL_CONFIG_H
34+#include "nbtool_config.h"
35+#else
36+#define HAVE_STRUCT_STAT_ST_FLAGS 1
37+#endif
38+
39+#include <sys/cdefs.h>
40+#if !defined(lint)
41+#if 0
42+static char sccsid[] = "@(#)stat_flags.c 8.2 (Berkeley) 7/28/94";
43+#else
44+__RCSID("$NetBSD: stat_flags.c,v 1.3 2022/04/19 20:32:17 rillig Exp $");
45+#endif
46+#endif /* not lint */
47+
48+#include <sys/types.h>
49+#include <sys/stat.h>
50+#include <fts.h>
51+#include <stddef.h>
52+#include <string.h>
53+#include <stdlib.h>
54+
55+#include "util.h"
56+
57+#define SAPPEND(s) do { \
58+ if (prefix != NULL) \
59+ (void)strlcat(string, prefix, sizeof(string)); \
60+ (void)strlcat(string, s, sizeof(string)); \
61+ prefix = ","; \
62+} while (0)
63+
64+/*
65+ * flags_to_string --
66+ * Convert stat flags to a comma-separated string. If no flags
67+ * are set, return the default string.
68+ */
69+char *
70+flags_to_string(u_long flags, const char *def)
71+{
72+ char string[128];
73+ const char *prefix;
74+
75+ string[0] = '\0';
76+ prefix = NULL;
77+#if HAVE_STRUCT_STAT_ST_FLAGS
78+ if (flags & UF_APPEND)
79+ SAPPEND("uappnd");
80+ if (flags & UF_IMMUTABLE)
81+ SAPPEND("uchg");
82+ if (flags & UF_NODUMP)
83+ SAPPEND("nodump");
84+ if (flags & UF_OPAQUE)
85+ SAPPEND("opaque");
86+ if (flags & SF_APPEND)
87+ SAPPEND("sappnd");
88+ if (flags & SF_ARCHIVED)
89+ SAPPEND("arch");
90+ if (flags & SF_IMMUTABLE)
91+ SAPPEND("schg");
92+#ifdef SF_SNAPSHOT
93+ if (flags & SF_SNAPSHOT)
94+ SAPPEND("snap");
95+#endif
96+#endif
97+ if (prefix != NULL)
98+ return strdup(string);
99+ return strdup(def);
100+}
101+
102+#define TEST(a, b, f) { \
103+ if (!strcmp(a, b)) { \
104+ if (clear) { \
105+ if (clrp) \
106+ *clrp |= (f); \
107+ if (setp) \
108+ *setp &= ~(f); \
109+ } else { \
110+ if (setp) \
111+ *setp |= (f); \
112+ if (clrp) \
113+ *clrp &= ~(f); \
114+ } \
115+ break; \
116+ } \
117+}
118+
119+/*
120+ * string_to_flags --
121+ * Take string of arguments and return stat flags. Return 0 on
122+ * success, 1 on failure. On failure, stringp is set to point
123+ * to the offending token.
124+ */
125+int
126+string_to_flags(char **stringp, u_long *setp, u_long *clrp)
127+{
128+ int clear;
129+ char *string, *p;
130+
131+ if (setp)
132+ *setp = 0;
133+ if (clrp)
134+ *clrp = 0;
135+
136+#if HAVE_STRUCT_STAT_ST_FLAGS
137+ string = *stringp;
138+ while ((p = strsep(&string, "\t ,")) != NULL) {
139+ clear = 0;
140+ *stringp = p;
141+ if (*p == '\0')
142+ continue;
143+ if (p[0] == 'n' && p[1] == 'o') {
144+ clear = 1;
145+ p += 2;
146+ }
147+ switch (p[0]) {
148+ case 'a':
149+ TEST(p, "arch", SF_ARCHIVED);
150+ TEST(p, "archived", SF_ARCHIVED);
151+ return (1);
152+ case 'd':
153+ clear = !clear;
154+ TEST(p, "dump", UF_NODUMP);
155+ return (1);
156+ case 'n':
157+ /*
158+ * Support `nonodump'. Note that
159+ * the state of clear is not changed.
160+ */
161+ TEST(p, "nodump", UF_NODUMP);
162+ return (1);
163+ case 'o':
164+ TEST(p, "opaque", UF_OPAQUE);
165+ return (1);
166+ case 's':
167+ TEST(p, "sappnd", SF_APPEND);
168+ TEST(p, "sappend", SF_APPEND);
169+ TEST(p, "schg", SF_IMMUTABLE);
170+ TEST(p, "schange", SF_IMMUTABLE);
171+ TEST(p, "simmutable", SF_IMMUTABLE);
172+ return (1);
173+ case 'u':
174+ TEST(p, "uappnd", UF_APPEND);
175+ TEST(p, "uappend", UF_APPEND);
176+ TEST(p, "uchg", UF_IMMUTABLE);
177+ TEST(p, "uchange", UF_IMMUTABLE);
178+ TEST(p, "uimmutable", UF_IMMUTABLE);
179+ return (1);
180+ default:
181+ return (1);
182+ }
183+ }
184+#endif
185+
186+ return (0);
187+}
+35,
-0
1@@ -0,0 +1,35 @@
2+/* $NetBSD: stat_flags.h,v 1.4 2003/08/07 09:05:16 agc Exp $ */
3+
4+/*-
5+ * Copyright (c) 1991, 1993
6+ * The Regents of the University of California. All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ * 3. Neither the name of the University nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+ * SUCH DAMAGE.
31+ *
32+ * @(#)extern.h 8.1 (Berkeley) 5/31/93
33+ */
34+
35+char *flags_to_string(u_long, const char *);
36+int string_to_flags(char **, u_long *, u_long *);
+1476,
-0
1@@ -0,0 +1,1476 @@
2+/* $NetBSD: bootblock.h,v 1.62 2026/01/09 15:43:07 nia Exp $ */
3+
4+/*-
5+ * Copyright (c) 2002-2004 The NetBSD Foundation, Inc.
6+ * All rights reserved.
7+ *
8+ * Redistribution and use in source and binary forms, with or without
9+ * modification, are permitted provided that the following conditions
10+ * are met:
11+ * 1. Redistributions of source code must retain the above copyright
12+ * notice, this list of conditions and the following disclaimer.
13+ * 2. Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in the
15+ * documentation and/or other materials provided with the distribution.
16+ *
17+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+ * POSSIBILITY OF SUCH DAMAGE.
28+ */
29+/*-
30+ * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
31+ * Michael L. Finch, Bradley A. Grantham, and
32+ * Lawrence A. Kesteloot
33+ * All rights reserved.
34+ *
35+ * Redistribution and use in source and binary forms, with or without
36+ * modification, are permitted provided that the following conditions
37+ * are met:
38+ * 1. Redistributions of source code must retain the above copyright
39+ * notice, this list of conditions and the following disclaimer.
40+ * 2. Redistributions in binary form must reproduce the above copyright
41+ * notice, this list of conditions and the following disclaimer in the
42+ * documentation and/or other materials provided with the distribution.
43+ * 3. All advertising materials mentioning features or use of this software
44+ * must display the following acknowledgement:
45+ * This product includes software developed by the Alice Group.
46+ * 4. The names of the Alice Group or any of its members may not be used
47+ * to endorse or promote products derived from this software without
48+ * specific prior written permission.
49+ *
50+ * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
51+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53+ * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
54+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60+ *
61+ */
62+/*
63+ * Copyright (c) 1994, 1999 Christopher G. Demetriou
64+ * All rights reserved.
65+ *
66+ * Redistribution and use in source and binary forms, with or without
67+ * modification, are permitted provided that the following conditions
68+ * are met:
69+ * 1. Redistributions of source code must retain the above copyright
70+ * notice, this list of conditions and the following disclaimer.
71+ * 2. Redistributions in binary form must reproduce the above copyright
72+ * notice, this list of conditions and the following disclaimer in the
73+ * documentation and/or other materials provided with the distribution.
74+ * 3. All advertising materials mentioning features or use of this software
75+ * must display the following acknowledgement:
76+ * This product includes software developed by Christopher G. Demetriou
77+ * for the NetBSD Project.
78+ * 4. The name of the author may not be used to endorse or promote products
79+ * derived from this software without specific prior written permission
80+ *
81+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
82+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
83+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
84+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
85+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
86+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
87+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
88+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
89+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
90+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91+ */
92+/*
93+ * Copyright (c) 1994 Rolf Grossmann
94+ * All rights reserved.
95+ *
96+ * Redistribution and use in source and binary forms, with or without
97+ * modification, are permitted provided that the following conditions
98+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
100+ * notice, this list of conditions and the following disclaimer.
101+ * 2. Redistributions in binary form must reproduce the above copyright
102+ * notice, this list of conditions and the following disclaimer in the
103+ * documentation and/or other materials provided with the distribution.
104+ * 3. All advertising materials mentioning features or use of this software
105+ * must display the following acknowledgement:
106+ * This product includes software developed by Rolf Grossmann.
107+ * 4. The name of the author may not be used to endorse or promote products
108+ * derived from this software without specific prior written permission
109+ *
110+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
111+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
112+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
113+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
114+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
115+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
116+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
117+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
118+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
119+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
120+ */
121+
122+#ifndef _SYS_BOOTBLOCK_H
123+#define _SYS_BOOTBLOCK_H
124+
125+#if !defined(__ASSEMBLER__)
126+#include <sys/cdefs.h>
127+#include <sys/endian.h>
128+#if defined(_KERNEL) || defined(_STANDALONE)
129+#include <sys/stdint.h>
130+#else
131+#include <stdint.h>
132+#endif
133+#endif /* !defined(__ASSEMBLER__) */
134+
135+/* ------------------------------------------
136+ * MBR (Master Boot Record) --
137+ * definitions for systems that use MBRs
138+ */
139+
140+/*
141+ * Layout of boot records:
142+ *
143+ * Byte range Use Description
144+ * ---------- --- -----------
145+ *
146+ * 0 - 2 FMP JMP xxx, NOP
147+ * 3 - 10 FP OEM Name
148+ *
149+ * 11 - 61 FMP FAT12/16 BPB
150+ * Whilst not strictly necessary for MBR,
151+ * GRUB reserves this area
152+ *
153+ * 11 - 89 P FAT32 BPB
154+ * (are we ever going to boot off this?)
155+ *
156+ *
157+ * 62 - 217 FMP Boot code
158+ *
159+ * 90 - 217 P FAT32 boot code
160+ *
161+ * 218 - 223 M Win95b/98/me "drive time"
162+ * http://www.geocities.com/thestarman3/asm/mbr/95BMEMBR.htm#MYST
163+ * only changed if all 6 bytes are 0
164+ *
165+ * 224 - 436 FMP boot code (continued)
166+ *
167+ * 437 - 439 M WinNT/2K/XP MBR "boot language"
168+ * http://www.geocities.com/thestarman3/asm/mbr/Win2kmbr.htm
169+ * not needed by us
170+ *
171+ * 400 - 439 MP NetBSD: mbr_bootsel
172+ *
173+ * 424 - 439 M NetBSD: bootptn_guid (in GPT PMBR only)
174+ *
175+ * 440 - 443 M WinNT/2K/XP Drive Serial Number (NT DSN)
176+ * http://www.geocities.com/thestarman3/asm/mbr/Win2kmbr.htm
177+ *
178+ * 444 - 445 FMP bootcode or unused
179+ * NetBSD: mbr_bootsel_magic
180+ *
181+ * 446 - 509 M partition table
182+ *
183+ * 510 - 511 FMP magic number (0xAA55)
184+ *
185+ * Use:
186+ * ----
187+ * F Floppy boot sector
188+ * M Master Boot Record
189+ * P Partition Boot record
190+ *
191+ */
192+
193+/*
194+ * MBR (Master Boot Record)
195+ */
196+#define MBR_BBSECTOR 0 /* MBR relative sector # */
197+#define MBR_BPB_OFFSET 11 /* offsetof(mbr_sector, mbr_bpb) */
198+#define MBR_BOOTCODE_OFFSET 90 /* offsetof(mbr_sector, mbr_bootcode) */
199+#define MBR_BS_OFFSET 400 /* offsetof(mbr_sector, mbr_bootsel) */
200+#define MBR_BS_OLD_OFFSET 404 /* where mbr_bootsel used to be */
201+#define MBR_GPT_GUID_OFFSET 424 /* location of partition GUID to boot */
202+#define MBR_GPT_GUID_DEFAULT /* default uninitialized GUID */ \
203+ {0xeee69d04,0x02f4,0x11e0,0x8f,0x5d,{0x00,0xe0,0x81,0x52,0x9a,0x6b}}
204+#define MBR_DSN_OFFSET 440 /* offsetof(mbr_sector, mbr_dsn) */
205+#define MBR_BS_MAGIC_OFFSET 444 /* offsetof(mbr_sector, mbr_bootsel_magic) */
206+#define MBR_PART_OFFSET 446 /* offsetof(mbr_sector, mbr_part[0]) */
207+#define MBR_MAGIC_OFFSET 510 /* offsetof(mbr_sector, mbr_magic) */
208+#define MBR_MAGIC 0xaa55 /* MBR magic number */
209+#define MBR_BS_MAGIC 0xb5e1 /* mbr_bootsel magic number */
210+#define MBR_PART_COUNT 4 /* Number of partitions in MBR */
211+#define MBR_BS_PARTNAMESIZE 8 /* Size of name mbr_bootsel nametab */
212+ /* (excluding trailing NUL) */
213+
214+ /* values for mbr_partition.mbrp_flag */
215+#define MBR_PFLAG_ACTIVE 0x80 /* The active partition */
216+
217+ /* values for mbr_partition.mbrp_type */
218+#define MBR_PTYPE_UNUSED 0x00 /* Unused */
219+#define MBR_PTYPE_FAT12 0x01 /* 12-bit FAT */
220+#define MBR_PTYPE_XENIX_ROOT 0x02 /* XENIX / */
221+#define MBR_PTYPE_XENIX_USR 0x03 /* XENIX /usr */
222+#define MBR_PTYPE_FAT16S 0x04 /* 16-bit FAT, less than 32M */
223+#define MBR_PTYPE_EXT 0x05 /* extended partition */
224+#define MBR_PTYPE_FAT16B 0x06 /* 16-bit FAT, more than 32M */
225+#define MBR_PTYPE_NTFS 0x07 /* OS/2 HPFS, NTFS, QNX2, Adv. UNIX */
226+#define MBR_PTYPE_DELL 0x08 /* AIX or os, or etc. */
227+#define MBR_PTYPE_AIX_BOOT 0x09 /* AIX boot partition or Coherent */
228+#define MBR_PTYPE_OS2_BOOT 0x0a /* O/2 boot manager or Coherent swap */
229+#define MBR_PTYPE_FAT32 0x0b /* 32-bit FAT */
230+#define MBR_PTYPE_FAT32L 0x0c /* 32-bit FAT, LBA-mapped */
231+#define MBR_PTYPE_7XXX 0x0d /* 7XXX, LBA-mapped */
232+#define MBR_PTYPE_FAT16L 0x0e /* 16-bit FAT, LBA-mapped */
233+#define MBR_PTYPE_EXT_LBA 0x0f /* extended partition, LBA-mapped */
234+#define MBR_PTYPE_OPUS 0x10 /* OPUS */
235+#define MBR_PTYPE_OS2_DOS12 0x11 /* OS/2 DOS 12-bit FAT */
236+#define MBR_PTYPE_COMPAQ_DIAG 0x12 /* Compaq diagnostics */
237+#define MBR_PTYPE_OS2_DOS16S 0x14 /* OS/2 DOS 16-bit FAT <32M */
238+#define MBR_PTYPE_OS2_DOS16B 0x16 /* OS/2 DOS 16-bit FAT >=32M */
239+#define MBR_PTYPE_OS2_IFS 0x17 /* OS/2 hidden IFS */
240+#define MBR_PTYPE_AST_SWAP 0x18 /* AST Windows swapfile */
241+#define MBR_PTYPE_WILLOWTECH 0x19 /* Willowtech Photon coS */
242+#define MBR_PTYPE_HID_FAT32 0x1b /* hidden win95 fat 32 */
243+#define MBR_PTYPE_HID_FAT32_LBA 0x1c /* hidden win95 fat 32 lba */
244+#define MBR_PTYPE_HID_FAT16_LBA 0x1d /* hidden win95 fat 16 lba */
245+#define MBR_PTYPE_WILLOWSOFT 0x20 /* Willowsoft OFS1 */
246+#define MBR_PTYPE_RESERVED_x21 0x21 /* reserved */
247+#define MBR_PTYPE_RESERVED_x23 0x23 /* reserved */
248+#define MBR_PTYPE_RESERVED_x24 0x24 /* NEC DOS */
249+#define MBR_PTYPE_RESERVED_x26 0x26 /* reserved */
250+#define MBR_PTYPE_RESERVED_x31 0x31 /* reserved */
251+#define MBR_PTYPE_NOS 0x32 /* Alien Internet Services NOS */
252+#define MBR_PTYPE_RESERVED_x33 0x33 /* reserved */
253+#define MBR_PTYPE_RESERVED_x34 0x34 /* reserved */
254+#define MBR_PTYPE_OS2_JFS 0x35 /* JFS on OS2 */
255+#define MBR_PTYPE_RESERVED_x36 0x36 /* reserved */
256+#define MBR_PTYPE_THEOS 0x38 /* Theos */
257+#define MBR_PTYPE_PLAN9 0x39 /* Plan 9, or Theos spanned */
258+#define MBR_PTYPE_THEOS_4GB 0x3a /* Theos ver 4 4gb partition */
259+#define MBR_PTYPE_THEOS_EXT 0x3b /* Theos ve 4 extended partition */
260+#define MBR_PTYPE_PMRECOVERY 0x3c /* PartitionMagic recovery */
261+#define MBR_PTYPE_HID_NETWARE 0x3d /* Hidden Netware */
262+#define MBR_PTYPE_VENIX 0x40 /* VENIX 286 or LynxOS */
263+#define MBR_PTYPE_PREP 0x41 /* PReP */
264+#define MBR_PTYPE_DRDOS_LSWAP 0x42 /* linux swap sharing DRDOS disk */
265+#define MBR_PTYPE_DRDOS_LINUX 0x43 /* linux sharing DRDOS disk */
266+#define MBR_PTYPE_GOBACK 0x44 /* GoBack change utility */
267+#define MBR_PTYPE_BOOT_US 0x45 /* Boot US Boot manager */
268+#define MBR_PTYPE_EUMEL_x46 0x46 /* EUMEL/Elan or Ergos 3 */
269+#define MBR_PTYPE_EUMEL_x47 0x47 /* EUMEL/Elan or Ergos 3 */
270+#define MBR_PTYPE_EUMEL_x48 0x48 /* EUMEL/Elan or Ergos 3 */
271+#define MBR_PTYPE_ALFS_THIN 0x4a /* ALFX/THIN filesystem for DOS */
272+#define MBR_PTYPE_OBERON 0x4c /* Oberon partition */
273+#define MBR_PTYPE_QNX4X 0x4d /* QNX4.x */
274+#define MBR_PTYPE_QNX4X_2 0x4e /* QNX4.x 2nd part */
275+#define MBR_PTYPE_QNX4X_3 0x4f /* QNX4.x 3rd part */
276+#define MBR_PTYPE_DM 0x50 /* DM (disk manager) */
277+#define MBR_PTYPE_DM6_AUX1 0x51 /* DM6 Aux1 (or Novell) */
278+#define MBR_PTYPE_CPM 0x52 /* CP/M or Microport SysV/AT */
279+#define MBR_PTYPE_DM6_AUX3 0x53 /* DM6 Aux3 */
280+#define MBR_PTYPE_DM6_DDO 0x54 /* DM6 DDO */
281+#define MBR_PTYPE_EZDRIVE 0x55 /* EZ-Drive (disk manager) */
282+#define MBR_PTYPE_GOLDEN_BOW 0x56 /* Golden Bow (disk manager) */
283+#define MBR_PTYPE_DRIVE_PRO 0x57 /* Drive PRO */
284+#define MBR_PTYPE_PRIAM_EDISK 0x5c /* Priam Edisk (disk manager) */
285+#define MBR_PTYPE_SPEEDSTOR 0x61 /* SpeedStor */
286+#define MBR_PTYPE_HURD 0x63 /* GNU HURD or Mach or Sys V/386 */
287+#define MBR_PTYPE_NOVELL_2XX 0x64 /* Novell Netware 2.xx or Speedstore */
288+#define MBR_PTYPE_NOVELL_3XX 0x65 /* Novell Netware 3.xx */
289+#define MBR_PTYPE_NOVELL_386 0x66 /* Novell 386 Netware */
290+#define MBR_PTYPE_NOVELL_x67 0x67 /* Novell */
291+#define MBR_PTYPE_NOVELL_x68 0x68 /* Novell */
292+#define MBR_PTYPE_NOVELL_x69 0x69 /* Novell */
293+#define MBR_PTYPE_DISKSECURE 0x70 /* DiskSecure Multi-Boot */
294+#define MBR_PTYPE_RESERVED_x71 0x71 /* reserved */
295+#define MBR_PTYPE_RESERVED_x73 0x73 /* reserved */
296+#define MBR_PTYPE_RESERVED_x74 0x74 /* reserved */
297+#define MBR_PTYPE_PCIX 0x75 /* PC/IX */
298+#define MBR_PTYPE_RESERVED_x76 0x76 /* reserved */
299+#define MBR_PTYPE_M2FS_M2CS 0x77 /* M2FS/M2CS partition */
300+#define MBR_PTYPE_XOSL_FS 0x78 /* XOSL boot loader filesystem */
301+#define MBR_PTYPE_MINIX_14A 0x80 /* MINIX until 1.4a */
302+#define MBR_PTYPE_MINIX_14B 0x81 /* MINIX since 1.4b */
303+#define MBR_PTYPE_LNXSWAP 0x82 /* Linux swap or Solaris */
304+#define MBR_PTYPE_LNXEXT2 0x83 /* Linux native */
305+#define MBR_PTYPE_OS2_C 0x84 /* OS/2 hidden C: drive */
306+#define MBR_PTYPE_EXT_LNX 0x85 /* Linux extended partition */
307+#define MBR_PTYPE_NTFATVOL 0x86 /* NT FAT volume set */
308+#define MBR_PTYPE_NTFSVOL 0x87 /* NTFS volume set or HPFS mirrored */
309+#define MBR_PTYPE_LNX_KERNEL 0x8a /* Linux Kernel AiR-BOOT partition */
310+#define MBR_PTYPE_FT_FAT32 0x8b /* Legacy Fault tolerant FAT32 */
311+#define MBR_PTYPE_FT_FAT32_EXT 0x8c /* Legacy Fault tolerant FAT32 ext */
312+#define MBR_PTYPE_HID_FR_FD_12 0x8d /* Hidden free FDISK FAT12 */
313+#define MBR_PTYPE_LNX_LVM 0x8e /* Linux Logical Volume Manager */
314+#define MBR_PTYPE_HID_FR_FD_16 0x90 /* Hidden free FDISK FAT16 */
315+#define MBR_PTYPE_HID_FR_FD_EXT 0x91 /* Hidden free FDISK DOS EXT */
316+#define MBR_PTYPE_HID_FR_FD_16B 0x92 /* Hidden free FDISK FAT16 Big */
317+#define MBR_PTYPE_AMOEBA_FS 0x93 /* Amoeba filesystem */
318+#define MBR_PTYPE_AMOEBA_BAD 0x94 /* Amoeba bad block table */
319+#define MBR_PTYPE_MIT_EXOPC 0x95 /* MIT EXOPC native partitions */
320+#define MBR_PTYPE_HID_FR_FD_32 0x97 /* Hidden free FDISK FAT32 */
321+#define MBR_PTYPE_DATALIGHT 0x98 /* Datalight ROM-DOS Super-Boot */
322+#define MBR_PTYPE_MYLEX 0x99 /* Mylex EISA SCSI */
323+#define MBR_PTYPE_HID_FR_FD_16L 0x9a /* Hidden free FDISK FAT16 LBA */
324+#define MBR_PTYPE_HID_FR_FD_EXL 0x9b /* Hidden free FDISK EXT LBA */
325+#define MBR_PTYPE_BSDI 0x9f /* BSDI? */
326+#define MBR_PTYPE_IBM_HIB 0xa0 /* IBM Thinkpad hibernation */
327+#define MBR_PTYPE_HP_VOL_xA1 0xa1 /* HP Volume expansion (SpeedStor) */
328+#define MBR_PTYPE_HP_VOL_xA3 0xa3 /* HP Volume expansion (SpeedStor) */
329+#define MBR_PTYPE_HP_VOL_xA4 0xa4 /* HP Volume expansion (SpeedStor) */
330+#define MBR_PTYPE_386BSD 0xa5 /* 386BSD partition type */
331+#define MBR_PTYPE_OPENBSD 0xa6 /* OpenBSD partition type */
332+#define MBR_PTYPE_NEXTSTEP_486 0xa7 /* NeXTSTEP 486 */
333+#define MBR_PTYPE_APPLE_UFS 0xa8 /* Apple UFS */
334+#define MBR_PTYPE_NETBSD 0xa9 /* NetBSD partition type */
335+#define MBR_PTYPE_OLIVETTI 0xaa /* Olivetty Fat12 1.44MB Service part */
336+#define MBR_PTYPE_APPLE_BOOT 0xab /* Apple Boot */
337+#define MBR_PTYPE_SHAG_OS 0xae /* SHAG OS filesystem */
338+#define MBR_PTYPE_APPLE_HFS 0xaf /* Apple HFS */
339+#define MBR_PTYPE_BOOTSTAR_DUM 0xb0 /* BootStar Dummy */
340+#define MBR_PTYPE_RESERVED_xB1 0xb1 /* reserved */
341+#define MBR_PTYPE_RESERVED_xB3 0xb3 /* reserved */
342+#define MBR_PTYPE_RESERVED_xB4 0xb4 /* reserved */
343+#define MBR_PTYPE_RESERVED_xB6 0xb6 /* reserved */
344+#define MBR_PTYPE_BSDI_386 0xb7 /* BSDI BSD/386 filesystem */
345+#define MBR_PTYPE_BSDI_SWAP 0xb8 /* BSDI BSD/386 swap */
346+#define MBR_PTYPE_BOOT_WIZARD 0xbb /* Boot Wizard Hidden */
347+#define MBR_PTYPE_SOLARIS_8 0xbe /* Solaris 8 partition type */
348+#define MBR_PTYPE_SOLARIS 0xbf /* Solaris partition type */
349+#define MBR_PTYPE_CTOS 0xc0 /* CTOS */
350+#define MBR_PTYPE_DRDOS_FAT12 0xc1 /* DRDOS/sec (FAT-12) */
351+#define MBR_PTYPE_HID_LNX 0xc2 /* Hidden Linux */
352+#define MBR_PTYPE_HID_LNX_SWAP 0xc3 /* Hidden Linux swap */
353+#define MBR_PTYPE_DRDOS_FAT16S 0xc4 /* DRDOS/sec (FAT-16, < 32M) */
354+#define MBR_PTYPE_DRDOS_EXT 0xc5 /* DRDOS/sec (EXT) */
355+#define MBR_PTYPE_DRDOS_FAT16B 0xc6 /* DRDOS/sec (FAT-16, >= 32M) */
356+#define MBR_PTYPE_SYRINX 0xc7 /* Syrinx (Cyrnix?) or HPFS disabled */
357+#define MBR_PTYPE_DRDOS_8_xC8 0xc8 /* Reserved for DR-DOS 8.0+ */
358+#define MBR_PTYPE_DRDOS_8_xC9 0xc9 /* Reserved for DR-DOS 8.0+ */
359+#define MBR_PTYPE_DRDOS_8_xCA 0xca /* Reserved for DR-DOS 8.0+ */
360+#define MBR_PTYPE_DRDOS_74_CHS 0xcb /* DR-DOS 7.04+ Secured FAT32 CHS */
361+#define MBR_PTYPE_DRDOS_74_LBA 0xcc /* DR-DOS 7.04+ Secured FAT32 LBA */
362+#define MBR_PTYPE_CTOS_MEMDUMP 0xcd /* CTOS Memdump */
363+#define MBR_PTYPE_DRDOS_74_16X 0xce /* DR-DOS 7.04+ FAT16X LBA */
364+#define MBR_PTYPE_DRDOS_74_EXT 0xcf /* DR-DOS 7.04+ EXT LBA */
365+#define MBR_PTYPE_REAL32 0xd0 /* REAL/32 secure big partition */
366+#define MBR_PTYPE_MDOS_FAT12 0xd1 /* Old Multiuser DOS FAT12 */
367+#define MBR_PTYPE_MDOS_FAT16S 0xd4 /* Old Multiuser DOS FAT16 Small */
368+#define MBR_PTYPE_MDOS_EXT 0xd5 /* Old Multiuser DOS Extended */
369+#define MBR_PTYPE_MDOS_FAT16B 0xd6 /* Old Multiuser DOS FAT16 Big */
370+#define MBR_PTYPE_CPM_86 0xd8 /* CP/M 86 */
371+#define MBR_PTYPE_CONCURRENT 0xdb /* CP/M or Concurrent CP/M */
372+#define MBR_PTYPE_HID_CTOS_MEM 0xdd /* Hidden CTOS Memdump */
373+#define MBR_PTYPE_DELL_UTIL 0xde /* Dell PowerEdge Server utilities */
374+#define MBR_PTYPE_DGUX_VIRTUAL 0xdf /* DG/UX virtual disk manager */
375+#define MBR_PTYPE_STMICROELEC 0xe0 /* STMicroelectronics ST AVFS */
376+#define MBR_PTYPE_DOS_ACCESS 0xe1 /* DOS access or SpeedStor 12-bit */
377+#define MBR_PTYPE_STORDIM 0xe3 /* DOS R/O or Storage Dimensions */
378+#define MBR_PTYPE_SPEEDSTOR_16S 0xe4 /* SpeedStor 16-bit FAT < 1024 cyl. */
379+#define MBR_PTYPE_RESERVED_xE5 0xe5 /* reserved */
380+#define MBR_PTYPE_RESERVED_xE6 0xe6 /* reserved */
381+#define MBR_PTYPE_BEOS 0xeb /* BeOS */
382+#define MBR_PTYPE_PMBR 0xee /* GPT Protective MBR */
383+#define MBR_PTYPE_EFI 0xef /* EFI system partition */
384+#define MBR_PTYPE_LNX_PA_RISC 0xf0 /* Linux PA-RISC boot loader */
385+#define MBR_PTYPE_SPEEDSTOR_X 0xf1 /* SpeedStor or Storage Dimensions */
386+#define MBR_PTYPE_DOS33_SEC 0xf2 /* DOS 3.3+ Secondary */
387+#define MBR_PTYPE_RESERVED_xF3 0xf3 /* reserved */
388+#define MBR_PTYPE_SPEEDSTOR_L 0xf4 /* SpeedStor large partition */
389+#define MBR_PTYPE_PROLOGUE 0xf5 /* Prologue multi-volumen partition */
390+#define MBR_PTYPE_RESERVED_xF6 0xf6 /* reserved */
391+#define MBR_PTYPE_PCACHE 0xf9 /* pCache: ext2/ext3 persistent cache */
392+#define MBR_PTYPE_BOCHS 0xfa /* Bochs x86 emulator */
393+#define MBR_PTYPE_VMWARE 0xfb /* VMware File System */
394+#define MBR_PTYPE_VMWARE_SWAP 0xfc /* VMware Swap */
395+#define MBR_PTYPE_LNX_RAID 0xfd /* Linux RAID partition persistent sb */
396+#define MBR_PTYPE_LANSTEP 0xfe /* LANstep or IBM PS/2 IML */
397+#define MBR_PTYPE_XENIX_BAD 0xff /* Xenix Bad Block Table */
398+
399+#ifdef MBRPTYPENAMES
400+static const struct mbr_ptype {
401+ int id;
402+ const char *name;
403+} mbr_ptypes[] = {
404+ { MBR_PTYPE_UNUSED, "<UNUSED>" },
405+ { MBR_PTYPE_FAT12, "Primary DOS with 12 bit FAT" },
406+ { MBR_PTYPE_XENIX_ROOT, "XENIX / filesystem" },
407+ { MBR_PTYPE_XENIX_USR, "XENIX /usr filesystem" },
408+ { MBR_PTYPE_FAT16S, "Primary DOS with 16 bit FAT <32M" },
409+ { MBR_PTYPE_EXT, "Extended partition" },
410+ { MBR_PTYPE_FAT16B, "Primary 'big' DOS, 16-bit FAT (> 32MB)" },
411+ { MBR_PTYPE_NTFS, "NTFS, OS/2 HPFS, QNX2 or Advanced UNIX" },
412+ { MBR_PTYPE_DELL, "AIX filesystem or OS/2 (thru v1.3) or DELL "
413+ "multiple drives or Commodore DOS or SplitDrive" },
414+ { MBR_PTYPE_AIX_BOOT, "AIX boot partition or Coherent" },
415+ { MBR_PTYPE_OS2_BOOT, "OS/2 Boot Manager or Coherent swap or OPUS" },
416+ { MBR_PTYPE_FAT32, "Primary DOS with 32 bit FAT" },
417+ { MBR_PTYPE_FAT32L, "Primary DOS with 32 bit FAT - LBA" },
418+ { MBR_PTYPE_7XXX, "Type 7??? - LBA" },
419+ { MBR_PTYPE_FAT16L, "DOS (16-bit FAT) - LBA" },
420+ { MBR_PTYPE_EXT_LBA, "Ext. partition - LBA" },
421+ { MBR_PTYPE_OPUS, "OPUS" },
422+ { MBR_PTYPE_OS2_DOS12, "OS/2 BM: hidden DOS 12-bit FAT" },
423+ { MBR_PTYPE_COMPAQ_DIAG, "Compaq diagnostics" },
424+ { MBR_PTYPE_OS2_DOS16S, "OS/2 BM: hidden DOS 16-bit FAT <32M "
425+ "or Novell DOS 7.0 bug" },
426+ { MBR_PTYPE_OS2_DOS16B, "OS/2 BM: hidden DOS 16-bit FAT >=32M" },
427+ { MBR_PTYPE_OS2_IFS, "OS/2 BM: hidden IFS" },
428+ { MBR_PTYPE_AST_SWAP, "AST Windows swapfile" },
429+ { MBR_PTYPE_WILLOWTECH, "Willowtech Photon coS" },
430+ { MBR_PTYPE_HID_FAT32, "hidden Windows/95 FAT32" },
431+ { MBR_PTYPE_HID_FAT32_LBA, "hidden Windows/95 FAT32 LBA" },
432+ { MBR_PTYPE_HID_FAT16_LBA, "hidden Windows/95 FAT16 LBA" },
433+ { MBR_PTYPE_WILLOWSOFT, "Willowsoft OFS1" },
434+ { MBR_PTYPE_RESERVED_x21, "reserved" },
435+ { MBR_PTYPE_RESERVED_x23, "reserved" },
436+ { MBR_PTYPE_RESERVED_x24, "NEC DOS"},
437+ { MBR_PTYPE_RESERVED_x26, "reserved" },
438+ { MBR_PTYPE_RESERVED_x31, "reserved" },
439+ { MBR_PTYPE_NOS, "Alien Internet Services NOS" },
440+ { MBR_PTYPE_RESERVED_x33, "reserved" },
441+ { MBR_PTYPE_RESERVED_x34, "reserved" },
442+ { MBR_PTYPE_OS2_JFS, "JFS on OS2" },
443+ { MBR_PTYPE_RESERVED_x36, "reserved" },
444+ { MBR_PTYPE_THEOS, "Theos" },
445+ { MBR_PTYPE_PLAN9, "Plan 9" },
446+ { MBR_PTYPE_PLAN9, "Plan 9, or Theos spanned" },
447+ { MBR_PTYPE_THEOS_4GB, "Theos ver 4 4gb partition" },
448+ { MBR_PTYPE_THEOS_EXT, "Theos ve 4 extended partition" },
449+ { MBR_PTYPE_PMRECOVERY, "PartitionMagic recovery" },
450+ { MBR_PTYPE_HID_NETWARE, "Hidden Netware" },
451+ { MBR_PTYPE_VENIX, "VENIX 286 or LynxOS" },
452+ { MBR_PTYPE_PREP, "Linux/MINIX (sharing disk with DRDOS) "
453+ "or Personal RISC boot" },
454+ { MBR_PTYPE_DRDOS_LSWAP, "SFS or Linux swap "
455+ "(sharing disk with DRDOS)" },
456+ { MBR_PTYPE_DRDOS_LINUX, "Linux native (sharing disk with DRDOS)" },
457+ { MBR_PTYPE_GOBACK, "GoBack change utility" },
458+ { MBR_PTYPE_BOOT_US, "Boot US Boot manager" },
459+ { MBR_PTYPE_EUMEL_x46, "EUMEL/Elan or Ergos 3" },
460+ { MBR_PTYPE_EUMEL_x47, "EUMEL/Elan or Ergos 3" },
461+ { MBR_PTYPE_EUMEL_x48, "EUMEL/Elan or Ergos 3" },
462+ { MBR_PTYPE_ALFS_THIN, "ALFX/THIN filesystem for DOS" },
463+ { MBR_PTYPE_OBERON, "Oberon partition" },
464+ { MBR_PTYPE_QNX4X, "QNX4.x" },
465+ { MBR_PTYPE_QNX4X_2, "QNX4.x 2nd part" },
466+ { MBR_PTYPE_QNX4X_3, "QNX4.x 3rd part" },
467+ { MBR_PTYPE_DM, "DM (disk manager)" },
468+ { MBR_PTYPE_DM6_AUX1, "DM6 Aux1 (or Novell)" },
469+ { MBR_PTYPE_CPM, "CP/M or Microport SysV/AT" },
470+ { MBR_PTYPE_DM6_AUX3, "DM6 Aux3" },
471+ { MBR_PTYPE_DM6_DDO, "DM6 DDO" },
472+ { MBR_PTYPE_EZDRIVE, "EZ-Drive (disk manager)" },
473+ { MBR_PTYPE_GOLDEN_BOW, "Golden Bow (disk manager)" },
474+ { MBR_PTYPE_DRIVE_PRO, "Drive PRO" },
475+ { MBR_PTYPE_PRIAM_EDISK, "Priam Edisk (disk manager)" },
476+ { MBR_PTYPE_SPEEDSTOR, "SpeedStor" },
477+ { MBR_PTYPE_HURD, "GNU HURD or Mach or Sys V/386 "
478+ "(such as ISC UNIX) or MtXinu" },
479+ { MBR_PTYPE_NOVELL_2XX, "Novell Netware 2.xx or Speedstore" },
480+ { MBR_PTYPE_NOVELL_3XX, "Novell Netware 3.xx" },
481+ { MBR_PTYPE_NOVELL_386, "Novell 386 Netware" },
482+ { MBR_PTYPE_NOVELL_x67, "Novell" },
483+ { MBR_PTYPE_NOVELL_x68, "Novell" },
484+ { MBR_PTYPE_NOVELL_x69, "Novell" },
485+ { MBR_PTYPE_DISKSECURE, "DiskSecure Multi-Boot" },
486+ { MBR_PTYPE_RESERVED_x71, "reserved" },
487+ { MBR_PTYPE_RESERVED_x73, "reserved" },
488+ { MBR_PTYPE_RESERVED_x74, "reserved" },
489+ { MBR_PTYPE_PCIX, "PC/IX" },
490+ { MBR_PTYPE_RESERVED_x76, "reserved" },
491+ { MBR_PTYPE_M2FS_M2CS, "M2FS/M2CS partition" },
492+ { MBR_PTYPE_XOSL_FS, "XOSL boot loader filesystem" },
493+ { MBR_PTYPE_MINIX_14A, "MINIX until 1.4a" },
494+ { MBR_PTYPE_MINIX_14B, "MINIX since 1.4b, early Linux, Mitac dmgr" },
495+ { MBR_PTYPE_LNXSWAP, "Linux swap or Prime or Solaris" },
496+ { MBR_PTYPE_LNXEXT2, "Linux native" },
497+ { MBR_PTYPE_OS2_C, "OS/2 hidden C: drive" },
498+ { MBR_PTYPE_EXT_LNX, "Linux extended" },
499+ { MBR_PTYPE_NTFATVOL, "NT FAT volume set" },
500+ { MBR_PTYPE_NTFSVOL, "NTFS volume set or HPFS mirrored" },
501+ { MBR_PTYPE_LNX_KERNEL, "Linux Kernel AiR-BOOT partition" },
502+ { MBR_PTYPE_FT_FAT32, "Legacy Fault tolerant FAT32" },
503+ { MBR_PTYPE_FT_FAT32_EXT, "Legacy Fault tolerant FAT32 ext" },
504+ { MBR_PTYPE_HID_FR_FD_12, "Hidden free FDISK FAT12" },
505+ { MBR_PTYPE_LNX_LVM, "Linux Logical Volume Manager" },
506+ { MBR_PTYPE_HID_FR_FD_16, "Hidden free FDISK FAT16" },
507+ { MBR_PTYPE_HID_FR_FD_EXT, "Hidden free FDISK DOS EXT" },
508+ { MBR_PTYPE_HID_FR_FD_16L, "Hidden free FDISK FAT16 Large" },
509+ { MBR_PTYPE_AMOEBA_FS, "Amoeba filesystem" },
510+ { MBR_PTYPE_AMOEBA_BAD, "Amoeba bad block table" },
511+ { MBR_PTYPE_MIT_EXOPC, "MIT EXOPC native partitions" },
512+ { MBR_PTYPE_HID_FR_FD_32, "Hidden free FDISK FAT32" },
513+ { MBR_PTYPE_DATALIGHT, "Datalight ROM-DOS Super-Boot" },
514+ { MBR_PTYPE_MYLEX, "Mylex EISA SCSI" },
515+ { MBR_PTYPE_HID_FR_FD_16L, "Hidden free FDISK FAT16 LBA" },
516+ { MBR_PTYPE_HID_FR_FD_EXL, "Hidden free FDISK EXT LBA" },
517+ { MBR_PTYPE_BSDI, "BSDI?" },
518+ { MBR_PTYPE_IBM_HIB, "IBM Thinkpad hibernation" },
519+ { MBR_PTYPE_HP_VOL_xA1, "HP Volume expansion (SpeedStor)" },
520+ { MBR_PTYPE_HP_VOL_xA3, "HP Volume expansion (SpeedStor)" },
521+ { MBR_PTYPE_HP_VOL_xA4, "HP Volume expansion (SpeedStor)" },
522+ { MBR_PTYPE_386BSD, "FreeBSD or 386BSD or old NetBSD" },
523+ { MBR_PTYPE_OPENBSD, "OpenBSD" },
524+ { MBR_PTYPE_NEXTSTEP_486, "NeXTSTEP 486" },
525+ { MBR_PTYPE_APPLE_UFS, "Apple UFS" },
526+ { MBR_PTYPE_NETBSD, "NetBSD" },
527+ { MBR_PTYPE_OLIVETTI, "Olivetty Fat12 1.44MB Service part" },
528+ { MBR_PTYPE_SHAG_OS, "SHAG OS filesystem" },
529+ { MBR_PTYPE_BOOTSTAR_DUM, "BootStar Dummy" },
530+ { MBR_PTYPE_BOOT_WIZARD, "Boot Wizard Hidden" },
531+ { MBR_PTYPE_APPLE_BOOT, "Apple Boot" },
532+ { MBR_PTYPE_APPLE_HFS, "Apple HFS" },
533+ { MBR_PTYPE_RESERVED_xB6, "reserved" },
534+ { MBR_PTYPE_RESERVED_xB6, "reserved" },
535+ { MBR_PTYPE_RESERVED_xB6, "reserved" },
536+ { MBR_PTYPE_RESERVED_xB6, "reserved" },
537+ { MBR_PTYPE_BSDI_386, "BSDI BSD/386 filesystem" },
538+ { MBR_PTYPE_BSDI_SWAP, "BSDI BSD/386 swap" },
539+ { MBR_PTYPE_SOLARIS_8, "Solaris 8 boot partition" },
540+ { MBR_PTYPE_SOLARIS, "Solaris boot partition" },
541+ { MBR_PTYPE_CTOS, "CTOS" },
542+ { MBR_PTYPE_DRDOS_FAT12, "DRDOS/sec (FAT-12)" },
543+ { MBR_PTYPE_HID_LNX, "Hidden Linux" },
544+ { MBR_PTYPE_HID_LNX_SWAP, "Hidden Linux Swap" },
545+ { MBR_PTYPE_DRDOS_FAT16S, "DRDOS/sec (FAT-16, < 32M)" },
546+ { MBR_PTYPE_DRDOS_EXT, "DRDOS/sec (EXT)" },
547+ { MBR_PTYPE_DRDOS_FAT16B, "DRDOS/sec (FAT-16, >= 32M)" },
548+ { MBR_PTYPE_SYRINX, "Syrinx (Cyrnix?) or HPFS disabled" },
549+ { MBR_PTYPE_DRDOS_8_xC8, "Reserved for DR-DOS 8.0+" },
550+ { MBR_PTYPE_DRDOS_8_xC9, "Reserved for DR-DOS 8.0+" },
551+ { MBR_PTYPE_DRDOS_8_xCA, "Reserved for DR-DOS 8.0+" },
552+ { MBR_PTYPE_DRDOS_74_CHS, "DR-DOS 7.04+ Secured FAT32 CHS" },
553+ { MBR_PTYPE_DRDOS_74_LBA, "DR-DOS 7.04+ Secured FAT32 LBA" },
554+ { MBR_PTYPE_CTOS_MEMDUMP, "CTOS Memdump" },
555+ { MBR_PTYPE_DRDOS_74_16X, "DR-DOS 7.04+ FAT16X LBA" },
556+ { MBR_PTYPE_DRDOS_74_EXT, "DR-DOS 7.04+ EXT LBA" },
557+ { MBR_PTYPE_REAL32, "REAL/32 secure big partition" },
558+ { MBR_PTYPE_MDOS_FAT12, "Old Multiuser DOS FAT12" },
559+ { MBR_PTYPE_MDOS_FAT16S, "Old Multiuser DOS FAT16 Small" },
560+ { MBR_PTYPE_MDOS_EXT, "Old Multiuser DOS Extended" },
561+ { MBR_PTYPE_MDOS_FAT16B, "Old Multiuser DOS FAT16 Big" },
562+ { MBR_PTYPE_CPM_86, "CP/M 86" },
563+ { MBR_PTYPE_CONCURRENT, "CP/M or Concurrent CP/M or Concurrent DOS "
564+ "or CTOS" },
565+ { MBR_PTYPE_HID_CTOS_MEM, "Hidden CTOS Memdump" },
566+ { MBR_PTYPE_DELL_UTIL, "Dell PowerEdge Server utilities" },
567+ { MBR_PTYPE_DGUX_VIRTUAL, "DG/UX virtual disk manager" },
568+ { MBR_PTYPE_STMICROELEC, "STMicroelectronics ST AVFS" },
569+ { MBR_PTYPE_DOS_ACCESS, "DOS access or SpeedStor 12-bit FAT "
570+ "extended partition" },
571+ { MBR_PTYPE_STORDIM, "DOS R/O or SpeedStor or Storage Dimensions" },
572+ { MBR_PTYPE_SPEEDSTOR_16S, "SpeedStor 16-bit FAT extended partition "
573+ "< 1024 cyl." },
574+ { MBR_PTYPE_RESERVED_xE5, "reserved" },
575+ { MBR_PTYPE_RESERVED_xE6, "reserved" },
576+ { MBR_PTYPE_BEOS, "BeOS" },
577+ { MBR_PTYPE_PMBR, "GPT Protective MBR" },
578+ { MBR_PTYPE_EFI, "EFI system partition" },
579+ { MBR_PTYPE_LNX_PA_RISC, "Linux PA-RISC boot loader" },
580+ { MBR_PTYPE_SPEEDSTOR_X, "SpeedStor or Storage Dimensions" },
581+ { MBR_PTYPE_DOS33_SEC, "DOS 3.3+ Secondary" },
582+ { MBR_PTYPE_RESERVED_xF3, "reserved" },
583+ { MBR_PTYPE_SPEEDSTOR_L, "SpeedStor large partition or "
584+ "Storage Dimensions" },
585+ { MBR_PTYPE_PROLOGUE, "Prologue multi-volumen partition" },
586+ { MBR_PTYPE_RESERVED_xF6, "reserved" },
587+ { MBR_PTYPE_PCACHE, "pCache: ext2/ext3 persistent cache" },
588+ { MBR_PTYPE_BOCHS, "Bochs x86 emulator" },
589+ { MBR_PTYPE_VMWARE, "VMware File System" },
590+ { MBR_PTYPE_VMWARE_SWAP, "VMware Swap" },
591+ { MBR_PTYPE_LNX_RAID, "Linux RAID partition persistent sb" },
592+ { MBR_PTYPE_LANSTEP, "SpeedStor >1024 cyl. or LANstep "
593+ "or IBM PS/2 IML" },
594+ { MBR_PTYPE_XENIX_BAD, "Xenix Bad Block Table" },
595+};
596+#endif
597+
598+#define MBR_PSECT(s) ((s) & 0x3f)
599+#define MBR_PCYL(c, s) ((c) + (((s) & 0xc0) << 2))
600+
601+#define MBR_IS_EXTENDED(x) ((x) == MBR_PTYPE_EXT || \
602+ (x) == MBR_PTYPE_EXT_LBA || \
603+ (x) == MBR_PTYPE_EXT_LNX)
604+
605+ /* values for mbr_bootsel.mbrbs_flags */
606+#define MBR_BS_ACTIVE 0x01 /* Bootselector active (or code present) */
607+#define MBR_BS_EXTINT13 0x02 /* Set by fdisk if LBA needed (deprecated) */
608+#define MBR_BS_READ_LBA 0x04 /* Force LBA reads (deprecated) */
609+#define MBR_BS_EXTLBA 0x08 /* Extended ptn capable (LBA reads) */
610+#define MBR_BS_ASCII 0x10 /* Bootselect code needs ascii key code */
611+/* This is always set, the bootsel is located using the magic number... */
612+#define MBR_BS_NEWMBR 0x80 /* New bootsel at offset 440 */
613+
614+#if !defined(__ASSEMBLER__) /* { */
615+
616+/*
617+ * (x86) BIOS Parameter Block for FAT12
618+ */
619+struct mbr_bpbFAT12 {
620+ uint16_t bpbBytesPerSec; /* bytes per sector */
621+ uint8_t bpbSecPerClust; /* sectors per cluster */
622+ uint16_t bpbResSectors; /* number of reserved sectors */
623+ uint8_t bpbFATs; /* number of FATs */
624+ uint16_t bpbRootDirEnts; /* number of root directory entries */
625+ uint16_t bpbSectors; /* total number of sectors */
626+ uint8_t bpbMedia; /* media descriptor */
627+ uint16_t bpbFATsecs; /* number of sectors per FAT */
628+ uint16_t bpbSecPerTrack; /* sectors per track */
629+ uint16_t bpbHeads; /* number of heads */
630+ uint16_t bpbHiddenSecs; /* # of hidden sectors */
631+} __packed;
632+
633+/*
634+ * (x86) BIOS Parameter Block for FAT16
635+ */
636+struct mbr_bpbFAT16 {
637+ uint16_t bpbBytesPerSec; /* bytes per sector */
638+ uint8_t bpbSecPerClust; /* sectors per cluster */
639+ uint16_t bpbResSectors; /* number of reserved sectors */
640+ uint8_t bpbFATs; /* number of FATs */
641+ uint16_t bpbRootDirEnts; /* number of root directory entries */
642+ uint16_t bpbSectors; /* total number of sectors */
643+ uint8_t bpbMedia; /* media descriptor */
644+ uint16_t bpbFATsecs; /* number of sectors per FAT */
645+ uint16_t bpbSecPerTrack; /* sectors per track */
646+ uint16_t bpbHeads; /* number of heads */
647+ uint32_t bpbHiddenSecs; /* # of hidden sectors */
648+ uint32_t bpbHugeSectors; /* # of sectors if bpbSectors == 0 */
649+ uint8_t bsDrvNum; /* Int 0x13 drive number (e.g. 0x80) */
650+ uint8_t bsReserved1; /* Reserved; set to 0 */
651+ uint8_t bsBootSig; /* 0x29 if next 3 fields are present */
652+ uint8_t bsVolID[4]; /* Volume serial number */
653+ uint8_t bsVolLab[11]; /* Volume label */
654+ uint8_t bsFileSysType[8];
655+ /* "FAT12 ", "FAT16 ", "FAT " */
656+} __packed;
657+
658+/*
659+ * (x86) BIOS Parameter Block for FAT32
660+ */
661+struct mbr_bpbFAT32 {
662+ uint16_t bpbBytesPerSec; /* bytes per sector */
663+ uint8_t bpbSecPerClust; /* sectors per cluster */
664+ uint16_t bpbResSectors; /* number of reserved sectors */
665+ uint8_t bpbFATs; /* number of FATs */
666+ uint16_t bpbRootDirEnts; /* number of root directory entries */
667+ uint16_t bpbSectors; /* total number of sectors */
668+ uint8_t bpbMedia; /* media descriptor */
669+ uint16_t bpbFATsecs; /* number of sectors per FAT */
670+ uint16_t bpbSecPerTrack; /* sectors per track */
671+ uint16_t bpbHeads; /* number of heads */
672+ uint32_t bpbHiddenSecs; /* # of hidden sectors */
673+ uint32_t bpbHugeSectors; /* # of sectors if bpbSectors == 0 */
674+ uint32_t bpbBigFATsecs; /* like bpbFATsecs for FAT32 */
675+ uint16_t bpbExtFlags; /* extended flags: */
676+#define MBR_FAT32_FATNUM 0x0F /* mask for numbering active FAT */
677+#define MBR_FAT32_FATMIRROR 0x80 /* FAT is mirrored (as previously) */
678+ uint16_t bpbFSVers; /* filesystem version */
679+#define MBR_FAT32_FSVERS 0 /* currently only 0 is understood */
680+ uint32_t bpbRootClust; /* start cluster for root directory */
681+ uint16_t bpbFSInfo; /* filesystem info structure sector */
682+ uint16_t bpbBackup; /* backup boot sector */
683+ uint8_t bsReserved[12]; /* Reserved for future expansion */
684+ uint8_t bsDrvNum; /* Int 0x13 drive number (e.g. 0x80) */
685+ uint8_t bsReserved1; /* Reserved; set to 0 */
686+ uint8_t bsBootSig; /* 0x29 if next 3 fields are present */
687+ uint8_t bsVolID[4]; /* Volume serial number */
688+ uint8_t bsVolLab[11]; /* Volume label */
689+ uint8_t bsFileSysType[8]; /* "FAT32 " */
690+} __packed;
691+
692+/*
693+ * (x86) MBR boot selector
694+ */
695+struct mbr_bootsel {
696+ uint8_t mbrbs_defkey;
697+ uint8_t mbrbs_flags;
698+ uint16_t mbrbs_timeo;
699+ char mbrbs_nametab[MBR_PART_COUNT][MBR_BS_PARTNAMESIZE + 1];
700+} __packed;
701+
702+/*
703+ * MBR partition
704+ */
705+struct mbr_partition {
706+ uint8_t mbrp_flag; /* MBR partition flags */
707+ uint8_t mbrp_shd; /* Starting head */
708+ uint8_t mbrp_ssect; /* Starting sector */
709+ uint8_t mbrp_scyl; /* Starting cylinder */
710+ uint8_t mbrp_type; /* Partition type (see below) */
711+ uint8_t mbrp_ehd; /* End head */
712+ uint8_t mbrp_esect; /* End sector */
713+ uint8_t mbrp_ecyl; /* End cylinder */
714+ uint32_t mbrp_start; /* Absolute starting sector number */
715+ uint32_t mbrp_size; /* Partition size in sectors */
716+} __packed;
717+
718+int xlat_mbr_fstype(int); /* in sys/lib/libkern/xlat_mbr_fstype.c */
719+
720+/*
721+ * MBR boot sector.
722+ * This is used by both the MBR (Master Boot Record) in sector 0 of the disk
723+ * and the PBR (Partition Boot Record) in sector 0 of an MBR partition.
724+ */
725+struct mbr_sector {
726+ /* Jump instruction to boot code. */
727+ /* Usually 0xE9nnnn or 0xEBnn90 */
728+ uint8_t mbr_jmpboot[3];
729+ /* OEM name and version */
730+ uint8_t mbr_oemname[8];
731+ union { /* BIOS Parameter Block */
732+ struct mbr_bpbFAT12 bpb12;
733+ struct mbr_bpbFAT16 bpb16;
734+ struct mbr_bpbFAT32 bpb32;
735+ } mbr_bpb;
736+ /* Boot code */
737+ uint8_t mbr_bootcode[310];
738+ /* Config for /usr/mdec/mbr_bootsel */
739+ struct mbr_bootsel mbr_bootsel;
740+ /* NT Drive Serial Number */
741+ uint32_t mbr_dsn;
742+ /* mbr_bootsel magic */
743+ uint16_t mbr_bootsel_magic;
744+ /* MBR partition table */
745+ struct mbr_partition mbr_parts[MBR_PART_COUNT];
746+ /* MBR magic (0xaa55) */
747+ uint16_t mbr_magic;
748+} __packed;
749+
750+#endif /* !defined(__ASSEMBLER__) */ /* } */
751+
752+
753+/* ------------------------------------------
754+ * shared --
755+ * definitions shared by many platforms
756+ */
757+
758+#if !defined(__ASSEMBLER__) /* { */
759+
760+ /* Maximum # of blocks in bbi_block_table, each bbi_block_size long */
761+#define SHARED_BBINFO_MAXBLOCKS 118 /* so sizeof(shared_bbinfo) == 512 */
762+
763+struct shared_bbinfo {
764+ uint8_t bbi_magic[32];
765+ int32_t bbi_block_size;
766+ int32_t bbi_block_count;
767+ int32_t bbi_block_table[SHARED_BBINFO_MAXBLOCKS];
768+};
769+
770+/* ------------------------------------------
771+ * alpha --
772+ * Alpha (disk, but also tape) Boot Block.
773+ *
774+ * See Section (III) 3.6.1 of the Alpha Architecture Reference Manual.
775+ */
776+
777+struct alpha_boot_block {
778+ uint64_t bb_data[63]; /* data (disklabel, also as below) */
779+ uint64_t bb_cksum; /* checksum of the boot block,
780+ * taken as uint64_t's
781+ */
782+};
783+#define bb_secsize bb_data[60] /* secondary size (blocks) */
784+#define bb_secstart bb_data[61] /* secondary start (blocks) */
785+#define bb_flags bb_data[62] /* unknown flags (set to zero) */
786+
787+#define ALPHA_BOOT_BLOCK_OFFSET 0 /* offset of boot block. */
788+#define ALPHA_BOOT_BLOCK_BLOCKSIZE 512 /* block size for sector
789+ * size/start, and for boot
790+ * block itself.
791+ */
792+
793+#define ALPHA_BOOT_BLOCK_CKSUM(bb,cksum) \
794+ do { \
795+ const struct alpha_boot_block *_bb = (bb); \
796+ uint64_t _cksum; \
797+ size_t _i; \
798+ \
799+ _cksum = 0; \
800+ for (_i = 0; \
801+ _i < (sizeof _bb->bb_data / sizeof _bb->bb_data[0]); \
802+ _i++) \
803+ _cksum += le64toh(_bb->bb_data[_i]); \
804+ *(cksum) = htole64(_cksum); \
805+ } while (0)
806+
807+/* ------------------------------------------
808+ * apple --
809+ * Apple computers boot block related information
810+ */
811+
812+/*
813+ * Driver Descriptor Map, from Inside Macintosh: Devices, SCSI Manager
814+ * pp 12-13. The driver descriptor map always resides on physical block 0.
815+ */
816+struct apple_drvr_descriptor {
817+ uint32_t descBlock; /* first block of driver */
818+ uint16_t descSize; /* driver size in blocks */
819+ uint16_t descType; /* system type */
820+} __packed;
821+
822+/*
823+ * system types; Apple reserves 0-15
824+ */
825+#define APPLE_DRVR_TYPE_MACINTOSH 1
826+
827+#define APPLE_DRVR_MAP_MAGIC 0x4552
828+#define APPLE_DRVR_MAP_MAX_DESCRIPTORS 61
829+
830+struct apple_drvr_map {
831+ uint16_t sbSig; /* map signature */
832+ uint16_t sbBlockSize; /* block size of device */
833+ uint32_t sbBlkCount; /* number of blocks on device */
834+ uint16_t sbDevType; /* (used internally by ROM) */
835+ uint16_t sbDevID; /* (used internally by ROM) */
836+ uint32_t sbData; /* (used internally by ROM) */
837+ uint16_t sbDrvrCount; /* number of driver descriptors */
838+ struct apple_drvr_descriptor sb_dd[APPLE_DRVR_MAP_MAX_DESCRIPTORS];
839+ uint16_t pad[3];
840+} __packed;
841+
842+/*
843+ * Partition map structure from Inside Macintosh: Devices, SCSI Manager
844+ * pp. 13-14. The partition map always begins on physical block 1.
845+ *
846+ * With the exception of block 0, all blocks on the disk must belong to
847+ * exactly one partition. The partition map itself belongs to a partition
848+ * of type `APPLE_PARTITION_MAP', and is not limited in size by anything
849+ * other than available disk space. The partition map is not necessarily
850+ * the first partition listed.
851+ */
852+#define APPLE_PART_MAP_ENTRY_MAGIC 0x504d
853+
854+struct apple_part_map_entry {
855+ uint16_t pmSig; /* partition signature */
856+ uint16_t pmSigPad; /* (reserved) */
857+ uint32_t pmMapBlkCnt; /* number of blocks in partition map */
858+ uint32_t pmPyPartStart; /* first physical block of partition */
859+ uint32_t pmPartBlkCnt; /* number of blocks in partition */
860+ uint8_t pmPartName[32]; /* partition name */
861+ uint8_t pmPartType[32]; /* partition type */
862+ uint32_t pmLgDataStart; /* first logical block of data area */
863+ uint32_t pmDataCnt; /* number of blocks in data area */
864+ uint32_t pmPartStatus; /* partition status information */
865+/*
866+ * Partition Status Information from Apple Tech Note 1189
867+ */
868+#define APPLE_PS_VALID 0x00000001 /* Entry is valid */
869+#define APPLE_PS_ALLOCATED 0x00000002 /* Entry is allocated */
870+#define APPLE_PS_IN_USE 0x00000004 /* Entry in use */
871+#define APPLE_PS_BOOT_INFO 0x00000008 /* Entry contains boot info */
872+#define APPLE_PS_READABLE 0x00000010 /* Entry is readable */
873+#define APPLE_PS_WRITABLE 0x00000020 /* Entry is writable */
874+#define APPLE_PS_BOOT_CODE_PIC 0x00000040 /* Boot code has position
875+ * independent code */
876+#define APPLE_PS_CC_DRVR 0x00000100 /* Partition contains chain-
877+ * compatible driver */
878+#define APPLE_PS_RL_DRVR 0x00000200 /* Partition contains real
879+ * driver */
880+#define APPLE_PS_CH_DRVR 0x00000400 /* Partition contains chain
881+ * driver */
882+#define APPLE_PS_AUTO_MOUNT 0x40000000 /* Mount automatically at
883+ * startup */
884+#define APPLE_PS_STARTUP 0x80000000 /* Is the startup partition */
885+ uint32_t pmLgBootStart; /* first logical block of boot code */
886+ uint32_t pmBootSize; /* size of boot code, in bytes */
887+ uint32_t pmBootLoad; /* boot code load address */
888+ uint32_t pmBootLoad2; /* (reserved) */
889+ uint32_t pmBootEntry; /* boot code entry point */
890+ uint32_t pmBootEntry2; /* (reserved) */
891+ uint32_t pmBootCksum; /* boot code checksum */
892+ int8_t pmProcessor[16]; /* processor type (e.g. "68020") */
893+ uint8_t pmBootArgs[128]; /* A/UX boot arguments */
894+ uint8_t pad[248]; /* pad to end of block */
895+};
896+
897+#define APPLE_PART_TYPE_DRIVER "APPLE_DRIVER"
898+#define APPLE_PART_TYPE_DRIVER43 "APPLE_DRIVER43"
899+#define APPLE_PART_TYPE_DRIVERATA "APPLE_DRIVER_ATA"
900+#define APPLE_PART_TYPE_DRIVERIOKIT "APPLE_DRIVER_IOKIT"
901+#define APPLE_PART_TYPE_FWDRIVER "APPLE_FWDRIVER"
902+#define APPLE_PART_TYPE_FWB_COMPONENT "FWB DRIVER COMPONENTS"
903+#define APPLE_PART_TYPE_FREE "APPLE_FREE"
904+#define APPLE_PART_TYPE_MAC "APPLE_HFS"
905+#define APPLE_PART_TYPE_NETBSD "NETBSD"
906+#define APPLE_PART_TYPE_NBSD_PPCBOOT "NETBSD/MACPPC"
907+#define APPLE_PART_TYPE_NBSD_68KBOOT "NETBSD/MAC68K"
908+#define APPLE_PART_TYPE_PATCHES "APPLE_PATCHES"
909+#define APPLE_PART_TYPE_PARTMAP "APPLE_PARTITION_MAP"
910+#define APPLE_PART_TYPE_PATCHES "APPLE_PATCHES"
911+#define APPLE_PART_TYPE_SCRATCH "APPLE_SCRATCH"
912+#define APPLE_PART_TYPE_UNIX "APPLE_UNIX_SVR2"
913+
914+/*
915+ * "pmBootArgs" for APPLE_UNIX_SVR2 partition.
916+ * NetBSD/mac68k only uses Magic, Cluster, Type, and Flags.
917+ */
918+struct apple_blockzeroblock {
919+ uint32_t bzbMagic;
920+ uint8_t bzbCluster;
921+ uint8_t bzbType;
922+ uint16_t bzbBadBlockInode;
923+ uint16_t bzbFlags;
924+ uint16_t bzbReserved;
925+ uint32_t bzbCreationTime;
926+ uint32_t bzbMountTime;
927+ uint32_t bzbUMountTime;
928+};
929+
930+#define APPLE_BZB_MAGIC 0xABADBABE
931+#define APPLE_BZB_TYPEFS 1
932+#define APPLE_BZB_TYPESWAP 3
933+#define APPLE_BZB_ROOTFS 0x8000
934+#define APPLE_BZB_USRFS 0x4000
935+
936+/* ------------------------------------------
937+ * ews4800mips
938+ *
939+ */
940+
941+#define EWS4800MIPS_BBINFO_MAGIC "NetBSD/ews4800mips 20040611"
942+#define EWS4800MIPS_BOOT_BLOCK_OFFSET 0
943+#define EWS4800MIPS_BOOT_BLOCK_BLOCKSIZE 512
944+#define EWS4800MIPS_BOOT_BLOCK_MAX_SIZE (512 * 8)
945+
946+/* ------------------------------------------
947+ * hp300
948+ *
949+ */
950+
951+/* volume header for "LIF" format volumes */
952+
953+struct hp300_lifvol {
954+ uint16_t vol_id;
955+ char vol_label[6];
956+ uint32_t vol_addr;
957+ uint16_t vol_oct;
958+ uint16_t vol_dummy;
959+ uint32_t vol_dirsize;
960+ uint16_t vol_version;
961+ uint16_t vol_zero;
962+ uint32_t vol_huh1;
963+ uint32_t vol_huh2;
964+ uint32_t vol_length;
965+};
966+
967+/* LIF directory entry format */
968+
969+struct hp300_lifdir {
970+ char dir_name[10];
971+ uint16_t dir_type;
972+ uint32_t dir_addr;
973+ uint32_t dir_length;
974+ char dir_toc[6];
975+ uint16_t dir_flag;
976+ uint32_t dir_exec;
977+};
978+
979+/* load header for boot rom */
980+struct hp300_load {
981+ uint32_t address;
982+ uint32_t count;
983+};
984+
985+#define HP300_VOL_ID 0x8000 /* always $8000 */
986+#define HP300_VOL_OCT 4096
987+#define HP300_DIR_TYPE 0xe942 /* "SYS9k Series 9000" */
988+#define HP300_DIR_FLAG 0x8001 /* don't ask me! */
989+#define HP300_SECTSIZE 256
990+
991+#define HP300_LIF_NUMDIR 8
992+
993+#define HP300_LIF_VOLSTART 0
994+#define HP300_LIF_VOLSIZE sizeof(struct hp300_lifvol)
995+#define HP300_LIF_DIRSTART 512
996+#define HP300_LIF_DIRSIZE (HP300_LIF_NUMDIR * sizeof(struct hp300_lifdir))
997+#define HP300_LIF_FILESTART 8192
998+
999+#define hp300_btolifs(b) (((b) + (HP300_SECTSIZE - 1)) / HP300_SECTSIZE)
1000+#define hp300_lifstob(s) ((s) * HP300_SECTSIZE)
1001+
1002+
1003+/* ------------------------------------------
1004+ * hppa
1005+ *
1006+ */
1007+
1008+/*
1009+ * volume header for "LIF" format volumes
1010+ */
1011+struct hppa_lifvol {
1012+ uint16_t vol_id;
1013+ uint8_t vol_label[6];
1014+ uint32_t vol_addr;
1015+ uint16_t vol_oct;
1016+ uint16_t vol_dummy;
1017+
1018+ uint32_t vol_dirsize;
1019+ uint16_t vol_version;
1020+ uint16_t vol_zero;
1021+ uint32_t vol_number;
1022+ uint32_t vol_lastvol;
1023+
1024+ uint32_t vol_length;
1025+ uint8_t vol_toc[6];
1026+ uint8_t vol_dummy1[198];
1027+
1028+ uint32_t ipl_addr;
1029+ uint32_t ipl_size;
1030+ uint32_t ipl_entry;
1031+
1032+ uint32_t vol_dummy2;
1033+};
1034+
1035+struct hppa_lifdir {
1036+ uint8_t dir_name[10];
1037+ uint16_t dir_type;
1038+ uint32_t dir_addr;
1039+ uint32_t dir_length;
1040+ uint8_t dir_toc[6];
1041+ uint16_t dir_flag;
1042+ uint32_t dir_implement;
1043+};
1044+
1045+struct hppa_lifload {
1046+ int address;
1047+ int count;
1048+};
1049+
1050+#define HPPA_LIF_VOL_ID 0x8000
1051+#define HPPA_LIF_VOL_OCT 0x1000
1052+#define HPPA_LIF_DIR_SWAP 0x5243
1053+#define HPPA_LIF_DIR_FS 0xcd38
1054+#define HPPA_LIF_DIR_IOMAP 0xcd60
1055+#define HPPA_LIF_DIR_HPUX 0xcd80
1056+#define HPPA_LIF_DIR_ISL 0xce00
1057+#define HPPA_LIF_DIR_PAD 0xcffe
1058+#define HPPA_LIF_DIR_AUTO 0xcfff
1059+#define HPPA_LIF_DIR_EST 0xd001
1060+#define HPPA_LIF_DIR_TYPE 0xe942
1061+
1062+#define HPPA_LIF_DIR_FLAG 0x8001 /* dont ask me! */
1063+#define HPPA_LIF_SECTSIZE 256
1064+
1065+#define HPPA_LIF_NUMDIR 8
1066+
1067+#define HPPA_LIF_VOLSTART 0
1068+#define HPPA_LIF_VOLSIZE sizeof(struct hppa_lifvol)
1069+#define HPPA_LIF_DIRSTART 2048
1070+#define HPPA_LIF_DIRSIZE (HPPA_LIF_NUMDIR * sizeof(struct hppa_lifdir))
1071+#define HPPA_LIF_FILESTART 4096
1072+
1073+#define hppa_btolifs(b) (((b) + (HPPA_LIF_SECTSIZE - 1)) / HPPA_LIF_SECTSIZE)
1074+#define hppa_lifstob(s) ((s) * HPPA_LIF_SECTSIZE)
1075+#define hppa_lifstodb(s) ((s) * HPPA_LIF_SECTSIZE / DEV_BSIZE)
1076+
1077+
1078+/* ------------------------------------------
1079+ * x86
1080+ *
1081+ */
1082+
1083+/*
1084+ * Parameters for NetBSD /boot written to start of pbr code by installboot
1085+ */
1086+
1087+struct x86_boot_params {
1088+ uint32_t bp_length; /* length of patchable data */
1089+ uint32_t bp_flags;
1090+ uint32_t bp_timeout; /* boot timeout in seconds */
1091+ uint32_t bp_consdev;
1092+ uint32_t bp_conspeed;
1093+ uint8_t bp_password[16]; /* md5 hash of password */
1094+ char bp_keymap[64]; /* keyboard translation map */
1095+ uint32_t bp_consaddr; /* ioaddr for console */
1096+};
1097+
1098+#endif /* !defined(__ASSEMBLER__) */ /* } */
1099+
1100+#define X86_BOOT_MAGIC(n) ('x' << 24 | 0x86b << 12 | 'm' << 4 | (n))
1101+#define X86_BOOT_MAGIC_1 X86_BOOT_MAGIC(1) /* pbr.S */
1102+#define X86_BOOT_MAGIC_2 X86_BOOT_MAGIC(2) /* bootxx.S */
1103+#define X86_BOOT_MAGIC_PXE X86_BOOT_MAGIC(3) /* start_pxe.S */
1104+#define X86_BOOT_MAGIC_FAT X86_BOOT_MAGIC(4) /* fatboot.S */
1105+#define X86_BOOT_MAGIC_EFI X86_BOOT_MAGIC(5) /* efiboot/start.S */
1106+#define X86_MBR_GPT_MAGIC 0xedb88320 /* gpt.S */
1107+
1108+ /* values for bp_flags */
1109+#define X86_BP_FLAGS_RESET_VIDEO 1
1110+#define X86_BP_FLAGS_PASSWORD 2
1111+#define X86_BP_FLAGS_NOMODULES 4
1112+#define X86_BP_FLAGS_NOBOOTCONF 8
1113+#define X86_BP_FLAGS_LBA64VALID 0x10
1114+
1115+ /* values for bp_consdev */
1116+#define X86_BP_CONSDEV_PC 0
1117+#define X86_BP_CONSDEV_COM0 1
1118+#define X86_BP_CONSDEV_COM1 2
1119+#define X86_BP_CONSDEV_COM2 3
1120+#define X86_BP_CONSDEV_COM3 4
1121+#define X86_BP_CONSDEV_COM0KBD 5
1122+#define X86_BP_CONSDEV_COM1KBD 6
1123+#define X86_BP_CONSDEV_COM2KBD 7
1124+#define X86_BP_CONSDEV_COM3KBD 8
1125+
1126+/* ------------------------------------------
1127+ * landisk
1128+ */
1129+
1130+#if !defined(__ASSEMBLER__) /* { */
1131+
1132+/*
1133+ * Parameters for NetBSD /boot written to start of pbr code by installboot
1134+ */
1135+struct landisk_boot_params {
1136+ uint32_t bp_length; /* length of patchable data */
1137+ uint32_t bp_flags;
1138+ uint32_t bp_timeout; /* boot timeout in seconds */
1139+ uint32_t bp_consdev;
1140+ uint32_t bp_conspeed;
1141+};
1142+
1143+#endif /* !defined(__ASSEMBLER__) */ /* } */
1144+
1145+#define LANDISK_BOOT_MAGIC_1 0x20031125
1146+#define LANDISK_BOOT_MAGIC_2 0x20041110
1147+
1148+#if !defined(__ASSEMBLER__) /* { */
1149+
1150+/* ------------------------------------------
1151+ * macppc
1152+ */
1153+
1154+#define MACPPC_BOOT_BLOCK_OFFSET 2048
1155+#define MACPPC_BOOT_BLOCK_BLOCKSIZE 512
1156+#define MACPPC_BOOT_BLOCK_MAX_SIZE 2048 /* XXX: could be up to 6144 */
1157+ /* Magic string -- 32 bytes long (including the NUL) */
1158+#define MACPPC_BBINFO_MAGIC "NetBSD/macppc bootxx 20020515"
1159+
1160+/* ------------------------------------------
1161+ * news68k, newsmips
1162+ */
1163+
1164+#define NEWS_BOOT_BLOCK_LABELOFFSET 64 /* XXX from <machine/disklabel.h> */
1165+#define NEWS_BOOT_BLOCK_OFFSET 0
1166+#define NEWS_BOOT_BLOCK_BLOCKSIZE 512
1167+#define NEWS_BOOT_BLOCK_MAX_SIZE (512 * 16)
1168+
1169+ /* Magic string -- 32 bytes long (including the NUL) */
1170+#define NEWS68K_BBINFO_MAGIC "NetBSD/news68k bootxx 20020518"
1171+#define NEWSMIPS_BBINFO_MAGIC "NetBSD/newsmips bootxx 20020518"
1172+
1173+/* ------------------------------------------
1174+ * next68k
1175+ */
1176+
1177+#define NEXT68K_LABEL_MAXPARTITIONS 8 /* number of partitions in next68k_disklabel */
1178+#define NEXT68K_LABEL_CPULBLLEN 24
1179+#define NEXT68K_LABEL_MAXDNMLEN 24
1180+#define NEXT68K_LABEL_MAXTYPLEN 24
1181+#define NEXT68K_LABEL_MAXBFLEN 24
1182+#define NEXT68K_LABEL_MAXHNLEN 32
1183+#define NEXT68K_LABEL_MAXMPTLEN 16
1184+#define NEXT68K_LABEL_MAXFSTLEN 8
1185+#define NEXT68K_LABEL_NBAD 1670 /* sized to make label ~= 8KB */
1186+
1187+struct next68k_partition {
1188+ int32_t cp_offset; /* starting sector */
1189+ int32_t cp_size; /* number of sectors in partition */
1190+ int16_t cp_bsize; /* block size in bytes */
1191+ int16_t cp_fsize; /* filesystem basic fragment size */
1192+ char cp_opt; /* optimization type: 's'pace/'t'ime */
1193+ char cp_pad1;
1194+ int16_t cp_cpg; /* filesystem cylinders per group */
1195+ int16_t cp_density; /* bytes per inode density */
1196+ int8_t cp_minfree; /* minfree (%) */
1197+ int8_t cp_newfs; /* run newfs during init */
1198+ char cp_mountpt[NEXT68K_LABEL_MAXMPTLEN];
1199+ /* default/standard mount point */
1200+ int8_t cp_automnt; /* auto-mount when inserted */
1201+ char cp_type[NEXT68K_LABEL_MAXFSTLEN]; /* file system type name */
1202+ char cp_pad2;
1203+} __packed;
1204+
1205+/* The disklabel the way it is on the disk */
1206+struct next68k_disklabel {
1207+ int32_t cd_version; /* label version */
1208+ int32_t cd_label_blkno; /* block # of this label */
1209+ int32_t cd_size; /* size of media area (sectors) */
1210+ char cd_label[NEXT68K_LABEL_CPULBLLEN]; /* disk name (label) */
1211+ uint32_t cd_flags; /* flags */
1212+ uint32_t cd_tag; /* volume tag */
1213+ char cd_name[NEXT68K_LABEL_MAXDNMLEN]; /* drive (hardware) name */
1214+ char cd_type[NEXT68K_LABEL_MAXTYPLEN]; /* drive type */
1215+ int32_t cd_secsize; /* # of bytes per sector */
1216+ int32_t cd_ntracks; /* # of tracks per cylinder */
1217+ int32_t cd_nsectors; /* # of data sectors per track */
1218+ int32_t cd_ncylinders; /* # of data cylinders per unit */
1219+ int32_t cd_rpm; /* rotational speed */
1220+ int16_t cd_front; /* # of sectors in "front porch" */
1221+ int16_t cd_back; /* # of sectors in "back porch" */
1222+ int16_t cd_ngroups; /* # of alt groups */
1223+ int16_t cd_ag_size; /* alt group size (sectors) */
1224+ int16_t cd_ag_alts; /* alternate sectors / alt group */
1225+ int16_t cd_ag_off; /* sector offset to first alternate */
1226+ int32_t cd_boot_blkno[2]; /* boot program locations */
1227+ char cd_kernel[NEXT68K_LABEL_MAXBFLEN]; /* default kernel name */
1228+ char cd_hostname[NEXT68K_LABEL_MAXHNLEN];
1229+ /* host name (usu. where disk was labeled) */
1230+ char cd_rootpartition; /* root partition letter e.g. 'a' */
1231+ char cd_rwpartition; /* r/w partition letter e.g. 'b' */
1232+ struct next68k_partition cd_partitions[NEXT68K_LABEL_MAXPARTITIONS];
1233+
1234+ union {
1235+ uint16_t CD_v3_checksum; /* label version 3 checksum */
1236+ int32_t CD_bad[NEXT68K_LABEL_NBAD];
1237+ /* block number that is bad */
1238+ } cd_un;
1239+ uint16_t cd_checksum; /* label version 1 or 2 checksum */
1240+} __packed;
1241+
1242+#define NEXT68K_LABEL_cd_checksum cd_checksum
1243+#define NEXT68K_LABEL_cd_v3_checksum cd_un.CD_v3_checksum
1244+#define NEXT68K_LABEL_cd_bad cd_un.CD_bad
1245+
1246+#define NEXT68K_LABEL_SECTOR 0 /* sector containing label */
1247+#define NEXT68K_LABEL_OFFSET 0 /* offset of label in sector */
1248+#define NEXT68K_LABEL_SIZE 8192 /* size of label */
1249+#define NEXT68K_LABEL_CD_V1 0x4e655854 /* version #1: "NeXT" */
1250+#define NEXT68K_LABEL_CD_V2 0x646c5632 /* version #2: "dlV2" */
1251+#define NEXT68K_LABEL_CD_V3 0x646c5633 /* version #3: "dlV3" */
1252+#define NEXT68K_LABEL_DEFAULTFRONTPORCH (160 * 2)
1253+#define NEXT68K_LABEL_DEFAULTBOOT0_1 (32 * 2)
1254+#define NEXT68K_LABEL_DEFAULTBOOT0_2 (96 * 2)
1255+
1256+/* ------------------------------------------
1257+ * pmax --
1258+ * PMAX (DECstation / MIPS) boot block information
1259+ */
1260+
1261+/*
1262+ * If mode is 0, there is just one sequence of blocks and one Dec_BootMap
1263+ * is used. If mode is 1, there are multiple sequences of blocks
1264+ * and multiple Dec_BootMaps are used, the last with numBlocks = 0.
1265+ */
1266+struct pmax_boot_map {
1267+ int32_t num_blocks; /* Number of blocks to read. */
1268+ int32_t start_block; /* Starting block on disk. */
1269+};
1270+
1271+/*
1272+ * This is the structure of a disk or tape boot block. The boot_map
1273+ * can either be a single boot count and start block (contiguous mode)
1274+ * or a list of up to 61 (to fill a 512 byte sector) block count and
1275+ * start block pairs. Under NetBSD, contiguous mode is always used.
1276+ */
1277+struct pmax_boot_block {
1278+ uint8_t pad[8];
1279+ int32_t magic; /* PMAX_BOOT_MAGIC */
1280+ int32_t mode; /* Mode for boot info. */
1281+ uint32_t load_addr; /* Address to start loading. */
1282+ uint32_t exec_addr; /* Address to start execing. */
1283+ struct pmax_boot_map map[61]; /* boot program section(s). */
1284+} __packed;
1285+
1286+#define PMAX_BOOT_MAGIC 0x0002757a
1287+#define PMAX_BOOTMODE_CONTIGUOUS 0
1288+#define PMAX_BOOTMODE_SCATTERED 1
1289+
1290+#define PMAX_BOOT_BLOCK_OFFSET 0
1291+#define PMAX_BOOT_BLOCK_BLOCKSIZE 512
1292+
1293+
1294+/* ------------------------------------------
1295+ * sgimips
1296+ */
1297+
1298+/*
1299+ * Some IRIX man pages refer to the size being a multiple of whole cylinders.
1300+ * Later ones only refer to the size being "typically" 2MB. IRIX fx(1)
1301+ * uses a default drive geometry if one can't be determined, suggesting
1302+ * that "whole cylinder" multiples are not required.
1303+ */
1304+
1305+#define SGI_BOOT_BLOCK_SIZE_VOLHDR 3135
1306+#define SGI_BOOT_BLOCK_MAGIC 0xbe5a941
1307+#define SGI_BOOT_BLOCK_MAXPARTITIONS 16
1308+#define SGI_BOOT_BLOCK_MAXVOLDIRS 15
1309+#define SGI_BOOT_BLOCK_BLOCKSIZE 512
1310+
1311+/*
1312+ * SGI partition conventions:
1313+ *
1314+ * Partition 0 - root
1315+ * Partition 1 - swap
1316+ * Partition 6 - usr
1317+ * Partition 7 - volume body
1318+ * Partition 8 - volume header
1319+ * Partition 10 - whole disk
1320+ */
1321+
1322+struct sgi_boot_devparms {
1323+ uint8_t dp_skew;
1324+ uint8_t dp_gap1;
1325+ uint8_t dp_gap2;
1326+ uint8_t dp_spares_cyl;
1327+ uint16_t dp_cyls;
1328+ uint16_t dp_shd0;
1329+ uint16_t dp_trks0;
1330+ uint8_t dp_ctq_depth;
1331+ uint8_t dp_cylshi;
1332+ uint16_t dp_unused;
1333+ uint16_t dp_secs;
1334+ uint16_t dp_secbytes;
1335+ uint16_t dp_interleave;
1336+ uint32_t dp_flags;
1337+ uint32_t dp_datarate;
1338+ uint32_t dp_nretries;
1339+ uint32_t dp_mspw;
1340+ uint16_t dp_xgap1;
1341+ uint16_t dp_xsync;
1342+ uint16_t dp_xrdly;
1343+ uint16_t dp_xgap2;
1344+ uint16_t dp_xrgate;
1345+ uint16_t dp_xwcont;
1346+} __packed;
1347+
1348+struct sgi_boot_block {
1349+ uint32_t magic;
1350+ int16_t root;
1351+ int16_t swap;
1352+ char bootfile[16];
1353+ struct sgi_boot_devparms dp;
1354+ struct {
1355+ char name[8];
1356+ int32_t block;
1357+ int32_t bytes;
1358+ } voldir[SGI_BOOT_BLOCK_MAXVOLDIRS];
1359+ struct {
1360+ int32_t blocks;
1361+ int32_t first;
1362+ int32_t type;
1363+ } partitions[SGI_BOOT_BLOCK_MAXPARTITIONS];
1364+ int32_t checksum;
1365+ int32_t _pad;
1366+} __packed;
1367+
1368+#define SGI_PTYPE_VOLHDR 0
1369+#define SGI_PTYPE_TRKREPL 1
1370+#define SGI_PTYPE_SECREPL 2
1371+#define SGI_PTYPE_RAW 3
1372+#define SGI_PTYPE_BSD 4
1373+#define SGI_PTYPE_SYSV 5
1374+#define SGI_PTYPE_VOLUME 6
1375+#define SGI_PTYPE_EFS 7
1376+#define SGI_PTYPE_LVOL 8
1377+#define SGI_PTYPE_RLVOL 9
1378+#define SGI_PTYPE_XFS 10
1379+#define SGI_PTYPE_XFSLOG 11
1380+#define SGI_PTYPE_XLV 12
1381+#define SGI_PTYPE_XVM 13
1382+
1383+/* ------------------------------------------
1384+ * sparc
1385+ */
1386+
1387+#define SPARC_BOOT_BLOCK_OFFSET 512
1388+#define SPARC_BOOT_BLOCK_BLOCKSIZE 512
1389+#define SPARC_BOOT_BLOCK_MAX_SIZE (512 * 15)
1390+ /* Magic string -- 32 bytes long (including the NUL) */
1391+#define SPARC_BBINFO_MAGIC "NetBSD/sparc bootxx 20020515"
1392+
1393+
1394+/* ------------------------------------------
1395+ * sparc64
1396+ */
1397+
1398+#define SPARC64_BOOT_BLOCK_OFFSET 512
1399+#define SPARC64_BOOT_BLOCK_BLOCKSIZE 512
1400+#define SPARC64_BOOT_BLOCK_MAX_SIZE (512 * 15)
1401+
1402+
1403+/* ------------------------------------------
1404+ * sun68k (sun2, sun3)
1405+ */
1406+
1407+#define SUN68K_BOOT_BLOCK_OFFSET 512
1408+#define SUN68K_BOOT_BLOCK_BLOCKSIZE 512
1409+#define SUN68K_BOOT_BLOCK_MAX_SIZE (512 * 15)
1410+ /* Magic string -- 32 bytes long (including the NUL) */
1411+#define SUN68K_BBINFO_MAGIC "NetBSD/sun68k bootxx 20020515"
1412+
1413+
1414+/* ------------------------------------------
1415+ * vax --
1416+ * VAX boot block information
1417+ */
1418+
1419+struct vax_boot_block {
1420+/* Note that these don't overlap any of the pmax boot block */
1421+ uint8_t pad0[2];
1422+ uint8_t bb_id_offset; /* offset in words to id (magic1)*/
1423+ uint8_t bb_mbone; /* must be one */
1424+ uint16_t bb_lbn_hi; /* lbn (hi word) of bootstrap */
1425+ uint16_t bb_lbn_low; /* lbn (low word) of bootstrap */
1426+ uint8_t pad1[406];
1427+ /* disklabel offset is 64 from base, or 56 from start of pad1 */
1428+
1429+ /* The rest of these fields are identification area and describe
1430+ * the secondary block for uVAX VMB.
1431+ */
1432+ uint8_t bb_magic1; /* magic number */
1433+ uint8_t bb_mbz1; /* must be zero */
1434+ uint8_t bb_pad1; /* any value */
1435+ uint8_t bb_sum1; /* ~(magic1 + mbz1 + pad1) */
1436+
1437+ uint8_t bb_mbz2; /* must be zero */
1438+ uint8_t bb_volinfo; /* volinfo */
1439+ uint8_t bb_pad2a; /* any value */
1440+ uint8_t bb_pad2b; /* any value */
1441+
1442+ uint32_t bb_size; /* size in blocks of bootstrap */
1443+ uint32_t bb_load; /* load offset to bootstrap */
1444+ uint32_t bb_entry; /* byte offset in bootstrap */
1445+ uint32_t bb_sum3; /* sum of previous 3 fields */
1446+
1447+ /* The rest is unused.
1448+ */
1449+ uint8_t pad2[74];
1450+} __packed;
1451+
1452+#define VAX_BOOT_MAGIC1 0x18 /* size of BB info? */
1453+#define VAX_BOOT_VOLINFO_NONE 0x00 /* no special info */
1454+#define VAX_BOOT_VOLINFO_SS 0x01 /* single sided */
1455+#define VAX_BOOT_VOLINFO_DS 0x81 /* double sided */
1456+
1457+#define VAX_BOOT_SIZE 15 /* 15 blocks */
1458+#define VAX_BOOT_LOAD 0 /* no load offset */
1459+#define VAX_BOOT_ENTRY 0x200 /* one block in */
1460+
1461+#define VAX_BOOT_BLOCK_OFFSET 0
1462+#define VAX_BOOT_BLOCK_BLOCKSIZE 512
1463+
1464+
1465+/* ------------------------------------------
1466+ * x68k
1467+ */
1468+
1469+#define X68K_BOOT_BLOCK_OFFSET 0
1470+#define X68K_BOOT_BLOCK_BLOCKSIZE 512
1471+#define X68K_BOOT_BLOCK_MAX_SIZE (512 * 16)
1472+ /* Magic string -- 32 bytes long (including the NUL) */
1473+#define X68K_BBINFO_MAGIC "NetBSD/x68k bootxx 20020601"
1474+
1475+#endif /* !defined(__ASSEMBLER__) */ /* } */
1476+
1477+#endif /* !_SYS_BOOTBLOCK_H */
+826,
-0
1@@ -0,0 +1,826 @@
2+/* $NetBSD: walk.c,v 1.43 2025/05/01 14:14:36 andvar Exp $ */
3+
4+/*
5+ * Copyright (c) 2001 Wasabi Systems, Inc.
6+ * All rights reserved.
7+ *
8+ * Written by Luke Mewburn for Wasabi Systems, Inc.
9+ *
10+ * Redistribution and use in source and binary forms, with or without
11+ * modification, are permitted provided that the following conditions
12+ * are met:
13+ * 1. Redistributions of source code must retain the above copyright
14+ * notice, this list of conditions and the following disclaimer.
15+ * 2. Redistributions in binary form must reproduce the above copyright
16+ * notice, this list of conditions and the following disclaimer in the
17+ * documentation and/or other materials provided with the distribution.
18+ * 3. All advertising materials mentioning features or use of this software
19+ * must display the following acknowledgement:
20+ * This product includes software developed for the NetBSD Project by
21+ * Wasabi Systems, Inc.
22+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23+ * or promote products derived from this software without specific prior
24+ * written permission.
25+ *
26+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36+ * POSSIBILITY OF SUCH DAMAGE.
37+ */
38+
39+#if HAVE_NBTOOL_CONFIG_H
40+#include "nbtool_config.h"
41+#endif
42+
43+#include <sys/cdefs.h>
44+#if defined(__RCSID) && !defined(__lint)
45+__RCSID("$NetBSD: walk.c,v 1.43 2025/05/01 14:14:36 andvar Exp $");
46+#endif /* !__lint */
47+
48+#include <sys/param.h>
49+#include <sys/stat.h>
50+
51+#include <assert.h>
52+#include <errno.h>
53+#include <fcntl.h>
54+#include <stdio.h>
55+#include <dirent.h>
56+#include <stdlib.h>
57+#include <string.h>
58+#include <unistd.h>
59+#include <util.h>
60+
61+#include "makefs.h"
62+#include "mtree.h"
63+
64+static void apply_specdir(const char *, NODE *, fsnode *, int);
65+static void apply_specentry(const char *, NODE *, fsnode *);
66+static fsnode *create_fsnode(const char *, const char *, const char *,
67+ struct stat *);
68+static fsinode *link_check(fsinode *);
69+static size_t missing = 0;
70+
71+/*
72+ * fsnode_cmp --
73+ * This function is used by `qsort` so sort one directory's
74+ * entries. `.` is always first, followed by anything else
75+ * as compared by `strcmp()`.
76+ */
77+static int
78+fsnode_cmp(const void *vleft, const void *vright)
79+{
80+ const fsnode * const *left = vleft;
81+ const fsnode * const *right = vright;
82+ const char *lname = (*left)->name, *rname = (*right)->name;
83+
84+ if (strcmp(lname, ".") == 0)
85+ return -1;
86+ if (strcmp(rname, ".") == 0)
87+ return 1;
88+ return strcmp(lname, rname);
89+}
90+
91+static fsnode *
92+fsnode_sort(fsnode *first, const char *root, const char *dir)
93+{
94+ fsnode **list, **listptr;
95+ size_t num = 0;
96+
97+ for (fsnode *tmp = first; tmp; tmp = tmp->next, num++) {
98+ if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
99+ printf("%s: pre sort: %s %s %s\n",
100+ __func__, root, dir, tmp->name);
101+ }
102+
103+ list = listptr = ecalloc(num, sizeof(*list));
104+ for (fsnode *tmp = first; tmp; tmp = tmp->next)
105+ *listptr++ = tmp;
106+
107+ qsort(list, num, sizeof(*list), fsnode_cmp);
108+
109+ for (size_t i = 0; i < num - 1; ++i)
110+ list[i]->next = list[i + 1];
111+ list[num - 1]->next = NULL;
112+ first = list[0];
113+ assert(strcmp(first->name, ".") == 0);
114+ free(list);
115+ if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
116+ for (fsnode *tmp = first; tmp; tmp = tmp->next)
117+ printf("%s: post sort: %s %s %s\n",
118+ __func__, root, dir, tmp->name);
119+
120+ return first;
121+}
122+
123+/*
124+ * join current entry with the list. Return the current entry to replace
125+ * in cur, and 1 if it is a directory and we need to add or 0 if we need
126+ * to replace it.
127+ */
128+static int
129+fsnode_join(fsnode **curp, fsnode *join, fsnode *last, const char *path,
130+ const char *name, const struct stat *st, int replace)
131+{
132+ fsnode *cur;
133+
134+ /* Look for the entry to replace by name */
135+ cur = join->next;
136+ for (;;) {
137+ if (cur == NULL || strcmp(cur->name, name) == 0)
138+ break;
139+ if (cur == last) {
140+ cur = NULL;
141+ break;
142+ }
143+ cur = cur->next;
144+ }
145+ if (cur == NULL) {
146+ /* Not found */
147+ *curp = NULL;
148+ return 0;
149+ }
150+ if (S_ISDIR(cur->type) && S_ISDIR(st->st_mode)) {
151+ /*
152+ * both the entry to join and this entry are directories
153+ * need to merge the two directories
154+ */
155+ if (debug & DEBUG_WALK_DIR_NODE)
156+ printf("%s: merging %s with %p\n",
157+ __func__, path, cur->child);
158+ *curp = cur;
159+ return 1;
160+ }
161+ if (!replace) {
162+ /*
163+ * if they are not both directories and replace is not
164+ * specified, bail out
165+ */
166+ errx(EXIT_FAILURE, "Can't merge %s `%s' with existing %s",
167+ inode_type(st->st_mode), path, inode_type(cur->type));
168+ }
169+
170+ if (debug & DEBUG_WALK_DIR_NODE)
171+ printf("%s: replacing %s %s\n",
172+ __func__, inode_type(st->st_mode), path);
173+
174+ /* merge the join list */
175+ if (cur == join->next)
176+ join->next = cur->next;
177+ else {
178+ fsnode *p;
179+ for (p = join->next;
180+ p->next != cur; p = p->next)
181+ continue;
182+ p->next = cur->next;
183+ }
184+ /* return the entry to be replaced */
185+ *curp = cur;
186+ return 0;
187+}
188+
189+/*
190+ * walk_dir --
191+ * build a tree of fsnodes from `root' and `dir', with a parent
192+ * fsnode of `parent' (which may be NULL for the root of the tree).
193+ * append the tree to a fsnode of `join' if it is not NULL.
194+ * each "level" is a directory, with the "." entry guaranteed to be
195+ * at the start of the list, and without ".." entries.
196+ */
197+fsnode *
198+walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join,
199+ int replace, int follow)
200+{
201+ fsnode *first, *cur, *prev, *last;
202+ DIR *dirp;
203+ struct dirent *dent;
204+ char path[MAXPATHLEN + 1];
205+ struct stat stbuf;
206+ char *name, *rp;
207+ int dot, len;
208+
209+ assert(root != NULL);
210+ assert(dir != NULL);
211+
212+ len = snprintf(path, sizeof(path), "%s/%s", root, dir);
213+ if ((size_t)len >= sizeof(path))
214+ errx(EXIT_FAILURE, "Pathname too long.");
215+ if (debug & DEBUG_WALK_DIR)
216+ printf("%s: %s %p\n", __func__, path, parent);
217+ if ((dirp = opendir(path)) == NULL)
218+ err(EXIT_FAILURE, "Can't opendir `%s'", path);
219+ rp = path + strlen(root) + 1;
220+ if (join != NULL) {
221+ first = cur = join;
222+ while (cur->next != NULL)
223+ cur = cur->next;
224+ prev = last = cur;
225+ } else
226+ last = first = prev = NULL;
227+ while ((dent = readdir(dirp)) != NULL) {
228+ name = dent->d_name;
229+ dot = 0;
230+ if (name[0] == '.')
231+ switch (name[1]) {
232+ case '\0': /* "." */
233+ if (join != NULL)
234+ continue;
235+ dot = 1;
236+ break;
237+ case '.': /* ".." */
238+ if (name[2] == '\0')
239+ continue;
240+ /* FALLTHROUGH */
241+ default:
242+ dot = 0;
243+ }
244+ if (debug & DEBUG_WALK_DIR_NODE)
245+ printf("%s: scanning %s/%s/%s\n",
246+ __func__, root, dir, name);
247+ if (snprintf(path + len, sizeof(path) - len, "/%s", name) >=
248+ (int)sizeof(path) - len)
249+ errx(EXIT_FAILURE, "Pathname too long.");
250+ if (follow) {
251+ if (stat(path, &stbuf) == -1)
252+ err(EXIT_FAILURE, "Can't stat `%s'", path);
253+ } else {
254+ if (lstat(path, &stbuf) == -1)
255+ err(EXIT_FAILURE, "Can't lstat `%s'", path);
256+ /*
257+ * Symlink permission bits vary between filesystems/OSs
258+ * (ie. 0755 on FFS/NetBSD, 0777 for ext[234]/Linux),
259+ * force them to 0755.
260+ */
261+ if (S_ISLNK(stbuf.st_mode)) {
262+ stbuf.st_mode &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
263+ stbuf.st_mode |= S_IRWXU
264+ | S_IRGRP | S_IXGRP
265+ | S_IROTH | S_IXOTH;
266+ }
267+ }
268+#ifdef S_ISSOCK
269+ if (S_ISSOCK(stbuf.st_mode & S_IFMT)) {
270+ if (debug & DEBUG_WALK_DIR_NODE)
271+ printf("%s: skipping socket %s\n", __func__,
272+ path);
273+ continue;
274+ }
275+#endif
276+
277+ if (join != NULL) {
278+ if (fsnode_join(&cur, join, last, path, name, &stbuf,
279+ replace)) {
280+ cur->child = walk_dir(root, rp, cur,
281+ cur->child, replace, follow);
282+ continue;
283+ } else if (cur) {
284+ if (prev == cur) {
285+ fsnode *p = join;
286+ while (p->next != NULL)
287+ p = p->next;
288+ prev = p;
289+ }
290+ free(cur->name);
291+ free(cur->path);
292+ free(cur);
293+ }
294+ }
295+
296+ cur = create_fsnode(root, dir, name, &stbuf);
297+ cur->parent = parent;
298+ if (dot) {
299+ /* ensure "." is at the start of the list */
300+ cur->next = first;
301+ first = cur;
302+ if (! prev)
303+ prev = cur;
304+ cur->first = first;
305+ } else { /* not "." */
306+ if (prev)
307+ prev->next = cur;
308+ prev = cur;
309+ if (!first)
310+ first = cur;
311+ cur->first = first;
312+ if (S_ISDIR(cur->type)) {
313+ cur->child = walk_dir(root, rp, cur, NULL,
314+ replace, follow);
315+ continue;
316+ }
317+ }
318+ if (stbuf.st_nlink > 1) {
319+ fsinode *curino;
320+
321+ curino = link_check(cur->inode);
322+ if (curino != NULL) {
323+ free(cur->inode);
324+ cur->inode = curino;
325+ cur->inode->nlink++;
326+ if (debug & DEBUG_WALK_DIR_LINKCHECK)
327+ printf("%s: link check found [%ju, %ju]\n",
328+ __func__,
329+ (uintmax_t)curino->st.st_dev,
330+ (uintmax_t)curino->st.st_ino);
331+ }
332+ }
333+ if (S_ISLNK(cur->type)) {
334+ char slink[PATH_MAX+1];
335+ ssize_t llen;
336+
337+ llen = readlink(path, slink, sizeof(slink) - 1);
338+ if (llen == -1)
339+ err(EXIT_FAILURE, "Readlink `%s'", path);
340+ slink[llen] = '\0';
341+ cur->symlink = estrdup(slink);
342+ }
343+ }
344+ assert(first != NULL);
345+ if (join == NULL)
346+ for (cur = first->next; cur != NULL; cur = cur->next)
347+ cur->first = first;
348+ if (closedir(dirp) == -1)
349+ err(EXIT_FAILURE, "Can't closedir `%s/%s'", root, dir);
350+
351+ return fsnode_sort(first, root, dir);
352+}
353+
354+static fsnode *
355+create_fsnode(const char *root, const char *path, const char *name,
356+ struct stat *stbuf)
357+{
358+ fsnode *cur;
359+
360+ cur = ecalloc(1, sizeof(*cur));
361+ cur->path = estrdup(path);
362+ cur->name = estrdup(name);
363+ cur->inode = ecalloc(1, sizeof(*cur->inode));
364+ cur->root = root;
365+ cur->type = stbuf->st_mode & S_IFMT;
366+ cur->inode->nlink = 1;
367+ cur->inode->st = *stbuf;
368+ if (stampst.st_ino) {
369+ cur->inode->st.st_atime = stampst.st_atime;
370+ cur->inode->st.st_mtime = stampst.st_mtime;
371+ cur->inode->st.st_ctime = stampst.st_ctime;
372+#if HAVE_STRUCT_STAT_ST_MTIMENSEC
373+ cur->inode->st.st_atimensec = stampst.st_atimensec;
374+ cur->inode->st.st_mtimensec = stampst.st_mtimensec;
375+ cur->inode->st.st_ctimensec = stampst.st_ctimensec;
376+#endif
377+#if HAVE_STRUCT_STAT_BIRTHTIME
378+ cur->inode->st.st_birthtime = stampst.st_birthtime;
379+ cur->inode->st.st_birthtimensec = stampst.st_birthtimensec;
380+#endif
381+ }
382+ return (cur);
383+}
384+
385+/*
386+ * free_fsnodes --
387+ * Removes node from tree and frees it and all of
388+ * its descendents.
389+ */
390+void
391+free_fsnodes(fsnode *node)
392+{
393+ fsnode *cur, *next;
394+
395+ assert(node != NULL);
396+
397+ /* for ".", start with actual parent node */
398+ if (node->first == node) {
399+ assert(node->name[0] == '.' && node->name[1] == '\0');
400+ if (node->parent) {
401+ assert(node->parent->child == node);
402+ node = node->parent;
403+ }
404+ }
405+
406+ /* Find ourselves in our sibling list and unlink */
407+ if (node->first != node) {
408+ for (cur = node->first; cur->next; cur = cur->next) {
409+ if (cur->next == node) {
410+ cur->next = node->next;
411+ node->next = NULL;
412+ break;
413+ }
414+ }
415+ }
416+
417+ for (cur = node; cur != NULL; cur = next) {
418+ next = cur->next;
419+ if (cur->child) {
420+ cur->child->parent = NULL;
421+ free_fsnodes(cur->child);
422+ }
423+ if (cur->inode->nlink-- == 1)
424+ free(cur->inode);
425+ if (cur->symlink)
426+ free(cur->symlink);
427+ free(cur->path);
428+ free(cur->name);
429+ free(cur);
430+ }
431+}
432+
433+/*
434+ * apply_specfile --
435+ * read in the mtree(8) specfile, and apply it to the tree
436+ * at dir,parent. parameters in parent on equivalent types
437+ * will be changed to those found in specfile, and missing
438+ * entries will be added.
439+ */
440+void
441+apply_specfile(const char *specfile, const char *dir, fsnode *parent, int speconly)
442+{
443+ struct timeval start;
444+ FILE *fp;
445+ NODE *root;
446+
447+ assert(specfile != NULL);
448+ assert(parent != NULL);
449+
450+ if (debug & DEBUG_APPLY_SPECFILE)
451+ printf("%s: %s, %s %p\n", __func__, specfile, dir, parent);
452+
453+ /* read in the specfile */
454+ if ((fp = fopen(specfile, "r")) == NULL)
455+ err(EXIT_FAILURE, "Can't open `%s'", specfile);
456+ TIMER_START(start);
457+ root = spec(fp);
458+ TIMER_RESULTS(start, "spec");
459+ if (fclose(fp) == EOF)
460+ err(EXIT_FAILURE, "Can't close `%s'", specfile);
461+
462+ /* perform some sanity checks */
463+ if (root == NULL)
464+ errx(EXIT_FAILURE,
465+ "Specfile `%s' did not contain a tree", specfile);
466+ assert(strcmp(root->name, ".") == 0);
467+ assert(root->type == F_DIR);
468+
469+ /* merge in the changes */
470+ apply_specdir(dir, root, parent, speconly);
471+
472+ free_nodes(root);
473+ if (missing)
474+ errx(EXIT_FAILURE, "Add %zu missing entries in `%s'",
475+ missing, specfile);
476+}
477+
478+static void
479+apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly)
480+{
481+ char path[MAXPATHLEN + 1];
482+ NODE *curnode;
483+ fsnode *curfsnode;
484+
485+ assert(specnode != NULL);
486+ assert(dirnode != NULL);
487+
488+ if (debug & DEBUG_APPLY_SPECFILE)
489+ printf("%s: %s %p %p\n", __func__, dir, specnode, dirnode);
490+
491+ if (specnode->type != F_DIR)
492+ errx(EXIT_FAILURE, "Specfile node `%s/%s' is not a directory",
493+ dir, specnode->name);
494+ if (dirnode->type != S_IFDIR)
495+ errx(EXIT_FAILURE, "Directory node `%s/%s' is not a directory",
496+ dir, dirnode->name);
497+
498+ apply_specentry(dir, specnode, dirnode);
499+
500+ /* Remove any filesystem nodes not found in specfile */
501+ /* XXX inefficient. This is O^2 in each dir and it would
502+ * have been better never to have walked this part of the tree
503+ * to begin with
504+ */
505+ if (speconly) {
506+ fsnode *next;
507+ assert(dirnode->name[0] == '.' && dirnode->name[1] == '\0');
508+ for (curfsnode = dirnode->next; curfsnode != NULL; curfsnode = next) {
509+ next = curfsnode->next;
510+ for (curnode = specnode->child; curnode != NULL;
511+ curnode = curnode->next) {
512+ if (strcmp(curnode->name, curfsnode->name) == 0)
513+ break;
514+ }
515+ if (curnode == NULL) {
516+ if (speconly > 1) {
517+ warnx("missing specfile entry for %s/%s",
518+ dir, curfsnode->name);
519+ missing++;
520+ }
521+ if (debug & DEBUG_APPLY_SPECONLY) {
522+ printf("%s: trimming %s/%s %p\n",
523+ __func__, dir, curfsnode->name,
524+ curfsnode);
525+ }
526+ free_fsnodes(curfsnode);
527+ }
528+ }
529+ }
530+
531+ /* now walk specnode->child matching up with dirnode */
532+ for (curnode = specnode->child; curnode != NULL;
533+ curnode = curnode->next) {
534+ if (debug & DEBUG_APPLY_SPECENTRY)
535+ printf("%s: spec %s\n", __func__, curnode->name);
536+ for (curfsnode = dirnode->next; curfsnode != NULL;
537+ curfsnode = curfsnode->next) {
538+#if 0 /* too verbose for now */
539+ if (debug & DEBUG_APPLY_SPECENTRY)
540+ printf("%s: dirent %s\n", __func__,
541+ curfsnode->name);
542+#endif
543+ if (strcmp(curnode->name, curfsnode->name) == 0)
544+ break;
545+ }
546+ if ((size_t)snprintf(path, sizeof(path), "%s/%s",
547+ dir, curnode->name) >= sizeof(path))
548+ errx(EXIT_FAILURE, "Pathname too long.");
549+ if (curfsnode == NULL) { /* need new entry */
550+ struct stat stbuf;
551+
552+ /*
553+ * don't add optional spec entries
554+ * that lack an existing fs entry
555+ */
556+ if ((curnode->flags & F_OPT) &&
557+ lstat(path, &stbuf) == -1)
558+ continue;
559+
560+ /* check that enough info is provided */
561+#define NODETEST(t, m) \
562+ if (!(t)) \
563+ errx(EXIT_FAILURE, \
564+ "`%s': %s not provided", path, m)
565+ NODETEST(curnode->flags & F_TYPE, "type");
566+ NODETEST(curnode->flags & F_MODE, "mode");
567+ /* XXX: require F_TIME ? */
568+ NODETEST(curnode->flags & F_GID ||
569+ curnode->flags & F_GNAME, "group");
570+ NODETEST(curnode->flags & F_UID ||
571+ curnode->flags & F_UNAME, "user");
572+ if (curnode->type == F_BLOCK || curnode->type == F_CHAR)
573+ NODETEST(curnode->flags & F_DEV,
574+ "device number");
575+#undef NODETEST
576+
577+ if (debug & DEBUG_APPLY_SPECFILE)
578+ printf("%s: adding %s\n", __func__, curnode->name);
579+ /* build minimal fsnode */
580+ memset(&stbuf, 0, sizeof(stbuf));
581+ stbuf.st_mode = nodetoino(curnode->type);
582+ stbuf.st_nlink = 1;
583+ stbuf.st_mtime = stbuf.st_atime =
584+ stbuf.st_ctime = start_time.tv_sec;
585+#if HAVE_STRUCT_STAT_ST_MTIMENSEC
586+ stbuf.st_mtimensec = stbuf.st_atimensec =
587+ stbuf.st_ctimensec = start_time.tv_nsec;
588+#endif
589+ curfsnode = create_fsnode(".", ".", curnode->name,
590+ &stbuf);
591+ curfsnode->parent = dirnode->parent;
592+ curfsnode->first = dirnode;
593+ curfsnode->next = dirnode->next;
594+ dirnode->next = curfsnode;
595+ if (curfsnode->type == S_IFDIR) {
596+ /* for dirs, make "." entry as well */
597+ curfsnode->child = create_fsnode(".", ".", ".",
598+ &stbuf);
599+ curfsnode->child->parent = curfsnode;
600+ curfsnode->child->first = curfsnode->child;
601+ }
602+ if (curfsnode->type == S_IFLNK) {
603+ assert(curnode->slink != NULL);
604+ /* for symlinks, copy the target */
605+ curfsnode->symlink = estrdup(curnode->slink);
606+ }
607+ }
608+ apply_specentry(dir, curnode, curfsnode);
609+ if (curnode->type == F_DIR) {
610+ if (curfsnode->type != S_IFDIR)
611+ errx(EXIT_FAILURE,
612+ "`%s' is not a directory", path);
613+ assert(curfsnode->child != NULL);
614+ apply_specdir(path, curnode, curfsnode->child, speconly);
615+ }
616+ }
617+}
618+
619+static void
620+apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
621+{
622+
623+ assert(specnode != NULL);
624+ assert(dirnode != NULL);
625+
626+ if (nodetoino(specnode->type) != dirnode->type)
627+ errx(EXIT_FAILURE,
628+ "`%s/%s' type mismatch: specfile %s, tree %s",
629+ dir, specnode->name, inode_type(nodetoino(specnode->type)),
630+ inode_type(dirnode->type));
631+
632+ if (debug & DEBUG_APPLY_SPECENTRY)
633+ printf("%s: %s/%s\n", dir, __func__, dirnode->name);
634+
635+#define ASEPRINT(t, b, o, n) \
636+ if (debug & DEBUG_APPLY_SPECENTRY) \
637+ printf("\t\t\tchanging %s from " b " to " b "\n", \
638+ t, o, n)
639+
640+ if (specnode->flags & (F_GID | F_GNAME)) {
641+ ASEPRINT("gid", "%d",
642+ dirnode->inode->st.st_gid, specnode->st_gid);
643+ dirnode->inode->st.st_gid = specnode->st_gid;
644+ }
645+ if (specnode->flags & F_MODE) {
646+ ASEPRINT("mode", "%#o",
647+ dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode);
648+ dirnode->inode->st.st_mode &= ~ALLPERMS;
649+ dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS);
650+ }
651+ /* XXX: ignoring F_NLINK for now */
652+ if (specnode->flags & F_SIZE) {
653+ ASEPRINT("size", "%jd",
654+ (intmax_t)dirnode->inode->st.st_size,
655+ (intmax_t)specnode->st_size);
656+ dirnode->inode->st.st_size = specnode->st_size;
657+ }
658+ if (specnode->flags & F_SLINK) {
659+ assert(dirnode->symlink != NULL);
660+ assert(specnode->slink != NULL);
661+ ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink);
662+ free(dirnode->symlink);
663+ dirnode->symlink = estrdup(specnode->slink);
664+ }
665+ if (specnode->flags & F_TIME) {
666+ ASEPRINT("time", "%ld",
667+ (long)dirnode->inode->st.st_mtime,
668+ (long)specnode->st_mtimespec.tv_sec);
669+ dirnode->inode->st.st_mtime = specnode->st_mtimespec.tv_sec;
670+ dirnode->inode->st.st_atime = specnode->st_mtimespec.tv_sec;
671+ dirnode->inode->st.st_ctime = start_time.tv_sec;
672+#if HAVE_STRUCT_STAT_ST_MTIMENSEC
673+ dirnode->inode->st.st_mtimensec = specnode->st_mtimespec.tv_nsec;
674+ dirnode->inode->st.st_atimensec = specnode->st_mtimespec.tv_nsec;
675+ dirnode->inode->st.st_ctimensec = start_time.tv_nsec;
676+#endif
677+ }
678+ if (specnode->flags & (F_UID | F_UNAME)) {
679+ ASEPRINT("uid", "%d",
680+ dirnode->inode->st.st_uid, specnode->st_uid);
681+ dirnode->inode->st.st_uid = specnode->st_uid;
682+ }
683+ if (specnode->flags & F_FLAGS) {
684+ ASEPRINT("flags", "%#lX",
685+ (unsigned long)FSINODE_ST_FLAGS(*dirnode->inode),
686+ (unsigned long)specnode->st_flags);
687+ FSINODE_ST_FLAGS(*dirnode->inode) = specnode->st_flags;
688+ }
689+ if (specnode->flags & F_DEV) {
690+ ASEPRINT("rdev", "%#jx",
691+ (uintmax_t)dirnode->inode->st.st_rdev,
692+ (uintmax_t)specnode->st_rdev);
693+ dirnode->inode->st.st_rdev = specnode->st_rdev;
694+ }
695+#undef ASEPRINT
696+
697+ dirnode->flags |= FSNODE_F_HASSPEC;
698+}
699+
700+
701+/*
702+ * dump_fsnodes --
703+ * dump the fsnodes from `cur'
704+ */
705+void
706+dump_fsnodes(fsnode *root)
707+{
708+ fsnode *cur;
709+ char path[MAXPATHLEN + 1];
710+
711+ printf("%s: %s %p\n", __func__, root->path, root);
712+ for (cur = root; cur != NULL; cur = cur->next) {
713+ if (snprintf(path, sizeof(path), "%s/%s", cur->path,
714+ cur->name) >= (int)sizeof(path))
715+ errx(EXIT_FAILURE, "Pathname too long.");
716+
717+ if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
718+ printf("%s: cur=%8p parent=%8p first=%8p ", __func__,
719+ cur, cur->parent, cur->first);
720+ printf("%7s: %s", inode_type(cur->type), path);
721+ if (S_ISLNK(cur->type)) {
722+ assert(cur->symlink != NULL);
723+ printf(" -> %s", cur->symlink);
724+ } else {
725+ assert(cur->symlink == NULL);
726+ }
727+ if (cur->inode->nlink > 1)
728+ printf(", nlinks=%d", cur->inode->nlink);
729+ putchar('\n');
730+
731+ if (cur->child) {
732+ assert(cur->type == S_IFDIR);
733+ dump_fsnodes(cur->child);
734+ }
735+ }
736+ printf("%s: finished %s/%s\n", __func__, root->path, root->name);
737+}
738+
739+
740+/*
741+ * inode_type --
742+ * for a given inode type `mode', return a descriptive string.
743+ * for most cases, uses inotype() from mtree/misc.c
744+ */
745+const char *
746+inode_type(mode_t mode)
747+{
748+
749+ if (S_ISLNK(mode))
750+ return ("symlink"); /* inotype() returns "link"... */
751+ return (inotype(mode));
752+}
753+
754+
755+/*
756+ * link_check --
757+ * return pointer to fsinode matching `entry's st_ino & st_dev if it exists,
758+ * otherwise add `entry' to table and return NULL
759+ */
760+/* This was borrowed from du.c and tweaked to keep an fsnode
761+ * pointer instead. -- dbj@netbsd.org
762+ */
763+static fsinode *
764+link_check(fsinode *entry)
765+{
766+ static struct entry {
767+ fsinode *data;
768+ } *htable;
769+ static size_t htshift; /* log(allocated size) */
770+ static size_t htmask; /* allocated size - 1 */
771+ static size_t htused; /* 2*number of insertions */
772+ size_t h, h2;
773+ uint64_t tmp;
774+ /* this constant is (1<<64)/((1+sqrt(5))/2)
775+ * aka (word size)/(golden ratio)
776+ */
777+ const uint64_t HTCONST = 11400714819323198485ULL;
778+ const size_t HTBITS = 64;
779+
780+ /* Never store zero in hashtable */
781+ assert(entry);
782+
783+ /* Extend hash table if necessary, keep load under 0.5 */
784+ if (htused<<1 >= htmask) {
785+ struct entry *ohtable;
786+
787+ if (!htable)
788+ htshift = 10; /* starting hashtable size */
789+ else
790+ htshift++; /* exponential hashtable growth */
791+
792+ htmask = (1 << htshift) - 1;
793+ htused = 0;
794+
795+ ohtable = htable;
796+ htable = ecalloc(htmask+1, sizeof(*htable));
797+ /* populate newly allocated hashtable */
798+ if (ohtable) {
799+ for (size_t i = 0; i <= htmask>>1; i++)
800+ if (ohtable[i].data)
801+ link_check(ohtable[i].data);
802+ free(ohtable);
803+ }
804+ }
805+
806+ /* multiplicative hashing */
807+ tmp = entry->st.st_dev;
808+ tmp <<= HTBITS>>1;
809+ tmp |= entry->st.st_ino;
810+ tmp *= HTCONST;
811+ h = tmp >> (HTBITS - htshift);
812+ h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
813+
814+ /* open address hashtable search with double hash probing */
815+ while (htable[h].data) {
816+ if ((htable[h].data->st.st_ino == entry->st.st_ino) &&
817+ (htable[h].data->st.st_dev == entry->st.st_dev)) {
818+ return htable[h].data;
819+ }
820+ h = (h + h2) & htmask;
821+ }
822+
823+ /* Insert the current entry into hashtable */
824+ htable[h].data = entry;
825+ htused++;
826+ return NULL;
827+}
+7,
-3
1@@ -1,7 +1,8 @@
2 .POSIX:
3
4 PROG = pr
5-SRCS = pr.c egetopt.c ../compat/raise_default_signal.c
6+SRCS = pr.c egetopt.c
7+COMPATLIB = ../compat/libnetcompat.a
8 MAN = pr.1
9
10 CC = cc
11@@ -13,8 +14,11 @@ MANDIR = /usr/local/share/man
12
13 all: $(PROG)
14
15-$(PROG): $(SRCS)
16- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
17+$(PROG): $(SRCS) $(COMPATLIB)
18+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
19+
20+$(COMPATLIB):
21+ (cd ../compat && $(MAKE) all)
22
23 install: $(PROG)
24 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+6,
-2
1@@ -2,6 +2,7 @@
2
3 PROG = rs
4 SRCS = rs.c
5+COMPATLIB = ../compat/libnetcompat.a
6 MAN = rs.1
7
8 CC = cc
9@@ -13,8 +14,11 @@ MANDIR = /usr/local/share/man
10
11 all: $(PROG)
12
13-$(PROG): $(SRCS)
14- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
15+$(PROG): $(SRCS) $(COMPATLIB)
16+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
17+
18+$(COMPATLIB):
19+ (cd ../compat && $(MAKE) all)
20
21 install: $(PROG)
22 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+7,
-3
1@@ -1,7 +1,8 @@
2 .POSIX:
3
4 PROG = script
5-SRCS = script.c ../compat/getprogname.c
6+SRCS = script.c
7+COMPATLIB = ../compat/libnetcompat.a
8 MAN = script.1
9
10 CC = cc
11@@ -14,8 +15,11 @@ MANDIR = /usr/local/share/man
12
13 all: $(PROG)
14
15-$(PROG): $(SRCS)
16- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
17+$(PROG): $(SRCS) $(COMPATLIB)
18+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(COMPATLIB) $(LDLIBS)
19+
20+$(COMPATLIB):
21+ (cd ../compat && $(MAKE) all)
22
23 install: $(PROG)
24 mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1