1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1984, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 /* 29 * Portions of this source code were derived from Berkeley 4.3 BSD 30 * under license from the Regents of the University of California. 31 */ 32 33 /* 34 * uuencode [-m] [input] decode_pathname 35 * 36 * Encode a file so it can be mailed to a remote system. 37 */ 38 #include <unistd.h> 39 #include <limits.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <stdio.h> 43 #include <locale.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <errno.h> 47 #include <assert.h> 48 #include <signal.h> 49 50 /* 51 * (Size of TABLE_SIZE octal is large enough to convert a basic 6-bit 52 * data chunk.) 53 */ 54 #define TABLE_SIZE 0x40 55 56 57 static unsigned char base64_table_initializer[] = 58 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 59 "abcdefghijklmnopqrstuvwxyz0123456789+/"; 60 61 static unsigned char encode_table[TABLE_SIZE]; 62 63 /* ENC is the basic 1 character encoding function to make a char printing */ 64 #define ENC(c) encode_table[(c) & 077] 65 66 static void encode(FILE *, FILE *, int); 67 static char *prog; 68 69 int 70 main(int argc, char **argv) 71 { 72 FILE *in; 73 struct stat sbuf; 74 mode_t mode = 0; 75 int c, i; 76 int errflag = 0; 77 int base64flag = 0; 78 char oline[PATH_MAX + 20]; 79 80 prog = argv[0]; 81 (void) signal(SIGPIPE, SIG_DFL); 82 83 /* Set locale environment variables local definitions */ 84 (void) setlocale(LC_ALL, ""); 85 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 86 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 87 #endif 88 (void) textdomain(TEXT_DOMAIN); 89 90 while ((c = getopt(argc, argv, "m")) != EOF) 91 switch (c) { 92 case 'm': 93 base64flag++; 94 break; 95 default: 96 case '?': 97 errflag++; 98 } 99 100 argc -= optind; 101 argv = &argv[optind]; 102 103 /* optional 1st argument */ 104 if (argc > 1) { 105 if ((in = fopen(*argv, "r")) == NULL) { 106 perror(*argv); 107 exit(1); 108 } 109 argv++; argc--; 110 } else { 111 in = stdin; 112 mode = 0777; 113 } 114 115 if ((argc != 1) || errflag) { 116 (void) fprintf(stderr, 117 gettext("Usage: %s [-m] [infile] remotefile\n"), prog); 118 exit(2); 119 } 120 121 /* figure out the input file mode */ 122 errno = 0; 123 if (fstat(fileno(in), &sbuf) < 0 || !S_ISREG(sbuf.st_mode)) { 124 mode = 0666 & ~umask(0666); 125 } else { 126 mode = sbuf.st_mode & 0777; 127 } 128 129 /* 130 * encoding varies depending on whether we are 131 * using base64 encoding or the historical algorithm 132 */ 133 if (base64flag) { 134 (void) memcpy(encode_table, base64_table_initializer, 135 sizeof (encode_table)); 136 } else { 137 for (i = 0; i < TABLE_SIZE; i++) 138 encode_table[i] = (unsigned char)i + 0x20; 139 } 140 141 /* 142 * here's the meat of the whole thing 143 */ 144 if (base64flag) 145 (void) snprintf(oline, sizeof (oline), "begin-base64 %lo %s\n", 146 (long)mode, *argv); 147 else 148 (void) snprintf(oline, sizeof (oline), "begin %lo %s\n", 149 (long)mode, *argv); 150 151 if (printf("%s", oline) < 0) { 152 perror(prog); 153 exit(6); 154 } 155 156 encode(in, stdout, base64flag); 157 158 if (base64flag) 159 (void) snprintf(oline, sizeof (oline), "====\n"); 160 else 161 (void) snprintf(oline, sizeof (oline), "end\n"); 162 163 if (printf("%s", oline) < 0) { 164 perror(prog); 165 exit(6); 166 } 167 168 if (ferror(stdout) != 0 || fclose(stdout) != 0) { 169 perror(prog); 170 exit(6); 171 } 172 173 return (0); 174 } 175 176 /* 177 * copy from in to out, encoding as you go along. 178 */ 179 static void 180 encode(FILE *in, FILE *out, int base64) 181 { 182 unsigned char in_buf[80]; 183 unsigned char out_buf[112]; 184 unsigned char *iptr, *optr; 185 int i; 186 size_t n, opos; 187 188 if (! base64) { 189 /* historical algorithm */ 190 191 for (;;) { 192 iptr = in_buf; 193 optr = out_buf; 194 195 /* 1 (up to) 45 character line */ 196 n = fread(iptr, 1, 45, in); 197 198 *(optr++) = ENC(n); 199 200 for (i = 0; i < n; i += 3) { 201 *(optr++) = ENC(*iptr >> 2); 202 *(optr++) = ENC((*iptr << 4) & 060 | 203 (*(iptr + 1) >> 4) & 017); 204 *(optr++) = ENC((*(iptr + 1) << 2) & 074 | 205 (*(iptr + 2) >> 6) & 03); 206 *(optr++) = ENC(*(iptr + 2) & 077); 207 iptr += 3; 208 } 209 210 *(optr++) = '\n'; 211 212 /*LINTED*/ 213 (void) fwrite(out_buf, 1, (size_t)(optr - out_buf), 214 out); 215 216 if (ferror(out)) { 217 perror(prog); 218 exit(6); 219 } 220 221 if (n == 0) 222 break; 223 } 224 } else { 225 /* base64 algorithm */ 226 227 optr = out_buf; 228 /* 229 * read must be a multiple of 3 bytes for 230 * this algorithm to work, and also must 231 * be small enough that read_size * (4/3) 232 * will always be 76 bytes or less, since 233 * base64 lines can be no longer than that 234 */ 235 while ((n = fread(in_buf, 1, 51, in)) > 0) { 236 opos = 0; 237 iptr = in_buf; 238 for (i = 0; i < n / 3; i++) { 239 *(optr++) = ENC(*iptr >> 2); 240 *(optr++) = ENC((*iptr << 4) & 060 | 241 (*(iptr + 1) >> 4) & 017); 242 *(optr++) = ENC((*(iptr + 1) << 2) 243 & 074 | (*(iptr + 2) >> 6) & 03); 244 *(optr++) = ENC(*(iptr + 2) & 077); 245 iptr += 3; 246 opos += 3; 247 248 /* need output padding ? */ 249 if (n - opos < 3) 250 break; 251 252 (void) fwrite(out_buf, 1, 253 /*LINTED*/ 254 (size_t)(optr - out_buf), out); 255 256 if (ferror(out)) { 257 perror(prog); 258 exit(6); 259 } 260 261 optr = out_buf; 262 } 263 /* 264 * Take care of any output padding that is 265 * necessary. 266 */ 267 assert(n - opos < 3); 268 switch (n - opos) { 269 case 0: 270 /* no-op - 24 bits of data encoded */ 271 *(optr++) = '\n'; 272 break; 273 case 1: 274 /* 8 bits encoded - pad with 2 '=' */ 275 *(optr++) = ENC((*iptr & 0xFC) >> 2); 276 *(optr++) = ENC((*iptr & 0x03) << 4); 277 *(optr++) = '='; 278 *(optr++) = '='; 279 *(optr++) = '\n'; 280 break; 281 case 2: 282 /* 16 bits encoded - pad with 1 '=' */ 283 *(optr++) = ENC((*iptr & 0xFC) >> 2); 284 *(optr++) = ENC(((*iptr & 0x03) << 4) | 285 ((*(iptr + 1) & 0xF0) >> 4)); 286 *(optr++) = ENC((*(iptr + 1) & 0x0F) 287 << 2); 288 *(optr++) = '='; 289 *(optr++) = '\n'; 290 break; 291 default: 292 /* impossible */ 293 break; 294 } 295 (void) fwrite(out_buf, 1, 296 /*LINTED*/ 297 (size_t)(optr - out_buf), out); 298 299 if (ferror(out)) { 300 perror(prog); 301 exit(6); 302 } 303 304 optr = out_buf; 305 } 306 } 307 } 308