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