uudecode.c revision 28564
1/*- 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94"; 43#endif 44static const char rcsid[] = 45 "$Id$"; 46#endif /* not lint */ 47 48/* 49 * uudecode [file ...] 50 * 51 * create the specified file, decoding as you go. 52 * used with uuencode. 53 */ 54#include <sys/param.h> 55#include <sys/stat.h> 56 57#include <err.h> 58#include <fnmatch.h> 59#include <pwd.h> 60#include <stdio.h> 61#include <stdlib.h> 62#include <string.h> 63#include <unistd.h> 64 65char *filename; 66int cflag, pflag; 67 68static void usage __P((void)); 69int decode __P((void)); 70int decode2 __P((int)); 71 72int 73main(argc, argv) 74 int argc; 75 char *argv[]; 76{ 77 int rval, ch; 78 79 while ((ch = getopt(argc, argv, "cp")) != -1) { 80 switch(ch) { 81 case 'c': 82 cflag = 1; /* multiple uudecode'd files */ 83 break; 84 case 'p': 85 pflag = 1; /* print output to stdout */ 86 break; 87 default: 88 usage(); 89 } 90 } 91 argc -= optind; 92 argv += optind; 93 94 95 if (*argv) { 96 rval = 0; 97 do { 98 if (!freopen(filename = *argv, "r", stdin)) { 99 warn("%s", *argv); 100 rval = 1; 101 continue; 102 } 103 rval |= decode(); 104 } while (*++argv); 105 } else { 106 filename = "stdin"; 107 rval = decode(); 108 } 109 exit(rval); 110} 111 112int 113decode () 114{ 115 int flag; 116 117 /* decode only one file per input stream */ 118 if (!cflag) 119 return(decode2(0)); 120 121 /* multiple uudecode'd files */ 122 for (flag = 0; ; flag++) 123 if (decode2(flag)) 124 return(1); 125 else if (feof(stdin)) 126 break; 127 128 return(0); 129} 130 131int 132decode2(flag) 133 int flag; 134{ 135 struct passwd *pw; 136 register int n; 137 register char ch, *p; 138 int mode, n1; 139 char buf[MAXPATHLEN]; 140 char buffn[MAXPATHLEN]; /* file name buffer */ 141 142 143 /* search for header line */ 144 do { 145 if (!fgets(buf, sizeof(buf), stdin)) { 146 if (flag) /* no error */ 147 return(0); 148 149 warnx("%s: no \"begin\" line", filename); 150 return(1); 151 } 152 } while (strncmp(buf, "begin ", 6) || 153 fnmatch("begin [0-7]* *", buf, 0)); 154 155 (void)sscanf(buf, "begin %o %s", &mode, buf); 156 157 /* handle ~user/file format */ 158 if (buf[0] == '~') { 159 if (!(p = index(buf, '/'))) { 160 warnx("%s: illegal ~user", filename); 161 return(1); 162 } 163 *p++ = NULL; 164 if (!(pw = getpwnam(buf + 1))) { 165 warnx("%s: no user %s", filename, buf); 166 return(1); 167 } 168 n = strlen(pw->pw_dir); 169 n1 = strlen(p); 170 if (n + n1 + 2 > MAXPATHLEN) { 171 warnx("%s: path too long", filename); 172 return(1); 173 } 174 bcopy(p, buf + n + 1, n1 + 1); 175 bcopy(pw->pw_dir, buf, n); 176 buf[n] = '/'; 177 } 178 179 /* create output file, set mode */ 180 if (pflag) 181 ; /* print to stdout */ 182 183 else if (!freopen(buf, "w", stdout) || 184 fchmod(fileno(stdout), mode&0666)) { 185 warn("%s: %s", buf, filename); 186 return(1); 187 } 188 strcpy(buffn, buf); /* store file name from header line */ 189 190 /* for each input line */ 191 for (;;) { 192 if (!fgets(p = buf, sizeof(buf), stdin)) { 193 warnx("%s: short file", filename); 194 return(1); 195 } 196#define DEC(c) (((c) - ' ') & 077) /* single character decode */ 197#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) ) 198/* #define IS_DEC(c) (1) */ 199 200#define OUT_OF_RANGE \ 201{ \ 202 warnx( \ 203"\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \ 204 filename, buffn, 1 + ' ', 077 + ' ' + 1); \ 205 return(1); \ 206} 207 208 209 /* 210 * `n' is used to avoid writing out all the characters 211 * at the end of the file. 212 */ 213 if ((n = DEC(*p)) <= 0) 214 break; 215 for (++p; n > 0; p += 4, n -= 3) 216 if (n >= 3) { 217 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) && 218 IS_DEC(*(p + 2)) && IS_DEC(*(p + 3)))) 219 OUT_OF_RANGE 220 221 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 222 putchar(ch); 223 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 224 putchar(ch); 225 ch = DEC(p[2]) << 6 | DEC(p[3]); 226 putchar(ch); 227 228 } 229 else { 230 if (n >= 1) { 231 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)))) 232 OUT_OF_RANGE 233 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 234 putchar(ch); 235 } 236 if (n >= 2) { 237 if (!(IS_DEC(*(p + 1)) && 238 IS_DEC(*(p + 2)))) 239 OUT_OF_RANGE 240 241 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 242 putchar(ch); 243 } 244 if (n >= 3) { 245 if (!(IS_DEC(*(p + 2)) && 246 IS_DEC(*(p + 3)))) 247 OUT_OF_RANGE 248 ch = DEC(p[2]) << 6 | DEC(p[3]); 249 putchar(ch); 250 } 251 } 252 } 253 if (fgets(buf, sizeof(buf), stdin) == NULL || 254 (strcmp(buf, "end") && strcmp(buf, "end\n") && 255 strcmp(buf, "end\r\n"))) { 256 warnx("%s: no \"end\" line", filename); 257 return(1); 258 } 259 return(0); 260} 261 262static void 263usage() 264{ 265 (void)fprintf(stderr, "usage: uudecode [-cp] [file ...]\n"); 266 exit(1); 267} 268