]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/bintrans/uuencode.c
Merge llvm-project release/15.x llvmorg-15.0.7-0-g8dfdcc7b7bf6
[FreeBSD/FreeBSD.git] / usr.bin / bintrans / uuencode.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1983, 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
32 #if 0
33 #ifndef lint
34 static const char copyright[] =
35 "@(#) Copyright (c) 1983, 1993\n\
36         The Regents of the University of California.  All rights reserved.\n";
37 #endif /* not lint */
38
39 #ifndef lint
40 static char sccsid[] = "@(#)uuencode.c  8.2 (Berkeley) 4/2/94";
41 #endif /* not lint */
42 #endif
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47  * uuencode [input] output
48  *
49  * Encode a file so it can be mailed to a remote system.
50  */
51 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <sys/stat.h>
54
55 #include <netinet/in.h>
56
57 #include <err.h>
58 #include <errno.h>
59 #include <libgen.h>
60 #include <resolv.h>
61 #include <stdio.h>
62 #include <stdbool.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66
67 extern int main_encode(int, char *[]);
68 extern int main_base64_encode(const char *, const char *);
69
70 static void encode(void);
71 static void base64_encode(void);
72 static int arg_to_col(const char *);
73 static void usage(void);
74
75 static FILE *output;
76 static int mode;
77 static bool raw;
78 static char **av;
79 static int columns = 76;
80
81 int
82 main_base64_encode(const char *in, const char *w)
83 {
84         raw = 1;
85         if (in != NULL && freopen(in, "r", stdin) == NULL)
86                 err(1, "%s", in);
87         output = stdout;
88         if (w != NULL)
89                 columns = arg_to_col(w);
90         base64_encode();
91         if (ferror(output))
92                 errx(1, "write error");
93         exit(0);
94 }
95
96 int
97 main_encode(int argc, char *argv[])
98 {
99         struct stat sb;
100         bool base64;
101         int ch;
102         const char *outfile;
103
104         base64 = false;
105         outfile = NULL;
106
107         if (strcmp(basename(argv[0]), "b64encode") == 0)
108                 base64 = 1;
109
110         while ((ch = getopt(argc, argv, "mo:rw:")) != -1) {
111                 switch (ch) {
112                 case 'm':
113                         base64 = true;
114                         break;
115                 case 'o':
116                         outfile = optarg;
117                         break;
118                 case 'r':
119                         raw = true;
120                         break;
121                 case 'w':
122                         columns = arg_to_col(optarg);
123                         break;
124                 case '?':
125                 default:
126                         usage();
127                 }
128         }
129         argv += optind;
130         argc -= optind;
131
132         switch (argc) {
133         case 2:                 /* optional first argument is input file */
134                 if (!freopen(*argv, "r", stdin) || fstat(fileno(stdin), &sb))
135                         err(1, "%s", *argv);
136 #define RWX     (S_IRWXU|S_IRWXG|S_IRWXO)
137                 mode = sb.st_mode & RWX;
138                 ++argv;
139                 break;
140         case 1:
141 #define RW      (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
142                 mode = RW & ~umask(RW);
143                 break;
144         case 0:
145         default:
146                 usage();
147         }
148
149         av = argv;
150
151         if (outfile != NULL) {
152                 output = fopen(outfile, "w+");
153                 if (output == NULL)
154                         err(1, "unable to open %s for output", outfile);
155         } else
156                 output = stdout;
157         if (base64)
158                 base64_encode();
159         else
160                 encode();
161         if (ferror(output))
162                 errx(1, "write error");
163         exit(0);
164 }
165
166 /* ENC is the basic 1 character encoding function to make a char printing */
167 #define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
168
169 /*
170  * Copy from in to out, encoding in base64 as you go along.
171  */
172 static void
173 base64_encode(void)
174 {
175         /*
176          * This buffer's length should be a multiple of 24 bits to avoid "="
177          * padding. Once it reached ~1 KB, further expansion didn't improve
178          * performance for me.
179          */
180         unsigned char buf[1023];
181         char buf2[sizeof(buf) * 2 + 1];
182         size_t n;
183         unsigned carry = 0;
184         int rv, written;
185
186         if (!raw)
187                 fprintf(output, "begin-base64 %o %s\n", mode, *av);
188         while ((n = fread(buf, 1, sizeof(buf), stdin))) {
189                 rv = b64_ntop(buf, n, buf2, nitems(buf2));
190                 if (rv == -1)
191                         errx(1, "b64_ntop: error encoding base64");
192                 if (columns == 0) {
193                         fputs(buf2, output);
194                         continue;
195                 }
196                 for (int i = 0; i < rv; i += written) {
197                         written = fprintf(output, "%.*s", columns - carry,
198                             &buf2[i]);
199
200                         carry = (carry + written) % columns;
201                         if (carry == 0)
202                                 fputc('\n', output);
203                 }
204         }
205         if (columns == 0 || carry != 0)
206                 fputc('\n', output);
207         if (!raw)
208                 fprintf(output, "====\n");
209 }
210
211 /*
212  * Copy from in to out, encoding as you go along.
213  */
214 static void
215 encode(void)
216 {
217         int ch, n;
218         char *p;
219         char buf[80];
220
221         if (!raw)
222                 (void)fprintf(output, "begin %o %s\n", mode, *av);
223         while ((n = fread(buf, 1, 45, stdin))) {
224                 ch = ENC(n);
225                 if (fputc(ch, output) == EOF)
226                         break;
227                 for (p = buf; n > 0; n -= 3, p += 3) {
228                         /* Pad with nulls if not a multiple of 3. */
229                         if (n < 3) {
230                                 p[2] = '\0';
231                                 if (n < 2)
232                                         p[1] = '\0';
233                         }
234                         ch = *p >> 2;
235                         ch = ENC(ch);
236                         if (fputc(ch, output) == EOF)
237                                 break;
238                         ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
239                         ch = ENC(ch);
240                         if (fputc(ch, output) == EOF)
241                                 break;
242                         ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
243                         ch = ENC(ch);
244                         if (fputc(ch, output) == EOF)
245                                 break;
246                         ch = p[2] & 077;
247                         ch = ENC(ch);
248                         if (fputc(ch, output) == EOF)
249                                 break;
250                 }
251                 if (fputc('\n', output) == EOF)
252                         break;
253         }
254         if (ferror(stdin))
255                 errx(1, "read error");
256         if (!raw)
257                 (void)fprintf(output, "%c\nend\n", ENC('\0'));
258 }
259
260 static int
261 arg_to_col(const char *w)
262 {
263         char *ep;
264         long option;
265
266         errno = 0;
267         option = strtol(w, &ep, 10);
268         if (option > INT_MAX)
269                 errno = ERANGE;
270         else if (ep[0] != '\0')
271                 errno = EINVAL;
272         if (errno != 0)
273                 err(2, NULL);
274
275         if (option < 0) {
276                 errno = EINVAL;
277                 err(2, "columns argument must be non-negative");
278         }
279         return (option);
280 }
281
282 static void
283 usage(void)
284 {
285         (void)fprintf(stderr,
286 "usage: uuencode [-m] [-o outfile] [infile] remotefile\n"
287 "       b64encode [-o outfile] [infile] remotefile\n");
288         exit(1);
289 }