commit 44ae0f1

shrub  ·  2026-05-27 12:37:21 +0000 UTC
parent 30ef0e4
add a simple shar
5 files changed,  +280, -2
+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
6+SUBDIRS = apply col ctags finger jot look pr rs script shar
7 all:
8 	@set -e; \
9 	for dir in $(SUBDIRS); do \
+3, -1
 1@@ -3,6 +3,8 @@ netmisc
 2 
 3 misc programs from netbsd with some compatibilty shim and portability bits.
 4 
 5+the shar implementation is not from netbsd, but a slightly improved version in C by me
 6+
 7 you need cc, make, yacc, etc to build, and a reasonably posix-compliant system. 
 8 
 9-all code under it's original license
10+all netbsd  code under it's original license
+26, -0
 1@@ -0,0 +1,26 @@
 2+.POSIX:
 3+
 4+PROG = shar
 5+SRCS = shar.c
 6+MAN = shar.1
 7+
 8+CC = cc
 9+CFLAGS = -O2
10+DESTDIR =
11+BINDIR = /usr/local/bin
12+MANDIR = /usr/local/share/man
13+
14+all: $(PROG)
15+
16+$(PROG): $(SRCS)
17+	$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LDLIBS)
18+
19+install: $(PROG)
20+	mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
21+	cp $(PROG) $(DESTDIR)$(BINDIR)/$(PROG)
22+	chmod 755 $(DESTDIR)$(BINDIR)/$(PROG)
23+	cp $(MAN) $(DESTDIR)$(MANDIR)/man1/$(MAN)
24+	chmod 644 $(DESTDIR)$(MANDIR)/man1/$(MAN)
25+
26+clean:
27+	rm -f $(PROG) *.o
+93, -0
 1@@ -0,0 +1,93 @@
 2+.\"	$NetBSD: shar.1,v 1.14 2023/01/25 19:52:14 rillig Exp $
 3+.\" [[[[ SLIGHTLY MODIFIED BY SHRUB :) ]]]]
 4+.\" Copyright (c) 1990, 1993
 5+.\"	The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
16+.\"    may be used to endorse or promote products derived from this software
17+.\"    without specific prior written permission.
18+.\"
19+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29+.\" SUCH DAMAGE.
30+.\"
31+.\"     @(#)shar.1	8.1 (Berkeley) 6/6/93
32+.\"
33+.Dd May 27, 2026
34+.Dt SHAR 1
35+.Os
36+.Sh NAME
37+.Nm shar
38+.Nd create a shell archive of files
39+.Sh SYNOPSIS
40+.Nm
41+.Ar
42+.Sh DESCRIPTION
43+.Nm
44+writes an
45+.Xr sh 1
46+shell script to the standard output which will recreate the file
47+hierarchy specified by the command line operands.
48+Parent directories for file operands are created as needed.
49+File and directory permissions are restored.
50+.Pp
51+.Nm
52+is normally used for distributing files by
53+.Xr ftp 1
54+or
55+.Xr mail 1 .
56+.Sh EXAMPLES
57+To create a shell archive of the program
58+.Xr ls 1
59+and mail it to Rick:
60+.Bd -literal -offset indent
61+cd ls
62+shar `find . -print` \&|  mail -s "ls source" rick
63+.Ed
64+.Pp
65+To recreate the program directory:
66+.Bd -literal -offset indent
67+mkdir ls
68+cd ls
69+\&...
70+<delete header lines and examine mailed archive>
71+\&...
72+sh archive
73+.Ed
74+.Sh SEE ALSO
75+.Xr compress 1 ,
76+.Xr mail 1 ,
77+.Xr tar 1 ,
78+.Xr uuencode 1
79+.Sh HISTORY
80+The
81+.Nm
82+command appeared in
83+.Bx 4.4 .
84+.Sh BUGS
85+.Nm
86+makes no provisions for special types of files.
87+It is not intended for binary files containing NUL bytes.
88+.Sh SECURITY CONSIDERATIONS
89+It is easy to insert trojan horses into
90+.Nm
91+files.
92+It is strongly recommended that all shell archive files be examined
93+before running them through
94+.Xr sh 1 .
+157, -0
  1@@ -0,0 +1,157 @@
  2+/*small shar in C inspired by netbsd shar script but with some 
  3+ * improvements, public domain :] */
  4+
  5+#include <sys/stat.h>
  6+
  7+#include <errno.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+
 12+
 13+/* single quote path name */
 14+static void
 15+q(char *s)
 16+{
 17+	putchar('\'');
 18+	for (; *s; s++)
 19+		if (*s == '\'')
 20+			fputs("'\\''", stdout);
 21+		else
 22+			putchar(*s);
 23+	putchar('\'');
 24+}
 25+
 26+static void
 27+qt(char *s, char *t)
 28+{
 29+	q(s);
 30+	fputs(t, stdout);
 31+}
 32+
 33+static void
 34+mkpar(char *s)
 35+{
 36+	char *p, *e;
 37+	size_t n;
 38+
 39+	if ((e = strrchr(s, '/')) == NULL || e == s)
 40+		return;
 41+	n = e - s;
 42+	if ((p = malloc(n + 1)) == NULL) {
 43+		fprintf(stderr, "shar: %s\n", strerror(errno));
 44+		exit(1);
 45+	}
 46+	memcpy(p, s, n);
 47+	p[n] = 0;
 48+	fputs("mkdir -p ", stdout);
 49+	q(p);
 50+	fputs(" > /dev/null 2>&1\n", stdout);
 51+	free(p);
 52+}
 53+
 54+static int
 55+readfile(char *s)
 56+{
 57+	FILE *f;
 58+	struct stat st;
 59+	int c, bol = 1;
 60+
 61+	if ((f = fopen(s, "r")) == NULL) {
 62+		fprintf(stderr, "shar: %s: %s\n", s, strerror(errno));
 63+		return 1;
 64+	}
 65+	if (fstat(fileno(f), &st) == -1) {
 66+		fprintf(stderr, "shar: %s: %s\n", s, strerror(errno));
 67+		fclose(f);
 68+		return 1;
 69+	}
 70+	mkpar(s);
 71+	fputs("echo x - ", stdout);
 72+	q(s);
 73+	fputs("\nsed 's/^X//' >", stdout);
 74+	q(s);
 75+	fputs(" << 'SHAR_EOF'\n", stdout);
 76+	while ((c = getc(f)) != EOF) {
 77+		if (bol)
 78+			putchar('X');
 79+		putchar(c);
 80+		bol = c == '\n';
 81+	}
 82+	if (ferror(f)) {
 83+		fprintf(stderr, "shar: %s: %s\n", s, strerror(errno));
 84+		fclose(f);
 85+		return 1;
 86+	}
 87+	fclose(f);
 88+	/* netbsd shar glues the marker to non newline files but we fix and trim */
 89+	if (!bol)
 90+		putchar('\n');
 91+	fputs("SHAR_EOF\n", stdout);
 92+	if (!bol) {
 93+		fputs("dd if=", stdout);
 94+		q(s);
 95+		fputs(" of=", stdout);
 96+		qt(s, ".$$");
 97+		printf(" bs=1 count=%lld > /dev/null 2>&1 && mv ",
 98+		    (long long)st.st_size);
 99+		qt(s, ".$$");
100+		putchar(' ');
101+		q(s);
102+		putchar('\n');
103+	}
104+	printf("chmod %03o ", (unsigned)st.st_mode & 0777);
105+	q(s);
106+	putchar('\n');
107+	return 0;
108+}
109+
110+static void
111+makedir(char *s, mode_t m)
112+{
113+	fputs("echo c - ", stdout);
114+	q(s);
115+	fputs("\nmkdir -p ", stdout);
116+	q(s);
117+	fputs(" > /dev/null 2>&1\n", stdout);
118+	printf("chmod %03o ", (unsigned)m & 0777);
119+	q(s);
120+	putchar('\n');
121+}
122+
123+static void
124+head(int n, char **v)
125+{
126+	int i;
127+
128+	fputs("# This is a shell archive.  Save it in a file, remove anything before\n"
129+	    "# this line, and then unpack it by entering \"sh file\".  Note, it may\n"
130+	    "# create directories; files and directories will be owned by you and\n"
131+	    "# have their original permissions.\n"
132+	    "#\n"
133+	    "# This archive contains:\n"
134+	    "#\n", stdout);
135+	for (i = 1; i < n; i++)
136+		printf("#\t%s\n", v[i]);
137+	printf("#\n");
138+}
139+
140+int
141+main(int n, char **v)
142+{
143+	struct stat st;
144+	int i;
145+
146+	if (n == 1) {
147+		fprintf(stderr, "usage: shar [file ...]\n");
148+		return 1;
149+	}
150+	head(n, v);
151+	for (i = 1; i < n; i++)
152+		if (stat(v[i], &st) == 0 && S_ISDIR(st.st_mode))
153+			makedir(v[i], st.st_mode);
154+		else if (readfile(v[i]))
155+			return 1;
156+	printf("exit\n\n");
157+	return 0;
158+}