commit c677451

shrub  ·  2026-06-24 00:12:35 +0000 UTC
parent 03a391f
add shar
4 files changed,  +302, -0
+42, -0
 1@@ -0,0 +1,42 @@
 2+# i know this is a ninja file, but you're allowed to edit it.
 3+# you can also pass things on the command line if you like, eg
 4+#
 5+#     CC=clang ninja
 6+
 7+cc = $${CC:-cc}
 8+cflags = $${CFLAGS:--O2 -std=c99}
 9+ldflags = $${LDFLAGS:-}
10+libs = $${LIBS:-}
11+prefix = $${PREFIX:-/usr/local}
12+destdir = $${DESTDIR:-}
13+bindir = $${BINDIR:-$${DESTDIR:-}$${PREFIX:-/usr/local}/bin}
14+mandir = $${MANDIR:-$${DESTDIR:-}$${PREFIX:-/usr/local}/man/man1}
15+
16+rule cc
17+  command = $cc $cflags -MMD -MF $out.d -c -o $out $in
18+  deps = gcc
19+  depfile = $out.d
20+  description = cc $out
21+
22+rule link
23+  command = $cc $ldflags -o $out $in $libs
24+  description = link $out
25+
26+rule install
27+  command = mkdir -p $bindir && cp shar $bindir/
28+  description = install shar
29+
30+rule install-man
31+  command = mkdir -p $mandir && cp shar.1 $mandir/
32+  description = man shar.1
33+
34+build shar.o: cc shar.c
35+
36+build shar: link shar.o
37+build all: phony shar
38+build man: install-man shar.1
39+build install: phony install-bin install-man
40+build install-bin: install shar
41+build install-man: install-man shar.1
42+
43+default all
+9, -0
 1@@ -0,0 +1,9 @@
 2+shar
 3+----
 4+a small public domain shar implementation.
 5+
 6+build:
 7+    ninja
 8+    ninja install
 9+
10+
+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 .
+158, -0
  1@@ -0,0 +1,158 @@
  2+/*small shar in C inspired by netbsd shar script but with some 
  3+ * improvements, public domain :] */
  4+
  5+#include <sys/stat.h>
  6+#include <sys/types.h>
  7+
  8+#include <errno.h>
  9+#include <stdio.h>
 10+#include <stdlib.h>
 11+#include <string.h>
 12+
 13+
 14+/* single quote path name */
 15+static void
 16+q(char *s)
 17+{
 18+	putchar('\'');
 19+	for (; *s; s++)
 20+		if (*s == '\'')
 21+			fputs("'\\''", stdout);
 22+		else
 23+			putchar(*s);
 24+	putchar('\'');
 25+}
 26+
 27+static void
 28+qt(char *s, char *t)
 29+{
 30+	q(s);
 31+	fputs(t, stdout);
 32+}
 33+
 34+static void
 35+mkpar(char *s)
 36+{
 37+	char *p, *e;
 38+	size_t n;
 39+
 40+	if ((e = strrchr(s, '/')) == NULL || e == s)
 41+		return;
 42+	n = e - s;
 43+	if ((p = malloc(n + 1)) == NULL) {
 44+		fprintf(stderr, "shar: %s\n", strerror(errno));
 45+		exit(1);
 46+	}
 47+	memcpy(p, s, n);
 48+	p[n] = 0;
 49+	fputs("mkdir -p ", stdout);
 50+	q(p);
 51+	fputs(" > /dev/null 2>&1\n", stdout);
 52+	free(p);
 53+}
 54+
 55+static int
 56+readfile(char *s)
 57+{
 58+	FILE *f;
 59+	struct stat st;
 60+	int c, bol = 1;
 61+
 62+	if ((f = fopen(s, "r")) == NULL) {
 63+		fprintf(stderr, "shar: %s: %s\n", s, strerror(errno));
 64+		return 1;
 65+	}
 66+	if (stat(s, &st) == -1) {
 67+		fprintf(stderr, "shar: %s: %s\n", s, strerror(errno));
 68+		fclose(f);
 69+		return 1;
 70+	}
 71+	mkpar(s);
 72+	fputs("echo x - ", stdout);
 73+	q(s);
 74+	fputs("\nsed 's/^X//' >", stdout);
 75+	q(s);
 76+	fputs(" << 'SHAR_EOF'\n", stdout);
 77+	while ((c = getc(f)) != EOF) {
 78+		if (bol)
 79+			putchar('X');
 80+		putchar(c);
 81+		bol = c == '\n';
 82+	}
 83+	if (ferror(f)) {
 84+		fprintf(stderr, "shar: %s: %s\n", s, strerror(errno));
 85+		fclose(f);
 86+		return 1;
 87+	}
 88+	fclose(f);
 89+	/* netbsd shar glues the marker to non newline files but we fix and trim */
 90+	if (!bol)
 91+		putchar('\n');
 92+	fputs("SHAR_EOF\n", stdout);
 93+	if (!bol) {
 94+		fputs("dd if=", stdout);
 95+		q(s);
 96+		fputs(" of=", stdout);
 97+		qt(s, ".$$");
 98+		printf(" bs=1 count=%lld > /dev/null 2>&1 && mv ",
 99+		    (long long)st.st_size);
100+		qt(s, ".$$");
101+		putchar(' ');
102+		q(s);
103+		putchar('\n');
104+	}
105+	printf("chmod %03o ", (unsigned)st.st_mode & 0777);
106+	q(s);
107+	putchar('\n');
108+	return 0;
109+}
110+
111+static void
112+makedir(char *s, mode_t m)
113+{
114+	fputs("echo c - ", stdout);
115+	q(s);
116+	fputs("\nmkdir -p ", stdout);
117+	q(s);
118+	fputs(" > /dev/null 2>&1\n", stdout);
119+	printf("chmod %03o ", (unsigned)m & 0777);
120+	q(s);
121+	putchar('\n');
122+}
123+
124+static void
125+head(int n, char **v)
126+{
127+	int i;
128+
129+	fputs("# This is a shell archive.  Save it in a file, remove anything before\n"
130+	    "# this line, and then unpack it by entering \"sh file\".  Note, it may\n"
131+	    "# create directories; files and directories will be owned by you and\n"
132+	    "# have their original permissions.\n"
133+	    "#\n"
134+	    "# This archive contains:\n"
135+	    "#\n", stdout);
136+	for (i = 1; i < n; i++)
137+		printf("#\t%s\n", v[i]);
138+	printf("#\n");
139+}
140+
141+int
142+main(int n, char **v)
143+{
144+	struct stat st;
145+	int i;
146+
147+	if (n == 1) {
148+		fprintf(stderr, "usage: shar [file ...]\n");
149+		return 1;
150+	}
151+	head(n, v);
152+	for (i = 1; i < n; i++)
153+		if (stat(v[i], &st) == 0 && S_ISDIR(st.st_mode))
154+			makedir(v[i], st.st_mode);
155+		else if (readfile(v[i]))
156+			return 1;
157+	printf("exit\n\n");
158+	return 0;
159+}