uudecode.c revision 1.18 1 /* $NetBSD: uudecode.c,v 1.18 2003/10/27 00:12:43 lukem Exp $ */
2
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 HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35
36 #include <sys/cdefs.h>
37 #if !defined(lint)
38 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #if 0
41 static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94";
42 #endif
43 __RCSID("$NetBSD: uudecode.c,v 1.18 2003/10/27 00:12:43 lukem Exp $");
44 #endif /* not lint */
45
46 /*
47 * uudecode [file ...]
48 *
49 * create the specified file, decoding as you go.
50 * used with uuencode.
51 */
52 #include <sys/param.h>
53 #include <sys/stat.h>
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <limits.h>
58 #include <locale.h>
59 #include <pwd.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64
65 static int decode __P((void));
66 static void usage __P((void));
67 int main __P((int, char **));
68
69 int pflag;
70 char *filename;
71
72 int
73 main(argc, argv)
74 int argc;
75 char *argv[];
76 {
77 int ch, rval;
78
79 setlocale(LC_ALL, "");
80
81 pflag = 0;
82 while ((ch = getopt(argc, argv, "p")) != -1)
83 switch (ch) {
84 case 'p':
85 pflag = 1;
86 break;
87 default:
88 usage();
89 }
90 argc -= optind;
91 argv += optind;
92
93 if (*argv) {
94 rval = 0;
95 do {
96 if (!freopen(filename = *argv, "r", stdin)) {
97 warn("%s", *argv);
98 rval = 1;
99 continue;
100 }
101 rval |= decode();
102 } while (*++argv);
103 } else {
104 filename = "stdin";
105 rval = decode();
106 }
107 exit(rval);
108 }
109
110 static int
111 decode()
112 {
113 struct passwd *pw;
114 int n;
115 char ch, *p;
116 int n1;
117 long mode;
118 char *fn;
119 char buf[MAXPATHLEN];
120
121 /* search for header line */
122 do {
123 if (!fgets(buf, sizeof(buf), stdin)) {
124 warnx("%s: no \"begin\" line", filename);
125 return(1);
126 }
127 } while (strncmp(buf, "begin ", 6));
128 /* must be followed by an octal mode and a space */
129 mode = strtol(buf + 6, &fn, 8);
130 if (fn == (buf+6) || !isspace(*fn) || mode==LONG_MIN || mode==LONG_MAX)
131 {
132 warnx("%s: invalid mode on \"begin\" line", filename);
133 return(1);
134 }
135 /* skip whitespace for file name */
136 while (*fn && isspace(*fn)) fn++;
137 if (*fn == 0) {
138 warnx("%s: no filename on \"begin\" line", filename);
139 return(1);
140 }
141 /* zap newline */
142 for (p = fn; *p && *p != '\n'; p++)
143 ;
144 if (*p) *p = 0;
145
146 /* handle ~user/file format */
147 if (*fn == '~') {
148 if (!(p = strchr(fn, '/'))) {
149 warnx("%s: illegal ~user.", filename);
150 return(1);
151 }
152 *p++ = '\0';
153 if (!(pw = getpwnam(fn + 1))) {
154 warnx("%s: no user %s.", filename, buf);
155 return(1);
156 }
157 n = strlen(pw->pw_dir);
158 n1 = strlen(p);
159 if (n + n1 + 2 > MAXPATHLEN) {
160 warnx("%s: path too long.", filename);
161 return(1);
162 }
163 /* make space at beginning of buf by moving end of pathname */
164 memmove(buf + n + 1, p, n1 + 1);
165 memmove(buf, pw->pw_dir, n);
166 buf[n] = '/';
167 fn = buf;
168 }
169
170 /* create output file, set mode */
171 if (!pflag && (!freopen(fn, "w", stdout) ||
172 fchmod(fileno(stdout), mode & 0666))) {
173 warn("%s: %s", fn, filename);
174 return(1);
175 }
176
177 /* for each input line */
178 for (;;) {
179 if (!fgets(p = buf, sizeof(buf), stdin)) {
180 warnx("%s: short file.", filename);
181 return(1);
182 }
183 #define DEC(c) (((c) - ' ') & 077) /* single character decode */
184 /*
185 * `n' is used to avoid writing out all the characters
186 * at the end of the file.
187 */
188 if ((n = DEC(*p)) <= 0)
189 break;
190 for (++p; n > 0; p += 4, n -= 3)
191 if (n >= 3) {
192 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
193 putchar(ch);
194 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
195 putchar(ch);
196 ch = DEC(p[2]) << 6 | DEC(p[3]);
197 putchar(ch);
198 }
199 else {
200 if (n >= 1) {
201 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
202 putchar(ch);
203 }
204 if (n >= 2) {
205 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
206 putchar(ch);
207 }
208 if (n >= 3) {
209 ch = DEC(p[2]) << 6 | DEC(p[3]);
210 putchar(ch);
211 }
212 }
213 }
214 if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) {
215 warnx("%s: no \"end\" line.", filename);
216 return(1);
217 }
218 return(0);
219 }
220
221 static void
222 usage()
223 {
224 (void)fprintf(stderr, "usage: uudecode [-p] [file ...]\n");
225 exit(1);
226 }
227