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}