1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1984, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27
28 /*
29 * Portions of this source code were derived from Berkeley 4.3 BSD
30 * under license from the Regents of the University of California.
31 */
32
33 /*
34 * uuencode [-m] [input] decode_pathname
35 *
36 * Encode a file so it can be mailed to a remote system.
37 */
38 #include <unistd.h>
39 #include <limits.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <locale.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <assert.h>
48 #include <signal.h>
49
50 /*
51 * (Size of TABLE_SIZE octal is large enough to convert a basic 6-bit
52 * data chunk.)
53 */
54 #define TABLE_SIZE 0x40
55
56
57 static unsigned char base64_table_initializer[] =
58 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
59 "abcdefghijklmnopqrstuvwxyz0123456789+/";
60
61 static unsigned char encode_table[TABLE_SIZE];
62
63 /* ENC is the basic 1 character encoding function to make a char printing */
64 #define ENC(c) encode_table[(c) & 077]
65
66 static void encode(FILE *, FILE *, int);
67 static char *prog;
68
69 int
main(int argc,char ** argv)70 main(int argc, char **argv)
71 {
72 FILE *in;
73 struct stat sbuf;
74 mode_t mode = 0;
75 int c, i;
76 int errflag = 0;
77 int base64flag = 0;
78 char oline[PATH_MAX + 20];
79
80 prog = argv[0];
81 (void) signal(SIGPIPE, SIG_DFL);
82
83 /* Set locale environment variables local definitions */
84 (void) setlocale(LC_ALL, "");
85 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
86 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
87 #endif
88 (void) textdomain(TEXT_DOMAIN);
89
90 while ((c = getopt(argc, argv, "m")) != EOF)
91 switch (c) {
92 case 'm':
93 base64flag++;
94 break;
95 default:
96 case '?':
97 errflag++;
98 }
99
100 argc -= optind;
101 argv = &argv[optind];
102
103 /* optional 1st argument */
104 if (argc > 1) {
105 if ((in = fopen(*argv, "r")) == NULL) {
106 perror(*argv);
107 exit(1);
108 }
109 argv++; argc--;
110 } else {
111 in = stdin;
112 mode = 0777;
113 }
114
115 if ((argc != 1) || errflag) {
116 (void) fprintf(stderr,
117 gettext("Usage: %s [-m] [infile] remotefile\n"), prog);
118 exit(2);
119 }
120
121 /* figure out the input file mode */
122 errno = 0;
123 if (fstat(fileno(in), &sbuf) < 0 || !S_ISREG(sbuf.st_mode)) {
124 mode = 0666 & ~umask(0666);
125 } else {
126 mode = sbuf.st_mode & 0777;
127 }
128
129 /*
130 * encoding varies depending on whether we are
131 * using base64 encoding or the historical algorithm
132 */
133 if (base64flag) {
134 (void) memcpy(encode_table, base64_table_initializer,
135 sizeof (encode_table));
136 } else {
137 for (i = 0; i < TABLE_SIZE; i++)
138 encode_table[i] = (unsigned char)i + 0x20;
139 }
140
141 /*
142 * here's the meat of the whole thing
143 */
144 if (base64flag)
145 (void) snprintf(oline, sizeof (oline), "begin-base64 %lo %s\n",
146 (long)mode, *argv);
147 else
148 (void) snprintf(oline, sizeof (oline), "begin %lo %s\n",
149 (long)mode, *argv);
150
151 if (printf("%s", oline) < 0) {
152 perror(prog);
153 exit(6);
154 }
155
156 encode(in, stdout, base64flag);
157
158 if (base64flag)
159 (void) snprintf(oline, sizeof (oline), "====\n");
160 else
161 (void) snprintf(oline, sizeof (oline), "end\n");
162
163 if (printf("%s", oline) < 0) {
164 perror(prog);
165 exit(6);
166 }
167
168 if (ferror(stdout) != 0 || fclose(stdout) != 0) {
169 perror(prog);
170 exit(6);
171 }
172
173 return (0);
174 }
175
176 /*
177 * copy from in to out, encoding as you go along.
178 */
179 static void
encode(FILE * in,FILE * out,int base64)180 encode(FILE *in, FILE *out, int base64)
181 {
182 unsigned char in_buf[80];
183 unsigned char out_buf[112];
184 unsigned char *iptr, *optr;
185 int i;
186 size_t n, opos;
187
188 if (! base64) {
189 /* historical algorithm */
190
191 for (;;) {
192 iptr = in_buf;
193 optr = out_buf;
194
195 /* 1 (up to) 45 character line */
196 n = fread(iptr, 1, 45, in);
197
198 *(optr++) = ENC(n);
199
200 for (i = 0; i < n; i += 3) {
201 *(optr++) = ENC(*iptr >> 2);
202 *(optr++) = ENC((*iptr << 4) & 060 |
203 (*(iptr + 1) >> 4) & 017);
204 *(optr++) = ENC((*(iptr + 1) << 2) & 074 |
205 (*(iptr + 2) >> 6) & 03);
206 *(optr++) = ENC(*(iptr + 2) & 077);
207 iptr += 3;
208 }
209
210 *(optr++) = '\n';
211
212 /*LINTED*/
213 (void) fwrite(out_buf, 1, (size_t)(optr - out_buf),
214 out);
215
216 if (ferror(out)) {
217 perror(prog);
218 exit(6);
219 }
220
221 if (n == 0)
222 break;
223 }
224 } else {
225 /* base64 algorithm */
226
227 optr = out_buf;
228 /*
229 * read must be a multiple of 3 bytes for
230 * this algorithm to work, and also must
231 * be small enough that read_size * (4/3)
232 * will always be 76 bytes or less, since
233 * base64 lines can be no longer than that
234 */
235 while ((n = fread(in_buf, 1, 51, in)) > 0) {
236 opos = 0;
237 iptr = in_buf;
238 for (i = 0; i < n / 3; i++) {
239 *(optr++) = ENC(*iptr >> 2);
240 *(optr++) = ENC((*iptr << 4) & 060 |
241 (*(iptr + 1) >> 4) & 017);
242 *(optr++) = ENC((*(iptr + 1) << 2)
243 & 074 | (*(iptr + 2) >> 6) & 03);
244 *(optr++) = ENC(*(iptr + 2) & 077);
245 iptr += 3;
246 opos += 3;
247
248 /* need output padding ? */
249 if (n - opos < 3)
250 break;
251
252 (void) fwrite(out_buf, 1,
253 /*LINTED*/
254 (size_t)(optr - out_buf), out);
255
256 if (ferror(out)) {
257 perror(prog);
258 exit(6);
259 }
260
261 optr = out_buf;
262 }
263 /*
264 * Take care of any output padding that is
265 * necessary.
266 */
267 assert(n - opos < 3);
268 switch (n - opos) {
269 case 0:
270 /* no-op - 24 bits of data encoded */
271 *(optr++) = '\n';
272 break;
273 case 1:
274 /* 8 bits encoded - pad with 2 '=' */
275 *(optr++) = ENC((*iptr & 0xFC) >> 2);
276 *(optr++) = ENC((*iptr & 0x03) << 4);
277 *(optr++) = '=';
278 *(optr++) = '=';
279 *(optr++) = '\n';
280 break;
281 case 2:
282 /* 16 bits encoded - pad with 1 '=' */
283 *(optr++) = ENC((*iptr & 0xFC) >> 2);
284 *(optr++) = ENC(((*iptr & 0x03) << 4) |
285 ((*(iptr + 1) & 0xF0) >> 4));
286 *(optr++) = ENC((*(iptr + 1) & 0x0F)
287 << 2);
288 *(optr++) = '=';
289 *(optr++) = '\n';
290 break;
291 default:
292 /* impossible */
293 break;
294 }
295 (void) fwrite(out_buf, 1,
296 /*LINTED*/
297 (size_t)(optr - out_buf), out);
298
299 if (ferror(out)) {
300 perror(prog);
301 exit(6);
302 }
303
304 optr = out_buf;
305 }
306 }
307 }
308