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