Add in a patch to make busybox use the normal pwd.h and grp.h
[oweals/busybox.git] / uudecode.c
1 /* uudecode.c -- uudecode utility.
2  * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3  *
4  * This product is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This product is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this product; see the file COPYING.  If not, write to
16  * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  *
19  * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
20  *
21  * Original copyright notice is retained at the end of this file.
22  */
23
24
25 #include "busybox.h"
26
27 #include <stdio.h>
28 #include <errno.h>
29 #include <getopt.h>
30
31 /*struct passwd *getpwnam();*/
32
33 /* Single character decode.  */
34 #define DEC(Char) (((Char) - ' ') & 077)
35
36 static int read_stduu (const char *inname)
37 {
38   char buf[2 * BUFSIZ];
39
40   while (1) {
41     int n;
42     char *p;
43
44     if (fgets (buf, sizeof(buf), stdin) == NULL) {
45       error_msg("%s: Short file\n", inname);
46       return FALSE;
47     }
48     p = buf;
49
50     /* N is used to avoid writing out all the characters at the end of
51        the file.  */
52     n = DEC (*p);
53     if (n <= 0)
54       break;
55     for (++p; n > 0; p += 4, n -= 3) {
56       char ch;
57
58       if (n >= 3) {
59         ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
60         putchar (ch);
61         ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
62         putchar (ch);
63         ch = DEC (p[2]) << 6 | DEC (p[3]);
64         putchar (ch);
65       } else {
66         if (n >= 1) {
67           ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
68           putchar (ch);
69         }
70         if (n >= 2) {
71           ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
72           putchar (ch);
73         }
74       }
75     }
76   }
77
78   if (fgets (buf, sizeof(buf), stdin) == NULL
79       || strcmp (buf, "end\n")) {
80     error_msg("%s: No `end' line\n", inname);
81     return FALSE;
82   }
83
84   return TRUE;
85 }
86
87 static int read_base64 (const char *inname)
88 {
89   static const char b64_tab[256] = {
90     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
91     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
92     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
93     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
94     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
95     '\177', '\177', '\177', '\76',  '\177', '\177', '\177', '\77',  /*050-057*/
96     '\64',  '\65',  '\66',  '\67',  '\70',  '\71',  '\72',  '\73',  /*060-067*/
97     '\74',  '\75',  '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
98     '\177', '\0',   '\1',   '\2',   '\3',   '\4',   '\5',   '\6',   /*100-107*/
99     '\7',   '\10',  '\11',  '\12',  '\13',  '\14',  '\15',  '\16',  /*110-117*/
100     '\17',  '\20',  '\21',  '\22',  '\23',  '\24',  '\25',  '\26',  /*120-127*/
101     '\27',  '\30',  '\31',  '\177', '\177', '\177', '\177', '\177', /*130-137*/
102     '\177', '\32',  '\33',  '\34',  '\35',  '\36',  '\37',  '\40',  /*140-147*/
103     '\41',  '\42',  '\43',  '\44',  '\45',  '\46',  '\47',  '\50',  /*150-157*/
104     '\51',  '\52',  '\53',  '\54',  '\55',  '\56',  '\57',  '\60',  /*160-167*/
105     '\61',  '\62',  '\63',  '\177', '\177', '\177', '\177', '\177', /*170-177*/
106     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
107     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
108     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
109     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
110     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
111     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
112     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
113     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
114     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
115     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
116     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
117     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
118     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
119     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
120     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
121     '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
122   };
123   unsigned char buf[2 * BUFSIZ];
124
125   while (1) {
126     int last_data = 0;
127     unsigned char *p;
128
129     if (fgets (buf, sizeof(buf), stdin) == NULL) {
130       error_msg("%s: Short file\n", inname);
131       return FALSE;
132     }
133     p = buf;
134
135     if (memcmp (buf, "====", 4) == 0)
136       break;
137     if (last_data != 0) {
138       error_msg("%s: data following `=' padding character\n", inname);
139       return FALSE;
140     }
141
142     /* The following implementation of the base64 decoding might look
143        a bit clumsy but I only try to follow the POSIX standard:
144        ``All line breaks or other characters not found in the table
145        [with base64 characters] shall be ignored by decoding
146        software.''  */
147     while (*p != '\n') {
148       char c1, c2, c3;
149
150       while ((b64_tab[*p] & '\100') != 0)
151         if (*p == '\n' || *p++ == '=')
152           break;
153       if (*p == '\n')
154         /* This leaves the loop.  */
155         continue;
156       c1 = b64_tab[*p++];
157
158       while ((b64_tab[*p] & '\100') != 0)
159         if (*p == '\n' || *p++ == '=') {
160           error_msg("%s: illegal line\n", inname);
161           return FALSE;
162         }
163       c2 = b64_tab[*p++];
164
165       while (b64_tab[*p] == '\177')
166         if (*p++ == '\n') {
167           error_msg("%s: illegal line\n", inname);
168           return FALSE;
169         }
170       if (*p == '=') {
171         putchar (c1 << 2 | c2 >> 4);
172         last_data = 1;
173         break;
174       }
175       c3 = b64_tab[*p++];
176
177       while (b64_tab[*p] == '\177')
178         if (*p++ == '\n') {
179           error_msg("%s: illegal line\n", inname);
180           return FALSE;
181         }
182       putchar (c1 << 2 | c2 >> 4);
183       putchar (c2 << 4 | c3 >> 2);
184       if (*p == '=') {
185         last_data = 1;
186         break;
187       }
188       else
189         putchar (c3 << 6 | b64_tab[*p++]);
190     }
191   }
192
193   return TRUE;
194 }
195
196 static int decode (const char *inname,
197                    const char *forced_outname)
198 {
199   struct passwd *pw;
200   register int n;
201   register char *p;
202   int mode, n1;
203   char buf[2 * BUFSIZ];
204   char *outname;
205   int do_base64 = 0;
206
207   /* Search for header line.  */
208
209   while (1) {
210     if (fgets (buf, sizeof (buf), stdin) == NULL) {
211       error_msg("%s: No `begin' line\n", inname);
212       return FALSE;
213     }
214
215     if (strncmp (buf, "begin", 5) == 0) {
216       if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
217         do_base64 = 1;
218         break;
219       } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
220         break;
221     }
222   }
223
224   /* If the output file name is given on the command line this rules.  */
225   if (forced_outname != NULL)
226     outname = (char *) forced_outname;
227   else {
228     /* Handle ~user/file format.  */
229     if (buf[0] != '~')
230       outname = buf;
231     else {
232       p = buf + 1;
233       while (*p != '/')
234         ++p;
235       if (*p == '\0') {
236         error_msg("%s: Illegal ~user\n", inname);
237         return FALSE;
238       }
239       *p++ = '\0';
240       pw = getpwnam (buf + 1);
241       if (pw == NULL) {
242         error_msg("%s: No user `%s'\n", inname, buf + 1);
243         return FALSE;
244       }
245       n = strlen (pw->pw_dir);
246       n1 = strlen (p);
247       outname = (char *) alloca ((size_t) (n + n1 + 2));
248       memcpy (outname + n + 1, p, (size_t) (n1 + 1));
249       memcpy (outname, pw->pw_dir, (size_t) n);
250       outname[n] = '/';
251     }
252   }
253
254   /* Create output file and set mode.  */
255   if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
256       && (freopen (outname, "w", stdout) == NULL
257           || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
258          )) {
259     perror_msg("%s", outname); /* */
260     return FALSE;
261   }
262
263   /* We differenciate decoding standard UU encoding and base64.  A
264      common function would only slow down the program.  */
265
266   /* For each input line:  */
267   if (do_base64)
268     return read_base64 (inname);
269   else
270     return read_stduu (inname);
271 }
272
273 int uudecode_main (int argc,
274                    char **argv)
275 {
276   int opt;
277   int exit_status;
278   const char *outname;
279   outname = NULL;
280
281   while ((opt = getopt(argc, argv, "o:")) != EOF) {
282     switch (opt) {
283      case 0:
284       break;
285
286      case 'o':
287       outname = optarg;
288       break;
289
290      default:
291       usage(uudecode_usage);
292     }
293   }
294
295   if (optind == argc)
296     exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
297   else {
298     exit_status = EXIT_SUCCESS;
299     do {
300       if (freopen (argv[optind], "r", stdin) != NULL) {
301         if (decode (argv[optind], outname) != 0)
302           exit_status = FALSE;
303       } else {
304         perror_msg("%s", argv[optind]);
305         exit_status = EXIT_FAILURE;
306       }
307       optind++;
308     }
309     while (optind < argc);
310   }
311   return(exit_status);
312 }
313
314 /* Copyright (c) 1983 Regents of the University of California.
315  * All rights reserved.
316  *
317  * Redistribution and use in source and binary forms, with or without
318  * modification, are permitted provided that the following conditions
319  * are met:
320  * 1. Redistributions of source code must retain the above copyright
321  *    notice, this list of conditions and the following disclaimer.
322  * 2. Redistributions in binary form must reproduce the above copyright
323  *    notice, this list of conditions and the following disclaimer in the
324  *    documentation and/or other materials provided with the distribution.
325  *
326  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
327  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
328  *
329  * 4. Neither the name of the University nor the names of its contributors
330  *    may be used to endorse or promote products derived from this software
331  *    without specific prior written permission.
332  *
333  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
334  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
335  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
336  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
337  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
338  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
339  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
340  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
342  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
343  * SUCH DAMAGE.
344  */
345
346