uudecode.c revision 58666
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1983, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3528564Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1983, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4128564Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)uudecode.c	8.2 (Berkeley) 4/2/94";
4328564Scharnier#endif
4428564Scharnierstatic const char rcsid[] =
4550477Speter  "$FreeBSD: head/usr.bin/uudecode/uudecode.c 58666 2000-03-27 11:49:36Z sheldonh $";
461590Srgrimes#endif /* not lint */
471590Srgrimes
481590Srgrimes/*
491590Srgrimes * uudecode [file ...]
501590Srgrimes *
511590Srgrimes * create the specified file, decoding as you go.
521590Srgrimes * used with uuencode.
531590Srgrimes */
541590Srgrimes#include <sys/param.h>
551590Srgrimes#include <sys/stat.h>
561590Srgrimes
5728564Scharnier#include <err.h>
5822887Swosch#include <fnmatch.h>
591590Srgrimes#include <pwd.h>
601590Srgrimes#include <stdio.h>
6128564Scharnier#include <stdlib.h>
621590Srgrimes#include <string.h>
6328564Scharnier#include <unistd.h>
641590Srgrimes
651590Srgrimeschar *filename;
6632780Swoschint cflag, iflag, pflag, sflag;
671590Srgrimes
6828564Scharnierstatic void usage __P((void));
6919078Swoschint	decode __P((void));
7019078Swoschint	decode2 __P((int));
7119078Swosch
721590Srgrimesint
731590Srgrimesmain(argc, argv)
741590Srgrimes	int argc;
751590Srgrimes	char *argv[];
761590Srgrimes{
7719078Swosch	int rval, ch;
781590Srgrimes
7932780Swosch	while ((ch = getopt(argc, argv, "cips")) != -1) {
8019078Swosch		switch(ch) {
8119078Swosch		case 'c':
8219078Swosch			cflag = 1; /* multiple uudecode'd files */
8319078Swosch			break;
8432780Swosch		case 'i':
8532780Swosch			iflag = 1; /* ask before override files */
8632780Swosch			break;
8719078Swosch		case 'p':
8819078Swosch			pflag = 1; /* print output to stdout */
8919078Swosch			break;
9032780Swosch		case 's':
9132780Swosch			sflag = 1; /* do not strip pathnames for output */
9232780Swosch			break;
9319078Swosch		default:
9428564Scharnier			usage();
9519078Swosch		}
9619078Swosch	}
9719078Swosch        argc -= optind;
9819078Swosch        argv += optind;
9919078Swosch
10019078Swosch
10119078Swosch	if (*argv) {
1021590Srgrimes		rval = 0;
1031590Srgrimes		do {
1041590Srgrimes			if (!freopen(filename = *argv, "r", stdin)) {
10528564Scharnier				warn("%s", *argv);
1061590Srgrimes				rval = 1;
1071590Srgrimes				continue;
1081590Srgrimes			}
1091590Srgrimes			rval |= decode();
1101590Srgrimes		} while (*++argv);
1111590Srgrimes	} else {
1121590Srgrimes		filename = "stdin";
1131590Srgrimes		rval = decode();
1141590Srgrimes	}
1151590Srgrimes	exit(rval);
1161590Srgrimes}
1171590Srgrimes
11819078Swoschint
11919078Swoschdecode ()
1201590Srgrimes{
12119078Swosch	int flag;
12219078Swosch
12319078Swosch	/* decode only one file per input stream */
12419078Swosch	if (!cflag)
12519078Swosch		return(decode2(0));
12619078Swosch
12719078Swosch	/* multiple uudecode'd files */
12819078Swosch	for (flag = 0; ; flag++)
12919078Swosch		if (decode2(flag))
13019078Swosch			return(1);
13119078Swosch		else if (feof(stdin))
13219078Swosch			break;
13319078Swosch
13419078Swosch	return(0);
13519078Swosch}
13619078Swosch
13719078Swoschint
13819078Swoschdecode2(flag)
13919078Swosch	int flag;
14019078Swosch{
1411590Srgrimes	struct passwd *pw;
1421590Srgrimes	register int n;
14332780Swosch	register char ch, first, *p;
14458666Ssheldonh	int ignore, mode, n1;
1451590Srgrimes	char buf[MAXPATHLEN];
14622887Swosch	char buffn[MAXPATHLEN]; /* file name buffer */
1471590Srgrimes
14858666Ssheldonh	ignore = 0;
1491590Srgrimes	/* search for header line */
1501590Srgrimes	do {
1511590Srgrimes		if (!fgets(buf, sizeof(buf), stdin)) {
15219078Swosch			if (flag) /* no error */
15319078Swosch				return(0);
15419078Swosch
15528564Scharnier			warnx("%s: no \"begin\" line", filename);
1561590Srgrimes			return(1);
1571590Srgrimes		}
15822887Swosch	} while (strncmp(buf, "begin ", 6) ||
15922887Swosch		 fnmatch("begin [0-7]* *", buf, 0));
16022887Swosch
16136355Ssteve	(void)sscanf(buf, "begin %o %[^\n\r]", &mode, buf);
1621590Srgrimes
16332780Swosch	if (!sflag && !pflag) {
16432780Swosch		strncpy(buffn, buf, sizeof(buffn));
16532780Swosch		if (strrchr(buffn, '/') != NULL)
16632780Swosch			strncpy(buf, strrchr(buffn, '/') + 1, sizeof(buf));
16732780Swosch		if (buf[0] == '\0') {
16832780Swosch			warnx("%s: illegal filename", buffn);
16932780Swosch			return(1);
17032780Swosch		}
17132780Swosch	}
17232780Swosch
1731590Srgrimes	/* handle ~user/file format */
1741590Srgrimes	if (buf[0] == '~') {
1751590Srgrimes		if (!(p = index(buf, '/'))) {
17628564Scharnier			warnx("%s: illegal ~user", filename);
1771590Srgrimes			return(1);
1781590Srgrimes		}
17929574Sphk		*p++ = '\0';
1801590Srgrimes		if (!(pw = getpwnam(buf + 1))) {
18128564Scharnier			warnx("%s: no user %s", filename, buf);
1821590Srgrimes			return(1);
1831590Srgrimes		}
1841590Srgrimes		n = strlen(pw->pw_dir);
1851590Srgrimes		n1 = strlen(p);
1861590Srgrimes		if (n + n1 + 2 > MAXPATHLEN) {
18728564Scharnier			warnx("%s: path too long", filename);
1881590Srgrimes			return(1);
1891590Srgrimes		}
1901590Srgrimes		bcopy(p, buf + n + 1, n1 + 1);
1911590Srgrimes		bcopy(pw->pw_dir, buf, n);
1921590Srgrimes		buf[n] = '/';
1931590Srgrimes	}
1941590Srgrimes
1951590Srgrimes	/* create output file, set mode */
19619078Swosch	if (pflag)
19719078Swosch		; /* print to stdout */
19819078Swosch
19932780Swosch	else {
20058666Ssheldonh		if (iflag && !access(buf, F_OK)) {
20132780Swosch			(void)fprintf(stderr, "not overwritten: %s\n", buf);
20258666Ssheldonh			ignore++;
20358666Ssheldonh		} else if (!freopen(buf, "w", stdout) ||
20432780Swosch		    fchmod(fileno(stdout), mode&0666)) {
20532780Swosch			warn("%s: %s", buf, filename);
20632780Swosch			return(1);
20732780Swosch		}
2081590Srgrimes	}
20922887Swosch	strcpy(buffn, buf); /* store file name from header line */
2101590Srgrimes
2111590Srgrimes	/* for each input line */
2121590Srgrimes	for (;;) {
2131590Srgrimes		if (!fgets(p = buf, sizeof(buf), stdin)) {
21428564Scharnier			warnx("%s: short file", filename);
2151590Srgrimes			return(1);
2161590Srgrimes		}
2171590Srgrimes#define	DEC(c)	(((c) - ' ') & 077)		/* single character decode */
21824263Swosch#define IS_DEC(c) ( (((c) - ' ') >= 0) &&  (((c) - ' ') <= 077 + 1) )
21922887Swosch/* #define IS_DEC(c) (1) */
22022887Swosch
22122887Swosch#define OUT_OF_RANGE \
22222887Swosch{	\
22328564Scharnier    warnx( \
22428564Scharnier"\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \
22528564Scharnier 	filename, buffn, 1 + ' ', 077 + ' ' + 1); \
22622887Swosch        return(1); \
22722887Swosch}
22858666Ssheldonh#define PUTCHAR(c) \
22958666Ssheldonhif (!ignore) \
23058666Ssheldonh	putchar(c)
23122887Swosch
23222887Swosch
2331590Srgrimes		/*
2341590Srgrimes		 * `n' is used to avoid writing out all the characters
2351590Srgrimes		 * at the end of the file.
2361590Srgrimes		 */
2371590Srgrimes		if ((n = DEC(*p)) <= 0)
2381590Srgrimes			break;
2391590Srgrimes		for (++p; n > 0; p += 4, n -= 3)
2401590Srgrimes			if (n >= 3) {
24122887Swosch				if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
24222887Swosch				     IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
24322887Swosch                                	OUT_OF_RANGE
24422887Swosch
2451590Srgrimes				ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
24658666Ssheldonh				PUTCHAR(ch);
2471590Srgrimes				ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
24858666Ssheldonh				PUTCHAR(ch);
2491590Srgrimes				ch = DEC(p[2]) << 6 | DEC(p[3]);
25058666Ssheldonh				PUTCHAR(ch);
25122887Swosch
2521590Srgrimes			}
2531590Srgrimes			else {
2541590Srgrimes				if (n >= 1) {
25522887Swosch					if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
25622887Swosch	                                	OUT_OF_RANGE
2571590Srgrimes					ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
25858666Ssheldonh					PUTCHAR(ch);
2591590Srgrimes				}
2601590Srgrimes				if (n >= 2) {
26122887Swosch					if (!(IS_DEC(*(p + 1)) &&
26222887Swosch						IS_DEC(*(p + 2))))
26322887Swosch		                                OUT_OF_RANGE
26422887Swosch
2651590Srgrimes					ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
26658666Ssheldonh					PUTCHAR(ch);
2671590Srgrimes				}
2681590Srgrimes				if (n >= 3) {
26922887Swosch					if (!(IS_DEC(*(p + 2)) &&
27022887Swosch						IS_DEC(*(p + 3))))
27122887Swosch		                                OUT_OF_RANGE
2721590Srgrimes					ch = DEC(p[2]) << 6 | DEC(p[3]);
27358666Ssheldonh					PUTCHAR(ch);
2741590Srgrimes				}
2751590Srgrimes			}
2761590Srgrimes	}
27722894Swosch	if (fgets(buf, sizeof(buf), stdin) == NULL ||
27822894Swosch	    (strcmp(buf, "end") && strcmp(buf, "end\n") &&
27922894Swosch	     strcmp(buf, "end\r\n"))) {
28028564Scharnier		warnx("%s: no \"end\" line", filename);
2811590Srgrimes		return(1);
2821590Srgrimes	}
2831590Srgrimes	return(0);
2841590Srgrimes}
2851590Srgrimes
28628564Scharnierstatic void
2871590Srgrimesusage()
2881590Srgrimes{
28932780Swosch	(void)fprintf(stderr, "usage: uudecode [-cips] [file ...]\n");
2901590Srgrimes	exit(1);
2911590Srgrimes}
292