summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore1
-rw-r--r--Changelog8
-rw-r--r--LICENSE24
-rw-r--r--Makefile38
-rw-r--r--README27
-rw-r--r--applets/busybox.c230
-rwxr-xr-xapplets/busybox.mkll17
-rw-r--r--archival/gzip.c3231
-rw-r--r--archival/tar.c1425
-rw-r--r--block_device.c64
-rw-r--r--busybox.c230
-rw-r--r--busybox.def.h64
-rwxr-xr-xbusybox.mkll17
-rw-r--r--busybox.spec43
-rw-r--r--busybox_functions.h11
-rw-r--r--cat.c54
-rw-r--r--chgrp.c89
-rw-r--r--chmod.c163
-rw-r--r--chown.c63
-rw-r--r--chroot.c32
-rw-r--r--clear.c13
-rw-r--r--console-tools/clear.c13
-rw-r--r--console-tools/loadkmap.c68
-rw-r--r--coreutils/cat.c54
-rw-r--r--coreutils/chgrp.c89
-rw-r--r--coreutils/chmod.c163
-rw-r--r--coreutils/chown.c63
-rw-r--r--coreutils/chroot.c32
-rw-r--r--coreutils/cp.c89
-rw-r--r--coreutils/date.c305
-rw-r--r--coreutils/dd.c307
-rw-r--r--coreutils/df.c103
-rw-r--r--coreutils/length.c13
-rw-r--r--coreutils/ln.c52
-rw-r--r--coreutils/ls.c542
-rw-r--r--coreutils/mkdir.c58
-rw-r--r--coreutils/mknod.c52
-rw-r--r--coreutils/mv.c38
-rw-r--r--coreutils/printf.c531
-rw-r--r--coreutils/pwd.c18
-rw-r--r--coreutils/rm.c30
-rw-r--r--coreutils/rmdir.c17
-rw-r--r--coreutils/sleep.c15
-rw-r--r--coreutils/sync.c11
-rw-r--r--coreutils/touch.c20
-rw-r--r--cp.c89
-rw-r--r--date.c305
-rw-r--r--dd.c307
-rw-r--r--descend.c124
-rw-r--r--df.c103
-rw-r--r--dmesg.c95
-rw-r--r--dutmp.c47
-rw-r--r--dyadic.c28
-rw-r--r--examples/busybox.spec43
-rw-r--r--fdflush.c36
-rw-r--r--find.c23
-rw-r--r--findmount.c46
-rw-r--r--findutils/find.c23
-rw-r--r--findutils/grep.c210
-rw-r--r--grep.c210
-rw-r--r--gzip.c3231
-rw-r--r--halt.c12
-rw-r--r--init.c438
-rw-r--r--init/halt.c12
-rw-r--r--init/init.c438
-rw-r--r--init/reboot.c12
-rw-r--r--internal.h189
-rw-r--r--kill.c140
-rw-r--r--length.c13
-rw-r--r--ln.c52
-rw-r--r--loadkmap.c68
-rw-r--r--losetup.c190
-rw-r--r--ls.c542
-rw-r--r--makedevs.c95
-rw-r--r--math.c149
-rw-r--r--miscutils/dutmp.c47
-rw-r--r--miscutils/makedevs.c95
-rw-r--r--miscutils/mt.c98
-rw-r--r--miscutils/update.c48
-rw-r--r--mkdir.c58
-rw-r--r--mknod.c52
-rw-r--r--mkswap.c253
-rw-r--r--mnc.c148
-rw-r--r--monadic.c126
-rw-r--r--more.c110
-rw-r--r--mount.c430
-rw-r--r--mt.c98
-rw-r--r--mv.c38
-rw-r--r--postprocess.c41
-rw-r--r--printf.c531
-rw-r--r--procps/kill.c140
-rw-r--r--pwd.c18
-rw-r--r--reboot.c12
-rw-r--r--rm.c30
-rw-r--r--rmdir.c17
-rw-r--r--sleep.c15
-rw-r--r--smtpout2
-rw-r--r--swapoff.c52
-rw-r--r--swapon.c34
-rw-r--r--sync.c11
-rw-r--r--tar.c1425
-rw-r--r--touch.c20
-rw-r--r--umount.c135
-rw-r--r--update.c48
-rw-r--r--util-linux/dmesg.c95
-rw-r--r--util-linux/fdflush.c36
-rw-r--r--util-linux/mkswap.c253
-rw-r--r--util-linux/more.c110
-rw-r--r--util-linux/mount.c430
-rw-r--r--util-linux/umount.c135
-rw-r--r--utility.c1181
-rw-r--r--utility.h73
-rw-r--r--zcat.c2262
113 files changed, 24504 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 000000000..a1a4c366c
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1 @@
busybox
diff --git a/Changelog b/Changelog
new file mode 100644
index 000000000..e00f7281e
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,8 @@
10.27
2 Mount now supports -a, and -t auto.
3 Mount now updates mtab correctly for 'ro'.
4 More checks screen rows size, outputs bytes percentage.
5 Printf added as module.
60.26
7 Touch now creates files. -c option for no create.
8 \ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..cf73b2c33
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
1Original release code (unless otherwise noted)
2Copyright 1995, 1996 Bruce Perens <bruce@pixar.com>
3
4mkswap
5Copyright 1991 Linus Torvalds
6
7tiny-ls(ls)
8Copyright 1996 Brian Candler <B.Candler@pobox.com>
9
10tarcat, loadkmap, various fixes, Debian maintenance
11Copyright 1998 Enrique Zanardi <ezanardi@ull.es>
12
13more(v2), makedevs, dutmp, modularization, auto links file,
14various fixes, Linux Router Project maintenance
15Copyright 1998 Dave Cinege <dcinege@psychosis.com>
16
17mini-gzip(gzip), mini-netcat(mnc)
18Copyright 1998 Charles P. Wright <cpwright@villagenet.com>
19
20
21Please see the top of the source files for more precise indivigual
22copyright and license info.
23
24This program suite may be distributed under the GNU General Public License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..bef25a3ae
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
1
2VERSION=0.29alpha1
3BUILDTIME=$(shell date "+%Y%m%d-%H%M")
4
5#This will choke on a non-debian system
6ARCH=`uname -m | sed -e 's/i.86/i386/' | sed -e 's/sparc.*/sparc/'`
7
8
9STRIP= strip --remove-section=.note --remove-section=.comment busybox
10LDFLAGS= -s
11
12# -D_GNU_SOURCE is needed because environ is used in init.c
13CFLAGS=-Wall -O2 -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE
14# For debugging only
15#CFLAGS=-Wall -g -D_GNU_SOURCE
16LIBRARIES=-lc
17OBJECTS=$(shell ./busybox.obj) utility.o
18
19CFLAGS+= -DBB_VER='"$(VERSION)"'
20CFLAGS+= -DBB_BT='"$(BUILDTIME)"'
21
22#all: busybox links
23all: busybox
24
25busybox: $(OBJECTS)
26 $(CC) $(CFLAGS) $(LDFLAGS) -o busybox $(OBJECTS) $(LIBRARIES)
27 #$(STRIP)
28
29links:
30 - ./busybox.mkll | sort >busybox.links
31
32clean:
33 - rm -f busybox busybox.links *~ *.o
34
35distclean: clean
36 - rm -f busybox
37
38force:
diff --git a/README b/README
new file mode 100644
index 000000000..7d4e0f304
--- /dev/null
+++ b/README
@@ -0,0 +1,27 @@
1Please see the LICENSE file for copyright information.
2
3Busybox is a multicall binary used to provide a minimal subset of
4POSIX style commands and specialized functions.
5
6It is geared toward 'mini-systems' like boot floppies. Specifically
7it is used in the Debian Rescue/Install system (which caused the
8original busybox to be made), the Linux Router Project, and others.
9
10As of version 0.20 there is a version number. : )
11Also as of version 0.20, BB is modularized to allow an easy build of
12only the BB parts you need, to reduce binary size.
13
14Edit the file busybox.def.h and comment out the parts you do not need
15using C++ comments (//)
16
17After the build is complete a busybox.links file is generated to allow
18you to easily make the sym/hard links to the busybox binary.
19
20Note the modular system is Makefile based, and purposly very
21simplistic. It does no dependency checking. That is left for you
22to figure out by trial and error.
23
24Please feed patches back to:
25 Dave Cinege <dcinege@psychosis.com>
26and:
27 Enrique Zanardi <ezanardi@ull.es>
diff --git a/applets/busybox.c b/applets/busybox.c
new file mode 100644
index 000000000..b7b2b6009
--- /dev/null
+++ b/applets/busybox.c
@@ -0,0 +1,230 @@
1#include "internal.h"
2#include <stdio.h>
3#include <string.h>
4#include <errno.h>
5
6static int been_there_done_that = 0;
7
8static const struct Applet applets[] = {
9
10#ifdef BB_BUSYBOX //bin
11 {"busybox", busybox_main},
12#endif
13#ifdef BB_BLOCK_DEVICE //sbin
14 {"block_device", block_device_main},
15#endif
16#ifdef BB_CAT //bin
17 {"cat", cat_more_main},
18#endif
19#ifdef BB_CHGRP //bin
20 {"chgrp", chgrp_main},
21#endif
22#ifdef BB_CHMOD //bin
23 {"chmod", chmod_main},
24#endif
25#ifdef BB_CHOWN //bin
26 {"chown", chown_main},
27#endif
28#ifdef BB_CHROOT //sbin
29 {"chroot", chroot_main},
30#endif
31#ifdef BB_CLEAR //usr/bin
32 {"clear", clear_main},
33#endif
34#ifdef BB_CP //bin
35 {"cp", dyadic_main},
36#endif
37#ifdef BB_DATE //bin
38 {"date", date_main},
39#endif
40#ifdef BB_DD //bin
41 {"dd", dd_main},
42#endif
43#ifdef BB_DF //bin
44 {"df", df_main},
45#endif
46#ifdef BB_DMESG //bin
47 {"dmesg", dmesg_main},
48#endif
49#ifdef BB_DUTMP //usr/sbin
50 {"dutmp", cat_more_main},
51#endif
52#ifdef BB_FALSE //bin
53 {"false", false_main},
54#endif
55#ifdef BB_FDFLUSH //bin
56 {"fdflush", monadic_main},
57#endif
58#ifdef BB_FIND //usr/bin
59 {"find", find_main},
60#endif
61#ifdef BB_GREP //bin
62 {"grep", grep_main},
63#endif
64#ifdef BB_HALT //sbin
65 {"halt", halt_main},
66#endif
67#ifdef BB_INIT //sbin
68 {"init", init_main},
69#endif
70#ifdef BB_KILL //bin
71 {"kill", kill_main},
72#endif
73#ifdef BB_LENGTH //usr/bin
74 {"length", length_main},
75#endif
76#ifdef BB_LN //bin
77 {"ln", dyadic_main},
78#endif
79#ifdef BB_LOADKMAP //sbin
80 {"loadkmap", loadkmap_main},
81#endif
82#ifdef BB_LOSETUP //sbin
83 {"losetup", losetup_main},
84#endif
85#ifdef BB_LS //bin
86 {"ls", ls_main},
87#endif
88#ifdef BB_MAKEDEVS //sbin
89 {"makedevs", makedevs_main},
90#endif
91#ifdef BB_MATH //usr/bin
92 {"math", math_main},
93#endif
94#ifdef BB_MKDIR //bin
95 {"mkdir", monadic_main},
96#endif
97#ifdef BB_MKNOD //bin
98 {"mknod", mknod_main},
99#endif
100#ifdef BB_MKSWAP //sbin
101 {"mkswap", mkswap_main},
102#endif
103#ifdef BB_MNC //usr/bin
104 {"mnc", mnc_main},
105#endif
106#ifdef BB_MORE //bin
107 {"more", cat_more_main},
108#endif
109#ifdef BB_MOUNT //bin
110 {"mount", mount_main},
111#endif
112#ifdef BB_MT //bin
113 {"mt", mt_main},
114#endif
115#ifdef BB_MV //bin
116 {"mv", dyadic_main},
117#endif
118#ifdef BB_PRINTF //usr/bin
119 {"printf", printf_main},
120#endif
121#ifdef BB_PWD //bin
122 {"pwd", pwd_main},
123#endif
124#ifdef BB_REBOOT //sbin
125 {"reboot", reboot_main},
126#endif
127#ifdef BB_RM //bin
128 {"rm", rm_main},
129#endif
130#ifdef BB_RMDIR //bin
131 {"rmdir", monadic_main},
132#endif
133#ifdef BB_SLEEP //bin
134 {"sleep", sleep_main},
135#endif
136#ifdef BB_TAR //bin
137 {"tar", tar_main},
138#endif
139#ifdef BB_SWAPOFF //sbin
140 {"swapoff", monadic_main},
141#endif
142#ifdef BB_SWAPON //sbin
143 {"swapon", monadic_main},
144#endif
145#ifdef BB_SYNC //bin
146 {"sync", sync_main},
147#endif
148#ifdef BB_TOUCH //usr/bin
149 {"touch", monadic_main},
150#endif
151#ifdef BB_TRUE //bin
152 {"true", true_main},
153#endif
154#ifdef BB_UMOUNT //bin
155 {"umount", umount_main},
156#endif
157#ifdef BB_UPDATE //sbin
158 {"update", update_main},
159#endif
160#ifdef BB_ZCAT //bin
161 {"zcat", zcat_main},
162 {"gunzip", zcat_main},
163#endif
164#ifdef BB_GZIP //bin
165 {"gzip", gzip_main},
166#endif
167 {0}
168};
169
170int main(int argc, char **argv)
171{
172 char *s = argv[0];
173 char *name = argv[0];
174 const struct Applet *a = applets;
175
176 while (*s != '\0') {
177 if (*s++ == '/')
178 name = s;
179 }
180
181 while (a->name != 0) {
182 if (strcmp(name, a->name) == 0) {
183 int status;
184
185 status = ((*(a->main)) (argc, argv));
186 if (status < 0) {
187 fprintf(stderr, "%s: %s\n", a->name, strerror(errno));
188 }
189 fprintf(stderr, "\n");
190 exit(status);
191 }
192 a++;
193 }
194 return (busybox_main(argc, argv));
195}
196
197
198int busybox_main(int argc, char **argv)
199{
200 argc--;
201 argv++;
202
203 /* If we've already been here once, exit now */
204 if (been_there_done_that == 1)
205 return -1;
206 been_there_done_that = 1;
207
208 if (argc < 1) {
209 const struct Applet *a = applets;
210 fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n",
211 BB_VER, BB_BT);
212 fprintf(stderr, "Usage: busybox [function] [arguments]...\n");
213 fprintf(stderr,
214 "\n\tMost people will create a symlink to busybox for each\n"
215 "\tfunction name, and busybox will act like whatever you invoke it as.\n");
216 fprintf(stderr, "\nCurrently defined functions:\n");
217
218 if (a->name != 0) {
219 fprintf(stderr, "%s", a->name);
220 a++;
221 }
222 while (a->name != 0) {
223 fprintf(stderr, ", %s", a->name);
224 a++;
225 }
226 fprintf(stderr, "\n\n");
227 exit(-1);
228 } else
229 return (main(argc, argv));
230}
diff --git a/applets/busybox.mkll b/applets/busybox.mkll
new file mode 100755
index 000000000..e43a1ccb0
--- /dev/null
+++ b/applets/busybox.mkll
@@ -0,0 +1,17 @@
1#!/bin/sh
2#Make busybox links list file
3
4DF="busybox.def.h"
5MF="main.c"
6
7LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)"
8
9 for def in ${LIST}; do
10
11 set -- $(sed -n '/^#ifdef '$def'[ +| +].*/,/^#endif/{s/.*\/\///p; /^{ /{ s/^{ "//; s/",.*$//p;}; }' $MF)
12 path=$1; shift
13
14 for n in $@; do
15 echo "$path/$n"
16 done
17 done
diff --git a/archival/gzip.c b/archival/gzip.c
new file mode 100644
index 000000000..6fd2e3971
--- /dev/null
+++ b/archival/gzip.c
@@ -0,0 +1,3231 @@
1/* gzip.c -- this is a stripped down version of gzip I put into busybox, it does
2 * only standard in to standard out with -9 compression. It also requires the
3 * zcat module for some important functions.
4 *
5 * Charles P. Wright <cpw@unix.asb.com>
6 */
7#include "internal.h"
8#ifdef BB_GZIP
9
10#ifndef BB_ZCAT
11error: you need zcat to have gzip support!
12#endif
13
14const char gzip_usage[] = "gzip\nignores all command line arguments\ncompress stdin to stdout with -9 compression\n";
15
16/* gzip.h -- common declarations for all gzip modules
17 * Copyright (C) 1992-1993 Jean-loup Gailly.
18 * This is free software; you can redistribute it and/or modify it under the
19 * terms of the GNU General Public License, see the file COPYING.
20 */
21
22#if defined(__STDC__) || defined(PROTO)
23# define OF(args) args
24#else
25# define OF(args) ()
26#endif
27
28#ifdef __STDC__
29 typedef void *voidp;
30#else
31 typedef char *voidp;
32#endif
33
34/* I don't like nested includes, but the string and io functions are used
35 * too often
36 */
37#include <stdio.h>
38#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
39# include <string.h>
40# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
41# include <memory.h>
42# endif
43# define memzero(s, n) memset ((voidp)(s), 0, (n))
44#else
45# include <strings.h>
46# define strchr index
47# define strrchr rindex
48# define memcpy(d, s, n) bcopy((s), (d), (n))
49# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
50# define memzero(s, n) bzero((s), (n))
51#endif
52
53#ifndef RETSIGTYPE
54# define RETSIGTYPE void
55#endif
56
57#define local static
58
59typedef unsigned char uch;
60typedef unsigned short ush;
61typedef unsigned long ulg;
62
63/* Return codes from gzip */
64#define OK 0
65#define ERROR 1
66#define WARNING 2
67
68/* Compression methods (see algorithm.doc) */
69#define STORED 0
70#define COMPRESSED 1
71#define PACKED 2
72#define LZHED 3
73/* methods 4 to 7 reserved */
74#define DEFLATED 8
75#define MAX_METHODS 9
76extern int method; /* compression method */
77
78/* To save memory for 16 bit systems, some arrays are overlaid between
79 * the various modules:
80 * deflate: prev+head window d_buf l_buf outbuf
81 * unlzw: tab_prefix tab_suffix stack inbuf outbuf
82 * inflate: window inbuf
83 * unpack: window inbuf prefix_len
84 * unlzh: left+right window c_table inbuf c_len
85 * For compression, input is done in window[]. For decompression, output
86 * is done in window except for unlzw.
87 */
88
89#ifndef INBUFSIZ
90# ifdef SMALL_MEM
91# define INBUFSIZ 0x2000 /* input buffer size */
92# else
93# define INBUFSIZ 0x8000 /* input buffer size */
94# endif
95#endif
96#define INBUF_EXTRA 64 /* required by unlzw() */
97
98#ifndef OUTBUFSIZ
99# ifdef SMALL_MEM
100# define OUTBUFSIZ 8192 /* output buffer size */
101# else
102# define OUTBUFSIZ 16384 /* output buffer size */
103# endif
104#endif
105#define OUTBUF_EXTRA 2048 /* required by unlzw() */
106
107#ifndef DIST_BUFSIZE
108# ifdef SMALL_MEM
109# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
110# else
111# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
112# endif
113#endif
114
115#ifdef DYN_ALLOC
116# define EXTERN(type, array) extern type * near array
117# define DECLARE(type, array, size) type * near array
118# define ALLOC(type, array, size) { \
119 array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
120 if (array == NULL) error("insufficient memory"); \
121 }
122# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
123#else
124# define EXTERN(type, array) extern type array[]
125# define DECLARE(type, array, size) type array[size]
126# define ALLOC(type, array, size)
127# define FREE(array)
128#endif
129
130EXTERN(uch, inbuf); /* input buffer */
131EXTERN(uch, outbuf); /* output buffer */
132EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
133EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
134#define tab_suffix window
135#ifndef MAXSEG_64K
136# define tab_prefix prev /* hash link (see deflate.c) */
137# define head (prev+WSIZE) /* hash head (see deflate.c) */
138 EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
139#else
140# define tab_prefix0 prev
141# define head tab_prefix1
142 EXTERN(ush, tab_prefix0); /* prefix for even codes */
143 EXTERN(ush, tab_prefix1); /* prefix for odd codes */
144#endif
145
146extern unsigned insize; /* valid bytes in inbuf */
147extern unsigned inptr; /* index of next byte to be processed in inbuf */
148extern unsigned outcnt; /* bytes in output buffer */
149
150extern long bytes_in; /* number of input bytes */
151extern long bytes_out; /* number of output bytes */
152extern long header_bytes;/* number of bytes in gzip header */
153
154#define isize bytes_in
155/* for compatibility with old zip sources (to be cleaned) */
156
157extern int ifd; /* input file descriptor */
158extern int ofd; /* output file descriptor */
159extern char ifname[]; /* input file name or "stdin" */
160extern char ofname[]; /* output file name or "stdout" */
161extern char *progname; /* program name */
162
163extern long time_stamp; /* original time stamp (modification time) */
164extern long ifile_size; /* input file size, -1 for devices (debug only) */
165
166typedef int file_t; /* Do not use stdio */
167#define NO_FILE (-1) /* in memory compression */
168
169
170#define PACK_MAGIC "\037\036" /* Magic header for packed files */
171#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
172#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
173#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/
174#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
175
176/* gzip flag byte */
177#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
178#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
179#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
180#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
181#define COMMENT 0x10 /* bit 4 set: file comment present */
182#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
183#define RESERVED 0xC0 /* bit 6,7: reserved */
184
185/* internal file attribute */
186#define UNKNOWN 0xffff
187#define BINARY 0
188#define ASCII 1
189
190#ifndef WSIZE
191# define WSIZE 0x8000 /* window size--must be a power of two, and */
192#endif /* at least 32K for zip's deflate method */
193
194#define MIN_MATCH 3
195#define MAX_MATCH 258
196/* The minimum and maximum match lengths */
197
198#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
199/* Minimum amount of lookahead, except at the end of the input file.
200 * See deflate.c for comments about the MIN_MATCH+1.
201 */
202
203#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
204/* In order to simplify the code, particularly on 16 bit machines, match
205 * distances are limited to MAX_DIST instead of WSIZE.
206 */
207
208extern int decrypt; /* flag to turn on decryption */
209extern int exit_code; /* program exit code */
210extern int verbose; /* be verbose (-v) */
211extern int quiet; /* be quiet (-q) */
212extern int test; /* check .z file integrity */
213extern int to_stdout; /* output to stdout (-c) */
214extern int save_orig_name; /* set if original name must be saved */
215
216#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
217#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
218
219/* put_byte is used for the compressed output, put_ubyte for the
220 * uncompressed output. However unlzw() uses window for its
221 * suffix table instead of its output buffer, so it does not use put_ubyte
222 * (to be cleaned up).
223 */
224#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
225 flush_outbuf();}
226#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
227 flush_window();}
228
229/* Output a 16 bit value, lsb first */
230#define put_short(w) \
231{ if (outcnt < OUTBUFSIZ-2) { \
232 outbuf[outcnt++] = (uch) ((w) & 0xff); \
233 outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
234 } else { \
235 put_byte((uch)((w) & 0xff)); \
236 put_byte((uch)((ush)(w) >> 8)); \
237 } \
238}
239
240/* Output a 32 bit value to the bit stream, lsb first */
241#define put_long(n) { \
242 put_short((n) & 0xffff); \
243 put_short(((ulg)(n)) >> 16); \
244}
245
246#define seekable() 0 /* force sequential output */
247#define translate_eol 0 /* no option -a yet */
248
249#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
250
251/* Macros for getting two-byte and four-byte header values */
252#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
253#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
254
255/* Diagnostic functions */
256#ifdef DEBUG
257# define Assert(cond,msg) {if(!(cond)) error(msg);}
258# define Trace(x) fprintf x
259# define Tracev(x) {if (verbose) fprintf x ;}
260# define Tracevv(x) {if (verbose>1) fprintf x ;}
261# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
262# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
263#else
264# define Assert(cond,msg)
265# define Trace(x)
266# define Tracev(x)
267# define Tracevv(x)
268# define Tracec(c,x)
269# define Tracecv(c,x)
270#endif
271
272#define WARN(msg) {if (!quiet) fprintf msg ; \
273 if (exit_code == OK) exit_code = WARNING;}
274
275local void do_exit(int exitcode);
276
277 /* in zip.c: */
278extern int zip OF((int in, int out));
279extern int file_read OF((char *buf, unsigned size));
280
281 /* in unzip.c */
282extern int unzip OF((int in, int out));
283extern int check_zipfile OF((int in));
284
285 /* in unpack.c */
286extern int unpack OF((int in, int out));
287
288 /* in unlzh.c */
289extern int unlzh OF((int in, int out));
290
291 /* in gzip.c */
292RETSIGTYPE abort_gzip OF((void));
293
294 /* in deflate.c */
295void lm_init OF((ush *flags));
296ulg deflate OF((void));
297
298 /* in trees.c */
299void ct_init OF((ush *attr, int *method));
300int ct_tally OF((int dist, int lc));
301ulg flush_block OF((char *buf, ulg stored_len, int eof));
302
303 /* in bits.c */
304void bi_init OF((file_t zipfile));
305void send_bits OF((int value, int length));
306unsigned bi_reverse OF((unsigned value, int length));
307void bi_windup OF((void));
308void copy_block OF((char *buf, unsigned len, int header));
309extern int (*read_buf) OF((char *buf, unsigned size));
310
311 /* in util.c: */
312extern int copy OF((int in, int out));
313extern ulg updcrc OF((uch *s, unsigned n));
314extern void clear_bufs OF((void));
315extern int fill_inbuf OF((int eof_ok));
316extern void flush_outbuf OF((void));
317extern void flush_window OF((void));
318extern void write_buf OF((int fd, voidp buf, unsigned cnt));
319extern char *strlwr OF((char *s));
320extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
321extern void error OF((char *m));
322extern void warn OF((char *a, char *b));
323extern void read_error OF((void));
324extern void write_error OF((void));
325extern void display_ratio OF((long num, long den, FILE *file));
326extern voidp xmalloc OF((unsigned int size));
327
328 /* in inflate.c */
329extern int inflate OF((void));
330/* lzw.h -- define the lzw functions.
331 * Copyright (C) 1992-1993 Jean-loup Gailly.
332 * This is free software; you can redistribute it and/or modify it under the
333 * terms of the GNU General Public License, see the file COPYING.
334 */
335
336#if !defined(OF) && defined(lint)
337# include "gzip.h"
338#endif
339
340#ifndef BITS
341# define BITS 16
342#endif
343#define INIT_BITS 9 /* Initial number of bits per code */
344
345#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
346/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
347 * It's a pity that old uncompress does not check bit 0x20. That makes
348 * extension of the format actually undesirable because old compress
349 * would just crash on the new format instead of giving a meaningful
350 * error message. It does check the number of bits, but it's more
351 * helpful to say "unsupported format, get a new version" than
352 * "can only handle 16 bits".
353 */
354
355#define BLOCK_MODE 0x80
356/* Block compression: if table is full and compression rate is dropping,
357 * clear the dictionary.
358 */
359
360#define LZW_RESERVED 0x60 /* reserved bits */
361
362#define CLEAR 256 /* flush the dictionary */
363#define FIRST (CLEAR+1) /* first free entry */
364
365extern int maxbits; /* max bits per code for LZW */
366extern int block_mode; /* block compress mode -C compatible with 2.0 */
367
368/* revision.h -- define the version number
369 * Copyright (C) 1992-1993 Jean-loup Gailly.
370 * This is free software; you can redistribute it and/or modify it under the
371 * terms of the GNU General Public License, see the file COPYING.
372 */
373
374#define VERSION "1.2.4"
375#define PATCHLEVEL 0
376#define REVDATE "18 Aug 93"
377
378/* This version does not support compression into old compress format: */
379#ifdef LZW
380# undef LZW
381#endif
382
383/* $Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $ */
384/* tailor.h -- target dependent definitions
385 * Copyright (C) 1992-1993 Jean-loup Gailly.
386 * This is free software; you can redistribute it and/or modify it under the
387 * terms of the GNU General Public License, see the file COPYING.
388 */
389
390/* The target dependent definitions should be defined here only.
391 * The target dependent functions should be defined in tailor.c.
392 */
393
394/* $Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $ */
395
396#if defined(__MSDOS__) && !defined(MSDOS)
397# define MSDOS
398#endif
399
400#if defined(__OS2__) && !defined(OS2)
401# define OS2
402#endif
403
404#if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */
405# undef MSDOS
406#endif
407
408#ifdef MSDOS
409# ifdef __GNUC__
410 /* DJGPP version 1.09+ on MS-DOS.
411 * The DJGPP 1.09 stat() function must be upgraded before gzip will
412 * fully work.
413 * No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
414 * implies DIRENT.
415 */
416# define near
417# else
418# define MAXSEG_64K
419# ifdef __TURBOC__
420# define NO_OFF_T
421# ifdef __BORLANDC__
422# define DIRENT
423# else
424# define NO_UTIME
425# endif
426# else /* MSC */
427# define HAVE_SYS_UTIME_H
428# define NO_UTIME_H
429# endif
430# endif
431# define PATH_SEP2 '\\'
432# define PATH_SEP3 ':'
433# define MAX_PATH_LEN 128
434# define NO_MULTIPLE_DOTS
435# define MAX_EXT_CHARS 3
436# define Z_SUFFIX "z"
437# define NO_CHOWN
438# define PROTO
439# define STDC_HEADERS
440# define NO_SIZE_CHECK
441# define casemap(c) tolow(c) /* Force file names to lower case */
442# include <io.h>
443# define OS_CODE 0x00
444# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
445# if !defined(NO_ASM) && !defined(ASMV)
446# define ASMV
447# endif
448#else
449# define near
450#endif
451
452#ifdef OS2
453# define PATH_SEP2 '\\'
454# define PATH_SEP3 ':'
455# define MAX_PATH_LEN 260
456# ifdef OS2FAT
457# define NO_MULTIPLE_DOTS
458# define MAX_EXT_CHARS 3
459# define Z_SUFFIX "z"
460# define casemap(c) tolow(c)
461# endif
462# define NO_CHOWN
463# define PROTO
464# define STDC_HEADERS
465# include <io.h>
466# define OS_CODE 0x06
467# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
468# ifdef _MSC_VER
469# define HAVE_SYS_UTIME_H
470# define NO_UTIME_H
471# define MAXSEG_64K
472# undef near
473# define near _near
474# endif
475# ifdef __EMX__
476# define HAVE_SYS_UTIME_H
477# define NO_UTIME_H
478# define DIRENT
479# define EXPAND(argc,argv) \
480 {_response(&argc, &argv); _wildcard(&argc, &argv);}
481# endif
482# ifdef __BORLANDC__
483# define DIRENT
484# endif
485# ifdef __ZTC__
486# define NO_DIR
487# define NO_UTIME_H
488# include <dos.h>
489# define EXPAND(argc,argv) \
490 {response_expand(&argc, &argv);}
491# endif
492#endif
493
494#ifdef WIN32 /* Windows NT */
495# define HAVE_SYS_UTIME_H
496# define NO_UTIME_H
497# define PATH_SEP2 '\\'
498# define PATH_SEP3 ':'
499# define MAX_PATH_LEN 260
500# define NO_CHOWN
501# define PROTO
502# define STDC_HEADERS
503# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
504# include <io.h>
505# include <malloc.h>
506# ifdef NTFAT
507# define NO_MULTIPLE_DOTS
508# define MAX_EXT_CHARS 3
509# define Z_SUFFIX "z"
510# define casemap(c) tolow(c) /* Force file names to lower case */
511# endif
512# define OS_CODE 0x0b
513#endif
514
515#ifdef MSDOS
516# ifdef __TURBOC__
517# include <alloc.h>
518# define DYN_ALLOC
519 /* Turbo C 2.0 does not accept static allocations of large arrays */
520 void * fcalloc (unsigned items, unsigned size);
521 void fcfree (void *ptr);
522# else /* MSC */
523# include <malloc.h>
524# define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
525# define fcfree(ptr) hfree(ptr)
526# endif
527#else
528# ifdef MAXSEG_64K
529# define fcalloc(items,size) calloc((items),(size))
530# else
531# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
532# endif
533# define fcfree(ptr) free(ptr)
534#endif
535
536#if defined(VAXC) || defined(VMS)
537# define PATH_SEP ']'
538# define PATH_SEP2 ':'
539# define SUFFIX_SEP ';'
540# define NO_MULTIPLE_DOTS
541# define Z_SUFFIX "-gz"
542# define RECORD_IO 1
543# define casemap(c) tolow(c)
544# define OS_CODE 0x02
545# define OPTIONS_VAR "GZIP_OPT"
546# define STDC_HEADERS
547# define NO_UTIME
548# define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
549# include <file.h>
550# define unlink delete
551# ifdef VAXC
552# define NO_FCNTL_H
553# include <unixio.h>
554# endif
555#endif
556
557#ifdef AMIGA
558# define PATH_SEP2 ':'
559# define STDC_HEADERS
560# define OS_CODE 0x01
561# define ASMV
562# ifdef __GNUC__
563# define DIRENT
564# define HAVE_UNISTD_H
565# else /* SASC */
566# define NO_STDIN_FSTAT
567# define SYSDIR
568# define NO_SYMLINK
569# define NO_CHOWN
570# define NO_FCNTL_H
571# include <fcntl.h> /* for read() and write() */
572# define direct dirent
573 extern void _expand_args(int *argc, char ***argv);
574# define EXPAND(argc,argv) _expand_args(&argc,&argv);
575# undef O_BINARY /* disable useless --ascii option */
576# endif
577#endif
578
579#if defined(ATARI) || defined(atarist)
580# ifndef STDC_HEADERS
581# define STDC_HEADERS
582# define HAVE_UNISTD_H
583# define DIRENT
584# endif
585# define ASMV
586# define OS_CODE 0x05
587# ifdef TOSFS
588# define PATH_SEP2 '\\'
589# define PATH_SEP3 ':'
590# define MAX_PATH_LEN 128
591# define NO_MULTIPLE_DOTS
592# define MAX_EXT_CHARS 3
593# define Z_SUFFIX "z"
594# define NO_CHOWN
595# define casemap(c) tolow(c) /* Force file names to lower case */
596# define NO_SYMLINK
597# endif
598#endif
599
600#ifdef MACOS
601# define PATH_SEP ':'
602# define DYN_ALLOC
603# define PROTO
604# define NO_STDIN_FSTAT
605# define NO_CHOWN
606# define NO_UTIME
607# define chmod(file, mode) (0)
608# define OPEN(name, flags, mode) open(name, flags)
609# define OS_CODE 0x07
610# ifdef MPW
611# define isatty(fd) ((fd) <= 2)
612# endif
613#endif
614
615#ifdef __50SERIES /* Prime/PRIMOS */
616# define PATH_SEP '>'
617# define STDC_HEADERS
618# define NO_MEMORY_H
619# define NO_UTIME_H
620# define NO_UTIME
621# define NO_CHOWN
622# define NO_STDIN_FSTAT
623# define NO_SIZE_CHECK
624# define NO_SYMLINK
625# define RECORD_IO 1
626# define casemap(c) tolow(c) /* Force file names to lower case */
627# define put_char(c) put_byte((c) & 0x7F)
628# define get_char(c) ascii2pascii(get_byte())
629# define OS_CODE 0x0F /* temporary, subject to change */
630# ifdef SIGTERM
631# undef SIGTERM /* We don't want a signal handler for SIGTERM */
632# endif
633#endif
634
635#if defined(pyr) && !defined(NOMEMCPY) /* Pyramid */
636# define NOMEMCPY /* problem with overlapping copies */
637#endif
638
639#ifdef TOPS20
640# define OS_CODE 0x0a
641#endif
642
643#ifndef unix
644# define NO_ST_INO /* don't rely on inode numbers */
645#endif
646
647
648 /* Common defaults */
649
650#ifndef OS_CODE
651# define OS_CODE 0x03 /* assume Unix */
652#endif
653
654#ifndef PATH_SEP
655# define PATH_SEP '/'
656#endif
657
658#ifndef casemap
659# define casemap(c) (c)
660#endif
661
662#ifndef OPTIONS_VAR
663# define OPTIONS_VAR "GZIP"
664#endif
665
666#ifndef Z_SUFFIX
667# define Z_SUFFIX ".gz"
668#endif
669
670#ifdef MAX_EXT_CHARS
671# define MAX_SUFFIX MAX_EXT_CHARS
672#else
673# define MAX_SUFFIX 30
674#endif
675
676#ifndef MAKE_LEGAL_NAME
677# ifdef NO_MULTIPLE_DOTS
678# define MAKE_LEGAL_NAME(name) make_simple_name(name)
679# else
680# define MAKE_LEGAL_NAME(name)
681# endif
682#endif
683
684#ifndef MIN_PART
685# define MIN_PART 3
686 /* keep at least MIN_PART chars between dots in a file name. */
687#endif
688
689#ifndef EXPAND
690# define EXPAND(argc,argv)
691#endif
692
693#ifndef RECORD_IO
694# define RECORD_IO 0
695#endif
696
697#ifndef SET_BINARY_MODE
698# define SET_BINARY_MODE(fd)
699#endif
700
701#ifndef OPEN
702# define OPEN(name, flags, mode) open(name, flags, mode)
703#endif
704
705#ifndef get_char
706# define get_char() get_byte()
707#endif
708
709#ifndef put_char
710# define put_char(c) put_byte(c)
711#endif
712/* bits.c -- output variable-length bit strings
713 * Copyright (C) 1992-1993 Jean-loup Gailly
714 * This is free software; you can redistribute it and/or modify it under the
715 * terms of the GNU General Public License, see the file COPYING.
716 */
717
718
719/*
720 * PURPOSE
721 *
722 * Output variable-length bit strings. Compression can be done
723 * to a file or to memory. (The latter is not supported in this version.)
724 *
725 * DISCUSSION
726 *
727 * The PKZIP "deflate" file format interprets compressed file data
728 * as a sequence of bits. Multi-bit strings in the file may cross
729 * byte boundaries without restriction.
730 *
731 * The first bit of each byte is the low-order bit.
732 *
733 * The routines in this file allow a variable-length bit value to
734 * be output right-to-left (useful for literal values). For
735 * left-to-right output (useful for code strings from the tree routines),
736 * the bits must have been reversed first with bi_reverse().
737 *
738 * For in-memory compression, the compressed bit stream goes directly
739 * into the requested output buffer. The input data is read in blocks
740 * by the mem_read() function. The buffer is limited to 64K on 16 bit
741 * machines.
742 *
743 * INTERFACE
744 *
745 * void bi_init (FILE *zipfile)
746 * Initialize the bit string routines.
747 *
748 * void send_bits (int value, int length)
749 * Write out a bit string, taking the source bits right to
750 * left.
751 *
752 * int bi_reverse (int value, int length)
753 * Reverse the bits of a bit string, taking the source bits left to
754 * right and emitting them right to left.
755 *
756 * void bi_windup (void)
757 * Write out any remaining bits in an incomplete byte.
758 *
759 * void copy_block(char *buf, unsigned len, int header)
760 * Copy a stored block to the zip file, storing first the length and
761 * its one's complement if requested.
762 *
763 */
764
765#ifdef DEBUG
766# include <stdio.h>
767#endif
768
769#ifdef RCSID
770static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
771#endif
772
773/* ===========================================================================
774 * Local data used by the "bit string" routines.
775 */
776
777local file_t zfile; /* output gzip file */
778
779local unsigned short bi_buf;
780/* Output buffer. bits are inserted starting at the bottom (least significant
781 * bits).
782 */
783
784#define Buf_size (8 * 2*sizeof(char))
785/* Number of bits used within bi_buf. (bi_buf might be implemented on
786 * more than 16 bits on some systems.)
787 */
788
789local int bi_valid;
790/* Number of valid bits in bi_buf. All bits above the last valid bit
791 * are always zero.
792 */
793
794int (*read_buf) OF((char *buf, unsigned size));
795/* Current input function. Set to mem_read for in-memory compression */
796
797#ifdef DEBUG
798 ulg bits_sent; /* bit length of the compressed data */
799#endif
800
801/* ===========================================================================
802 * Initialize the bit string routines.
803 */
804void bi_init (zipfile)
805 file_t zipfile; /* output zip file, NO_FILE for in-memory compression */
806{
807 zfile = zipfile;
808 bi_buf = 0;
809 bi_valid = 0;
810#ifdef DEBUG
811 bits_sent = 0L;
812#endif
813
814 /* Set the defaults for file compression. They are set by memcompress
815 * for in-memory compression.
816 */
817 if (zfile != NO_FILE) {
818 read_buf = file_read;
819 }
820}
821
822/* ===========================================================================
823 * Send a value on a given number of bits.
824 * IN assertion: length <= 16 and value fits in length bits.
825 */
826void send_bits(value, length)
827 int value; /* value to send */
828 int length; /* number of bits */
829{
830#ifdef DEBUG
831 Tracev((stderr," l %2d v %4x ", length, value));
832 Assert(length > 0 && length <= 15, "invalid length");
833 bits_sent += (ulg)length;
834#endif
835 /* If not enough room in bi_buf, use (valid) bits from bi_buf and
836 * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
837 * unused bits in value.
838 */
839 if (bi_valid > (int)Buf_size - length) {
840 bi_buf |= (value << bi_valid);
841 put_short(bi_buf);
842 bi_buf = (ush)value >> (Buf_size - bi_valid);
843 bi_valid += length - Buf_size;
844 } else {
845 bi_buf |= value << bi_valid;
846 bi_valid += length;
847 }
848}
849
850/* ===========================================================================
851 * Reverse the first len bits of a code, using straightforward code (a faster
852 * method would use a table)
853 * IN assertion: 1 <= len <= 15
854 */
855unsigned bi_reverse(code, len)
856 unsigned code; /* the value to invert */
857 int len; /* its bit length */
858{
859 register unsigned res = 0;
860 do {
861 res |= code & 1;
862 code >>= 1, res <<= 1;
863 } while (--len > 0);
864 return res >> 1;
865}
866
867/* ===========================================================================
868 * Write out any remaining bits in an incomplete byte.
869 */
870void bi_windup()
871{
872 if (bi_valid > 8) {
873 put_short(bi_buf);
874 } else if (bi_valid > 0) {
875 put_byte(bi_buf);
876 }
877 bi_buf = 0;
878 bi_valid = 0;
879#ifdef DEBUG
880 bits_sent = (bits_sent+7) & ~7;
881#endif
882}
883
884/* ===========================================================================
885 * Copy a stored block to the zip file, storing first the length and its
886 * one's complement if requested.
887 */
888void copy_block(buf, len, header)
889 char *buf; /* the input data */
890 unsigned len; /* its length */
891 int header; /* true if block header must be written */
892{
893 bi_windup(); /* align on byte boundary */
894
895 if (header) {
896 put_short((ush)len);
897 put_short((ush)~len);
898#ifdef DEBUG
899 bits_sent += 2*16;
900#endif
901 }
902#ifdef DEBUG
903 bits_sent += (ulg)len<<3;
904#endif
905 while (len--) {
906#ifdef CRYPT
907 int t;
908 if (key) zencode(*buf, t);
909#endif
910 put_byte(*buf++);
911 }
912}
913/* deflate.c -- compress data using the deflation algorithm
914 * Copyright (C) 1992-1993 Jean-loup Gailly
915 * This is free software; you can redistribute it and/or modify it under the
916 * terms of the GNU General Public License, see the file COPYING.
917 */
918
919/*
920 * PURPOSE
921 *
922 * Identify new text as repetitions of old text within a fixed-
923 * length sliding window trailing behind the new text.
924 *
925 * DISCUSSION
926 *
927 * The "deflation" process depends on being able to identify portions
928 * of the input text which are identical to earlier input (within a
929 * sliding window trailing behind the input currently being processed).
930 *
931 * The most straightforward technique turns out to be the fastest for
932 * most input files: try all possible matches and select the longest.
933 * The key feature of this algorithm is that insertions into the string
934 * dictionary are very simple and thus fast, and deletions are avoided
935 * completely. Insertions are performed at each input character, whereas
936 * string matches are performed only when the previous match ends. So it
937 * is preferable to spend more time in matches to allow very fast string
938 * insertions and avoid deletions. The matching algorithm for small
939 * strings is inspired from that of Rabin & Karp. A brute force approach
940 * is used to find longer strings when a small match has been found.
941 * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
942 * (by Leonid Broukhis).
943 * A previous version of this file used a more sophisticated algorithm
944 * (by Fiala and Greene) which is guaranteed to run in linear amortized
945 * time, but has a larger average cost, uses more memory and is patented.
946 * However the F&G algorithm may be faster for some highly redundant
947 * files if the parameter max_chain_length (described below) is too large.
948 *
949 * ACKNOWLEDGEMENTS
950 *
951 * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
952 * I found it in 'freeze' written by Leonid Broukhis.
953 * Thanks to many info-zippers for bug reports and testing.
954 *
955 * REFERENCES
956 *
957 * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
958 *
959 * A description of the Rabin and Karp algorithm is given in the book
960 * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
961 *
962 * Fiala,E.R., and Greene,D.H.
963 * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
964 *
965 * INTERFACE
966 *
967 * void lm_init (int pack_level, ush *flags)
968 * Initialize the "longest match" routines for a new file
969 *
970 * ulg deflate (void)
971 * Processes a new input file and return its compressed length. Sets
972 * the compressed length, crc, deflate flags and internal file
973 * attributes.
974 */
975
976#include <stdio.h>
977
978#ifdef RCSID
979static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
980#endif
981
982/* ===========================================================================
983 * Configuration parameters
984 */
985
986/* Compile with MEDIUM_MEM to reduce the memory requirements or
987 * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
988 * entire input file can be held in memory (not possible on 16 bit systems).
989 * Warning: defining these symbols affects HASH_BITS (see below) and thus
990 * affects the compression ratio. The compressed output
991 * is still correct, and might even be smaller in some cases.
992 */
993
994#ifdef SMALL_MEM
995# define HASH_BITS 13 /* Number of bits used to hash strings */
996#endif
997#ifdef MEDIUM_MEM
998# define HASH_BITS 14
999#endif
1000#ifndef HASH_BITS
1001# define HASH_BITS 15
1002 /* For portability to 16 bit machines, do not use values above 15. */
1003#endif
1004
1005/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
1006 * window with tab_suffix. Check that we can do this:
1007 */
1008#if (WSIZE<<1) > (1<<BITS)
1009 error: cannot overlay window with tab_suffix and prev with tab_prefix0
1010#endif
1011#if HASH_BITS > BITS-1
1012 error: cannot overlay head with tab_prefix1
1013#endif
1014
1015#define HASH_SIZE (unsigned)(1<<HASH_BITS)
1016#define HASH_MASK (HASH_SIZE-1)
1017#define WMASK (WSIZE-1)
1018/* HASH_SIZE and WSIZE must be powers of two */
1019
1020#define NIL 0
1021/* Tail of hash chains */
1022
1023#define FAST 4
1024#define SLOW 2
1025/* speed options for the general purpose bit flag */
1026
1027#ifndef TOO_FAR
1028# define TOO_FAR 4096
1029#endif
1030/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
1031
1032/* ===========================================================================
1033 * Local data used by the "longest match" routines.
1034 */
1035
1036typedef ush Pos;
1037typedef unsigned IPos;
1038/* A Pos is an index in the character window. We use short instead of int to
1039 * save space in the various tables. IPos is used only for parameter passing.
1040 */
1041
1042/* DECLARE(uch, window, 2L*WSIZE); */
1043/* Sliding window. Input bytes are read into the second half of the window,
1044 * and move to the first half later to keep a dictionary of at least WSIZE
1045 * bytes. With this organization, matches are limited to a distance of
1046 * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
1047 * performed with a length multiple of the block size. Also, it limits
1048 * the window size to 64K, which is quite useful on MSDOS.
1049 * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
1050 * be less efficient).
1051 */
1052
1053/* DECLARE(Pos, prev, WSIZE); */
1054/* Link to older string with same hash index. To limit the size of this
1055 * array to 64K, this link is maintained only for the last 32K strings.
1056 * An index in this array is thus a window index modulo 32K.
1057 */
1058
1059/* DECLARE(Pos, head, 1<<HASH_BITS); */
1060/* Heads of the hash chains or NIL. */
1061
1062ulg window_size = (ulg)2*WSIZE;
1063/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
1064 * input file length plus MIN_LOOKAHEAD.
1065 */
1066
1067long block_start;
1068/* window position at the beginning of the current output block. Gets
1069 * negative when the window is moved backwards.
1070 */
1071
1072local unsigned ins_h; /* hash index of string to be inserted */
1073
1074#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
1075/* Number of bits by which ins_h and del_h must be shifted at each
1076 * input step. It must be such that after MIN_MATCH steps, the oldest
1077 * byte no longer takes part in the hash key, that is:
1078 * H_SHIFT * MIN_MATCH >= HASH_BITS
1079 */
1080
1081unsigned int near prev_length;
1082/* Length of the best match at previous step. Matches not greater than this
1083 * are discarded. This is used in the lazy match evaluation.
1084 */
1085
1086 unsigned near strstart; /* start of string to insert */
1087 unsigned near match_start; /* start of matching string */
1088local int eofile; /* flag set at end of input file */
1089local unsigned lookahead; /* number of valid bytes ahead in window */
1090
1091unsigned near max_chain_length;
1092/* To speed up deflation, hash chains are never searched beyond this length.
1093 * A higher limit improves compression ratio but degrades the speed.
1094 */
1095
1096local unsigned int max_lazy_match;
1097/* Attempt to find a better match only when the current match is strictly
1098 * smaller than this value. This mechanism is used only for compression
1099 * levels >= 4.
1100 */
1101#define max_insert_length max_lazy_match
1102/* Insert new strings in the hash table only if the match length
1103 * is not greater than this length. This saves time but degrades compression.
1104 * max_insert_length is used only for compression levels <= 3.
1105 */
1106
1107unsigned near good_match;
1108/* Use a faster search when the previous match is longer than this */
1109
1110
1111/* Values for max_lazy_match, good_match and max_chain_length, depending on
1112 * the desired pack level (0..9). The values given below have been tuned to
1113 * exclude worst case performance for pathological files. Better values may be
1114 * found for specific files.
1115 */
1116
1117typedef struct config {
1118 ush good_length; /* reduce lazy search above this match length */
1119 ush max_lazy; /* do not perform lazy search above this match length */
1120 ush nice_length; /* quit search above this match length */
1121 ush max_chain;
1122} config;
1123
1124#ifdef FULL_SEARCH
1125# define nice_match MAX_MATCH
1126#else
1127 int near nice_match; /* Stop searching when current match exceeds this */
1128#endif
1129
1130local config configuration_table =
1131/* 9 */ {32, 258, 258, 4096}; /* maximum compression */
1132
1133/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
1134 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
1135 * meaning.
1136 */
1137
1138#define EQUAL 0
1139/* result of memcmp for equal strings */
1140
1141/* ===========================================================================
1142 * Prototypes for local functions.
1143 */
1144local void fill_window OF((void));
1145
1146 int longest_match OF((IPos cur_match));
1147#ifdef ASMV
1148 void match_init OF((void)); /* asm code initialization */
1149#endif
1150
1151#ifdef DEBUG
1152local void check_match OF((IPos start, IPos match, int length));
1153#endif
1154
1155/* ===========================================================================
1156 * Update a hash value with the given input byte
1157 * IN assertion: all calls to to UPDATE_HASH are made with consecutive
1158 * input characters, so that a running hash key can be computed from the
1159 * previous key instead of complete recalculation each time.
1160 */
1161#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
1162
1163/* ===========================================================================
1164 * Insert string s in the dictionary and set match_head to the previous head
1165 * of the hash chain (the most recent string with same hash key). Return
1166 * the previous length of the hash chain.
1167 * IN assertion: all calls to to INSERT_STRING are made with consecutive
1168 * input characters and the first MIN_MATCH bytes of s are valid
1169 * (except for the last MIN_MATCH-1 bytes of the input file).
1170 */
1171#define INSERT_STRING(s, match_head) \
1172 (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
1173 prev[(s) & WMASK] = match_head = head[ins_h], \
1174 head[ins_h] = (s))
1175
1176/* ===========================================================================
1177 * Initialize the "longest match" routines for a new file
1178 */
1179void lm_init (flags)
1180 ush *flags; /* general purpose bit flag */
1181{
1182 register unsigned j;
1183
1184 /* Initialize the hash table. */
1185#if defined(MAXSEG_64K) && HASH_BITS == 15
1186 for (j = 0; j < HASH_SIZE; j++) head[j] = NIL;
1187#else
1188 memzero((char*)head, HASH_SIZE*sizeof(*head));
1189#endif
1190 /* prev will be initialized on the fly */
1191
1192 /* Set the default configuration parameters:
1193 */
1194 max_lazy_match = configuration_table.max_lazy;
1195 good_match = configuration_table.good_length;
1196#ifndef FULL_SEARCH
1197 nice_match = configuration_table.nice_length;
1198#endif
1199 max_chain_length = configuration_table.max_chain;
1200 *flags |= SLOW;
1201 /* ??? reduce max_chain_length for binary files */
1202
1203 strstart = 0;
1204 block_start = 0L;
1205#ifdef ASMV
1206 match_init(); /* initialize the asm code */
1207#endif
1208
1209 lookahead = read_buf((char*)window,
1210 sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
1211
1212 if (lookahead == 0 || lookahead == (unsigned)EOF) {
1213 eofile = 1, lookahead = 0;
1214 return;
1215 }
1216 eofile = 0;
1217 /* Make sure that we always have enough lookahead. This is important
1218 * if input comes from a device such as a tty.
1219 */
1220 while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
1221
1222 ins_h = 0;
1223 for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
1224 /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
1225 * not important since only literal bytes will be emitted.
1226 */
1227}
1228
1229/* ===========================================================================
1230 * Set match_start to the longest match starting at the given string and
1231 * return its length. Matches shorter or equal to prev_length are discarded,
1232 * in which case the result is equal to prev_length and match_start is
1233 * garbage.
1234 * IN assertions: cur_match is the head of the hash chain for the current
1235 * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
1236 */
1237#ifndef ASMV
1238/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
1239 * match.s. The code is functionally equivalent, so you can use the C version
1240 * if desired.
1241 */
1242int longest_match(cur_match)
1243 IPos cur_match; /* current match */
1244{
1245 unsigned chain_length = max_chain_length; /* max hash chain length */
1246 register uch *scan = window + strstart; /* current string */
1247 register uch *match; /* matched string */
1248 register int len; /* length of current match */
1249 int best_len = prev_length; /* best match length so far */
1250 IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
1251 /* Stop when cur_match becomes <= limit. To simplify the code,
1252 * we prevent matches with the string of window index 0.
1253 */
1254
1255/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
1256 * It is easy to get rid of this optimization if necessary.
1257 */
1258#if HASH_BITS < 8 || MAX_MATCH != 258
1259 error: Code too clever
1260#endif
1261
1262#ifdef UNALIGNED_OK
1263 /* Compare two bytes at a time. Note: this is not always beneficial.
1264 * Try with and without -DUNALIGNED_OK to check.
1265 */
1266 register uch *strend = window + strstart + MAX_MATCH - 1;
1267 register ush scan_start = *(ush*)scan;
1268 register ush scan_end = *(ush*)(scan+best_len-1);
1269#else
1270 register uch *strend = window + strstart + MAX_MATCH;
1271 register uch scan_end1 = scan[best_len-1];
1272 register uch scan_end = scan[best_len];
1273#endif
1274
1275 /* Do not waste too much time if we already have a good match: */
1276 if (prev_length >= good_match) {
1277 chain_length >>= 2;
1278 }
1279 Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
1280
1281 do {
1282 Assert(cur_match < strstart, "no future");
1283 match = window + cur_match;
1284
1285 /* Skip to next match if the match length cannot increase
1286 * or if the match length is less than 2:
1287 */
1288#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
1289 /* This code assumes sizeof(unsigned short) == 2. Do not use
1290 * UNALIGNED_OK if your compiler uses a different size.
1291 */
1292 if (*(ush*)(match+best_len-1) != scan_end ||
1293 *(ush*)match != scan_start) continue;
1294
1295 /* It is not necessary to compare scan[2] and match[2] since they are
1296 * always equal when the other bytes match, given that the hash keys
1297 * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
1298 * strstart+3, +5, ... up to strstart+257. We check for insufficient
1299 * lookahead only every 4th comparison; the 128th check will be made
1300 * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
1301 * necessary to put more guard bytes at the end of the window, or
1302 * to check more often for insufficient lookahead.
1303 */
1304 scan++, match++;
1305 do {
1306 } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
1307 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
1308 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
1309 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
1310 scan < strend);
1311 /* The funny "do {}" generates better code on most compilers */
1312
1313 /* Here, scan <= window+strstart+257 */
1314 Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
1315 if (*scan == *match) scan++;
1316
1317 len = (MAX_MATCH - 1) - (int)(strend-scan);
1318 scan = strend - (MAX_MATCH-1);
1319
1320#else /* UNALIGNED_OK */
1321
1322 if (match[best_len] != scan_end ||
1323 match[best_len-1] != scan_end1 ||
1324 *match != *scan ||
1325 *++match != scan[1]) continue;
1326
1327 /* The check at best_len-1 can be removed because it will be made
1328 * again later. (This heuristic is not always a win.)
1329 * It is not necessary to compare scan[2] and match[2] since they
1330 * are always equal when the other bytes match, given that
1331 * the hash keys are equal and that HASH_BITS >= 8.
1332 */
1333 scan += 2, match++;
1334
1335 /* We check for insufficient lookahead only every 8th comparison;
1336 * the 256th check will be made at strstart+258.
1337 */
1338 do {
1339 } while (*++scan == *++match && *++scan == *++match &&
1340 *++scan == *++match && *++scan == *++match &&
1341 *++scan == *++match && *++scan == *++match &&
1342 *++scan == *++match && *++scan == *++match &&
1343 scan < strend);
1344
1345 len = MAX_MATCH - (int)(strend - scan);
1346 scan = strend - MAX_MATCH;
1347
1348#endif /* UNALIGNED_OK */
1349
1350 if (len > best_len) {
1351 match_start = cur_match;
1352 best_len = len;
1353 if (len >= nice_match) break;
1354#ifdef UNALIGNED_OK
1355 scan_end = *(ush*)(scan+best_len-1);
1356#else
1357 scan_end1 = scan[best_len-1];
1358 scan_end = scan[best_len];
1359#endif
1360 }
1361 } while ((cur_match = prev[cur_match & WMASK]) > limit
1362 && --chain_length != 0);
1363
1364 return best_len;
1365}
1366#endif /* ASMV */
1367
1368#ifdef DEBUG
1369/* ===========================================================================
1370 * Check that the match at match_start is indeed a match.
1371 */
1372local void check_match(start, match, length)
1373 IPos start, match;
1374 int length;
1375{
1376 /* check that the match is indeed a match */
1377 if (memcmp((char*)window + match,
1378 (char*)window + start, length) != EQUAL) {
1379 fprintf(stderr,
1380 " start %d, match %d, length %d\n",
1381 start, match, length);
1382 error("invalid match");
1383 }
1384 if (verbose > 1) {
1385 fprintf(stderr,"\\[%d,%d]", start-match, length);
1386 do { putc(window[start++], stderr); } while (--length != 0);
1387 }
1388}
1389#else
1390# define check_match(start, match, length)
1391#endif
1392
1393/* ===========================================================================
1394 * Fill the window when the lookahead becomes insufficient.
1395 * Updates strstart and lookahead, and sets eofile if end of input file.
1396 * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
1397 * OUT assertions: at least one byte has been read, or eofile is set;
1398 * file reads are performed for at least two bytes (required for the
1399 * translate_eol option).
1400 */
1401local void fill_window()
1402{
1403 register unsigned n, m;
1404 unsigned more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
1405 /* Amount of free space at the end of the window. */
1406
1407 /* If the window is almost full and there is insufficient lookahead,
1408 * move the upper half to the lower one to make room in the upper half.
1409 */
1410 if (more == (unsigned)EOF) {
1411 /* Very unlikely, but possible on 16 bit machine if strstart == 0
1412 * and lookahead == 1 (input done one byte at time)
1413 */
1414 more--;
1415 } else if (strstart >= WSIZE+MAX_DIST) {
1416 /* By the IN assertion, the window is not empty so we can't confuse
1417 * more == 0 with more == 64K on a 16 bit machine.
1418 */
1419 Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
1420
1421 memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
1422 match_start -= WSIZE;
1423 strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
1424
1425 block_start -= (long) WSIZE;
1426
1427 for (n = 0; n < HASH_SIZE; n++) {
1428 m = head[n];
1429 head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1430 }
1431 for (n = 0; n < WSIZE; n++) {
1432 m = prev[n];
1433 prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1434 /* If n is not on any hash chain, prev[n] is garbage but
1435 * its value will never be used.
1436 */
1437 }
1438 more += WSIZE;
1439 }
1440 /* At this point, more >= 2 */
1441 if (!eofile) {
1442 n = read_buf((char*)window+strstart+lookahead, more);
1443 if (n == 0 || n == (unsigned)EOF) {
1444 eofile = 1;
1445 } else {
1446 lookahead += n;
1447 }
1448 }
1449}
1450
1451/* ===========================================================================
1452 * Flush the current block, with given end-of-file flag.
1453 * IN assertion: strstart is set to the end of the current match.
1454 */
1455#define FLUSH_BLOCK(eof) \
1456 flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
1457 (char*)NULL, (long)strstart - block_start, (eof))
1458
1459/* ===========================================================================
1460 * Same as above, but achieves better compression. We use a lazy
1461 * evaluation for matches: a match is finally adopted only if there is
1462 * no better match at the next window position.
1463 */
1464ulg deflate()
1465{
1466 IPos hash_head; /* head of hash chain */
1467 IPos prev_match; /* previous match */
1468 int flush; /* set if current block must be flushed */
1469 int match_available = 0; /* set if previous match exists */
1470 register unsigned match_length = MIN_MATCH-1; /* length of best match */
1471#ifdef DEBUG
1472 extern long isize; /* byte length of input file, for debug only */
1473#endif
1474
1475 /* Process the input block. */
1476 while (lookahead != 0) {
1477 /* Insert the string window[strstart .. strstart+2] in the
1478 * dictionary, and set hash_head to the head of the hash chain:
1479 */
1480 INSERT_STRING(strstart, hash_head);
1481
1482 /* Find the longest match, discarding those <= prev_length.
1483 */
1484 prev_length = match_length, prev_match = match_start;
1485 match_length = MIN_MATCH-1;
1486
1487 if (hash_head != NIL && prev_length < max_lazy_match &&
1488 strstart - hash_head <= MAX_DIST) {
1489 /* To simplify the code, we prevent matches with the string
1490 * of window index 0 (in particular we have to avoid a match
1491 * of the string with itself at the start of the input file).
1492 */
1493 match_length = longest_match (hash_head);
1494 /* longest_match() sets match_start */
1495 if (match_length > lookahead) match_length = lookahead;
1496
1497 /* Ignore a length 3 match if it is too distant: */
1498 if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
1499 /* If prev_match is also MIN_MATCH, match_start is garbage
1500 * but we will ignore the current match anyway.
1501 */
1502 match_length--;
1503 }
1504 }
1505 /* If there was a match at the previous step and the current
1506 * match is not better, output the previous match:
1507 */
1508 if (prev_length >= MIN_MATCH && match_length <= prev_length) {
1509
1510 check_match(strstart-1, prev_match, prev_length);
1511
1512 flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
1513
1514 /* Insert in hash table all strings up to the end of the match.
1515 * strstart-1 and strstart are already inserted.
1516 */
1517 lookahead -= prev_length-1;
1518 prev_length -= 2;
1519 do {
1520 strstart++;
1521 INSERT_STRING(strstart, hash_head);
1522 /* strstart never exceeds WSIZE-MAX_MATCH, so there are
1523 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
1524 * these bytes are garbage, but it does not matter since the
1525 * next lookahead bytes will always be emitted as literals.
1526 */
1527 } while (--prev_length != 0);
1528 match_available = 0;
1529 match_length = MIN_MATCH-1;
1530 strstart++;
1531 if (flush) FLUSH_BLOCK(0), block_start = strstart;
1532
1533 } else if (match_available) {
1534 /* If there was no match at the previous position, output a
1535 * single literal. If there was a match but the current match
1536 * is longer, truncate the previous match to a single literal.
1537 */
1538 Tracevv((stderr,"%c",window[strstart-1]));
1539 if (ct_tally (0, window[strstart-1])) {
1540 FLUSH_BLOCK(0), block_start = strstart;
1541 }
1542 strstart++;
1543 lookahead--;
1544 } else {
1545 /* There is no previous match to compare with, wait for
1546 * the next step to decide.
1547 */
1548 match_available = 1;
1549 strstart++;
1550 lookahead--;
1551 }
1552 Assert (strstart <= isize && lookahead <= isize, "a bit too far");
1553
1554 /* Make sure that we always have enough lookahead, except
1555 * at the end of the input file. We need MAX_MATCH bytes
1556 * for the next match, plus MIN_MATCH bytes to insert the
1557 * string following the next match.
1558 */
1559 while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
1560 }
1561 if (match_available) ct_tally (0, window[strstart-1]);
1562
1563 return FLUSH_BLOCK(1); /* eof */
1564}
1565/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
1566 * Copyright (C) 1992-1993 Jean-loup Gailly
1567 * The unzip code was written and put in the public domain by Mark Adler.
1568 * Portions of the lzw code are derived from the public domain 'compress'
1569 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
1570 * Ken Turkowski, Dave Mack and Peter Jannesen.
1571 *
1572 * See the license_msg below and the file COPYING for the software license.
1573 * See the file algorithm.doc for the compression algorithms and file formats.
1574 */
1575
1576/* Compress files with zip algorithm and 'compress' interface.
1577 * See usage() and help() functions below for all options.
1578 * Outputs:
1579 * file.gz: compressed file with same mode, owner, and utimes
1580 * or stdout with -c option or if stdin used as input.
1581 * If the output file name had to be truncated, the original name is kept
1582 * in the compressed file.
1583 * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
1584 *
1585 * Using gz on MSDOS would create too many file name conflicts. For
1586 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
1587 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
1588 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
1589 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
1590 *
1591 * For the meaning of all compilation flags, see comments in Makefile.in.
1592 */
1593
1594#ifdef RCSID
1595static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
1596#endif
1597
1598#include <ctype.h>
1599#include <sys/types.h>
1600#include <signal.h>
1601#include <sys/stat.h>
1602#include <errno.h>
1603
1604 /* configuration */
1605
1606#ifdef NO_TIME_H
1607# include <sys/time.h>
1608#else
1609# include <time.h>
1610#endif
1611
1612#ifndef NO_FCNTL_H
1613# include <fcntl.h>
1614#endif
1615
1616#ifdef HAVE_UNISTD_H
1617# include <unistd.h>
1618#endif
1619
1620#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
1621# include <stdlib.h>
1622#else
1623 extern int errno;
1624#endif
1625
1626#if defined(DIRENT)
1627# include <dirent.h>
1628 typedef struct dirent dir_type;
1629# define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
1630# define DIR_OPT "DIRENT"
1631#else
1632# define NLENGTH(dirent) ((dirent)->d_namlen)
1633# ifdef SYSDIR
1634# include <sys/dir.h>
1635 typedef struct direct dir_type;
1636# define DIR_OPT "SYSDIR"
1637# else
1638# ifdef SYSNDIR
1639# include <sys/ndir.h>
1640 typedef struct direct dir_type;
1641# define DIR_OPT "SYSNDIR"
1642# else
1643# ifdef NDIR
1644# include <ndir.h>
1645 typedef struct direct dir_type;
1646# define DIR_OPT "NDIR"
1647# else
1648# define NO_DIR
1649# define DIR_OPT "NO_DIR"
1650# endif
1651# endif
1652# endif
1653#endif
1654
1655#ifndef NO_UTIME
1656# ifndef NO_UTIME_H
1657# include <utime.h>
1658# define TIME_OPT "UTIME"
1659# else
1660# ifdef HAVE_SYS_UTIME_H
1661# include <sys/utime.h>
1662# define TIME_OPT "SYS_UTIME"
1663# else
1664 struct utimbuf {
1665 time_t actime;
1666 time_t modtime;
1667 };
1668# define TIME_OPT ""
1669# endif
1670# endif
1671#else
1672# define TIME_OPT "NO_UTIME"
1673#endif
1674
1675#if !defined(S_ISDIR) && defined(S_IFDIR)
1676# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1677#endif
1678#if !defined(S_ISREG) && defined(S_IFREG)
1679# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1680#endif
1681
1682typedef RETSIGTYPE (*sig_type) OF((int));
1683
1684#ifndef O_BINARY
1685# define O_BINARY 0 /* creation mode for open() */
1686#endif
1687
1688#ifndef O_CREAT
1689 /* Pure BSD system? */
1690# include <sys/file.h>
1691# ifndef O_CREAT
1692# define O_CREAT FCREAT
1693# endif
1694# ifndef O_EXCL
1695# define O_EXCL FEXCL
1696# endif
1697#endif
1698
1699#ifndef S_IRUSR
1700# define S_IRUSR 0400
1701#endif
1702#ifndef S_IWUSR
1703# define S_IWUSR 0200
1704#endif
1705#define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
1706
1707#ifndef MAX_PATH_LEN
1708# define MAX_PATH_LEN 1024 /* max pathname length */
1709#endif
1710
1711#ifndef SEEK_END
1712# define SEEK_END 2
1713#endif
1714
1715#ifdef NO_OFF_T
1716 typedef long off_t;
1717 off_t lseek OF((int fd, off_t offset, int whence));
1718#endif
1719
1720/* Separator for file name parts (see shorten_name()) */
1721#ifdef NO_MULTIPLE_DOTS
1722# define PART_SEP "-"
1723#else
1724# define PART_SEP "."
1725#endif
1726
1727 /* global buffers */
1728
1729DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
1730DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
1731DECLARE(ush, d_buf, DIST_BUFSIZE);
1732DECLARE(uch, window, 2L*WSIZE);
1733#ifndef MAXSEG_64K
1734 DECLARE(ush, tab_prefix, 1L<<BITS);
1735#else
1736 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
1737 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
1738#endif
1739
1740 /* local variables */
1741
1742int ascii = 0; /* convert end-of-lines to local OS conventions */
1743int to_stdout = 0; /* output to stdout (-c) */
1744int decompress = 0; /* decompress (-d) */
1745int no_name = -1; /* don't save or restore the original file name */
1746int no_time = -1; /* don't save or restore the original file time */
1747int foreground; /* set if program run in foreground */
1748char *progname; /* program name */
1749static int method = DEFLATED;/* compression method */
1750static int exit_code = OK; /* program exit code */
1751int save_orig_name; /* set if original name must be saved */
1752int last_member; /* set for .zip and .Z files */
1753int part_nb; /* number of parts in .gz file */
1754long time_stamp; /* original time stamp (modification time) */
1755long ifile_size; /* input file size, -1 for devices (debug only) */
1756char *env; /* contents of GZIP env variable */
1757char **args = NULL; /* argv pointer if GZIP env variable defined */
1758char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
1759int z_len; /* strlen(z_suffix) */
1760
1761long bytes_in; /* number of input bytes */
1762long bytes_out; /* number of output bytes */
1763char ifname[MAX_PATH_LEN]; /* input file name */
1764char ofname[MAX_PATH_LEN]; /* output file name */
1765int remove_ofname = 0; /* remove output file on error */
1766struct stat istat; /* status for input file */
1767int ifd; /* input file descriptor */
1768int ofd; /* output file descriptor */
1769unsigned insize; /* valid bytes in inbuf */
1770unsigned inptr; /* index of next byte to be processed in inbuf */
1771unsigned outcnt; /* bytes in output buffer */
1772
1773/* local functions */
1774
1775local void treat_stdin OF((void));
1776static int (*work) OF((int infile, int outfile)) = zip; /* function to call */
1777
1778#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
1779
1780/* ======================================================================== */
1781// int main (argc, argv)
1782// int argc;
1783// char **argv;
1784int gzip_main(struct FileInfo * i, int argc, char * * argv)
1785{
1786 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
1787 if (foreground) {
1788 (void) signal (SIGINT, (sig_type)abort_gzip);
1789 }
1790#ifdef SIGTERM
1791 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
1792 (void) signal(SIGTERM, (sig_type)abort_gzip);
1793 }
1794#endif
1795#ifdef SIGHUP
1796 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
1797 (void) signal(SIGHUP, (sig_type)abort_gzip);
1798 }
1799#endif
1800
1801 strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
1802 z_len = strlen(z_suffix);
1803
1804 to_stdout = 1;
1805
1806 /* Allocate all global buffers (for DYN_ALLOC option) */
1807 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
1808 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
1809 ALLOC(ush, d_buf, DIST_BUFSIZE);
1810 ALLOC(uch, window, 2L*WSIZE);
1811#ifndef MAXSEG_64K
1812 ALLOC(ush, tab_prefix, 1L<<BITS);
1813#else
1814 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
1815 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
1816#endif
1817
1818 /* And get to work */
1819 treat_stdin();
1820 do_exit(exit_code);
1821 return exit_code; /* just to avoid lint warning */
1822}
1823
1824/* ========================================================================
1825 * Compress or decompress stdin
1826 */
1827local void treat_stdin()
1828{
1829 SET_BINARY_MODE(fileno(stdout));
1830 strcpy(ifname, "stdin");
1831 strcpy(ofname, "stdout");
1832
1833 /* Get the time stamp on the input file. */
1834 time_stamp = 0; /* time unknown by default */
1835
1836 ifile_size = -1L; /* convention for unknown size */
1837
1838 clear_bufs(); /* clear input and output buffers */
1839 to_stdout = 1;
1840 part_nb = 0;
1841
1842 /* Actually do the compression/decompression. Loop over zipped members.
1843 */
1844 if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
1845}
1846
1847/* ========================================================================
1848 * Free all dynamically allocated variables and exit with the given code.
1849 */
1850local void do_exit(int exitcode)
1851{
1852 static int in_exit = 0;
1853
1854 if (in_exit) exit(exitcode);
1855 in_exit = 1;
1856 if (env != NULL) free(env), env = NULL;
1857 if (args != NULL) free((char*)args), args = NULL;
1858 FREE(inbuf);
1859 FREE(outbuf);
1860 FREE(d_buf);
1861 FREE(window);
1862#ifndef MAXSEG_64K
1863 FREE(tab_prefix);
1864#else
1865 FREE(tab_prefix0);
1866 FREE(tab_prefix1);
1867#endif
1868 exit(exitcode);
1869}
1870/* trees.c -- output deflated data using Huffman coding
1871 * Copyright (C) 1992-1993 Jean-loup Gailly
1872 * This is free software; you can redistribute it and/or modify it under the
1873 * terms of the GNU General Public License, see the file COPYING.
1874 */
1875
1876/*
1877 * PURPOSE
1878 *
1879 * Encode various sets of source values using variable-length
1880 * binary code trees.
1881 *
1882 * DISCUSSION
1883 *
1884 * The PKZIP "deflation" process uses several Huffman trees. The more
1885 * common source values are represented by shorter bit sequences.
1886 *
1887 * Each code tree is stored in the ZIP file in a compressed form
1888 * which is itself a Huffman encoding of the lengths of
1889 * all the code strings (in ascending order by source values).
1890 * The actual code strings are reconstructed from the lengths in
1891 * the UNZIP process, as described in the "application note"
1892 * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
1893 *
1894 * REFERENCES
1895 *
1896 * Lynch, Thomas J.
1897 * Data Compression: Techniques and Applications, pp. 53-55.
1898 * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
1899 *
1900 * Storer, James A.
1901 * Data Compression: Methods and Theory, pp. 49-50.
1902 * Computer Science Press, 1988. ISBN 0-7167-8156-5.
1903 *
1904 * Sedgewick, R.
1905 * Algorithms, p290.
1906 * Addison-Wesley, 1983. ISBN 0-201-06672-6.
1907 *
1908 * INTERFACE
1909 *
1910 * void ct_init (ush *attr, int *methodp)
1911 * Allocate the match buffer, initialize the various tables and save
1912 * the location of the internal file attribute (ascii/binary) and
1913 * method (DEFLATE/STORE)
1914 *
1915 * void ct_tally (int dist, int lc);
1916 * Save the match info and tally the frequency counts.
1917 *
1918 * long flush_block (char *buf, ulg stored_len, int eof)
1919 * Determine the best encoding for the current block: dynamic trees,
1920 * static trees or store, and output the encoded block to the zip
1921 * file. Returns the total compressed length for the file so far.
1922 *
1923 */
1924
1925#include <ctype.h>
1926
1927#ifdef RCSID
1928static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
1929#endif
1930
1931/* ===========================================================================
1932 * Constants
1933 */
1934
1935#define MAX_BITS 15
1936/* All codes must not exceed MAX_BITS bits */
1937
1938#define MAX_BL_BITS 7
1939/* Bit length codes must not exceed MAX_BL_BITS bits */
1940
1941#define LENGTH_CODES 29
1942/* number of length codes, not counting the special END_BLOCK code */
1943
1944#define LITERALS 256
1945/* number of literal bytes 0..255 */
1946
1947#define END_BLOCK 256
1948/* end of block literal code */
1949
1950#define L_CODES (LITERALS+1+LENGTH_CODES)
1951/* number of Literal or Length codes, including the END_BLOCK code */
1952
1953#define D_CODES 30
1954/* number of distance codes */
1955
1956#define BL_CODES 19
1957/* number of codes used to transfer the bit lengths */
1958
1959
1960local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
1961 = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
1962
1963local int near extra_dbits[D_CODES] /* extra bits for each distance code */
1964 = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
1965
1966local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
1967 = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
1968
1969#define STORED_BLOCK 0
1970#define STATIC_TREES 1
1971#define DYN_TREES 2
1972/* The three kinds of block type */
1973
1974#ifndef LIT_BUFSIZE
1975# ifdef SMALL_MEM
1976# define LIT_BUFSIZE 0x2000
1977# else
1978# ifdef MEDIUM_MEM
1979# define LIT_BUFSIZE 0x4000
1980# else
1981# define LIT_BUFSIZE 0x8000
1982# endif
1983# endif
1984#endif
1985#ifndef DIST_BUFSIZE
1986# define DIST_BUFSIZE LIT_BUFSIZE
1987#endif
1988/* Sizes of match buffers for literals/lengths and distances. There are
1989 * 4 reasons for limiting LIT_BUFSIZE to 64K:
1990 * - frequencies can be kept in 16 bit counters
1991 * - if compression is not successful for the first block, all input data is
1992 * still in the window so we can still emit a stored block even when input
1993 * comes from standard input. (This can also be done for all blocks if
1994 * LIT_BUFSIZE is not greater than 32K.)
1995 * - if compression is not successful for a file smaller than 64K, we can
1996 * even emit a stored file instead of a stored block (saving 5 bytes).
1997 * - creating new Huffman trees less frequently may not provide fast
1998 * adaptation to changes in the input data statistics. (Take for
1999 * example a binary file with poorly compressible code followed by
2000 * a highly compressible string table.) Smaller buffer sizes give
2001 * fast adaptation but have of course the overhead of transmitting trees
2002 * more frequently.
2003 * - I can't count above 4
2004 * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
2005 * memory at the expense of compression). Some optimizations would be possible
2006 * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
2007 */
2008#if LIT_BUFSIZE > INBUFSIZ
2009 error cannot overlay l_buf and inbuf
2010#endif
2011
2012#define REP_3_6 16
2013/* repeat previous bit length 3-6 times (2 bits of repeat count) */
2014
2015#define REPZ_3_10 17
2016/* repeat a zero length 3-10 times (3 bits of repeat count) */
2017
2018#define REPZ_11_138 18
2019/* repeat a zero length 11-138 times (7 bits of repeat count) */
2020
2021/* ===========================================================================
2022 * Local data
2023 */
2024
2025/* Data structure describing a single value and its code string. */
2026typedef struct ct_data {
2027 union {
2028 ush freq; /* frequency count */
2029 ush code; /* bit string */
2030 } fc;
2031 union {
2032 ush dad; /* father node in Huffman tree */
2033 ush len; /* length of bit string */
2034 } dl;
2035} ct_data;
2036
2037#define Freq fc.freq
2038#define Code fc.code
2039#define Dad dl.dad
2040#define Len dl.len
2041
2042#define HEAP_SIZE (2*L_CODES+1)
2043/* maximum heap size */
2044
2045local ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
2046local ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
2047
2048local ct_data near static_ltree[L_CODES+2];
2049/* The static literal tree. Since the bit lengths are imposed, there is no
2050 * need for the L_CODES extra codes used during heap construction. However
2051 * The codes 286 and 287 are needed to build a canonical tree (see ct_init
2052 * below).
2053 */
2054
2055local ct_data near static_dtree[D_CODES];
2056/* The static distance tree. (Actually a trivial tree since all codes use
2057 * 5 bits.)
2058 */
2059
2060local ct_data near bl_tree[2*BL_CODES+1];
2061/* Huffman tree for the bit lengths */
2062
2063typedef struct tree_desc {
2064 ct_data near *dyn_tree; /* the dynamic tree */
2065 ct_data near *static_tree; /* corresponding static tree or NULL */
2066 int near *extra_bits; /* extra bits for each code or NULL */
2067 int extra_base; /* base index for extra_bits */
2068 int elems; /* max number of elements in the tree */
2069 int max_length; /* max bit length for the codes */
2070 int max_code; /* largest code with non zero frequency */
2071} tree_desc;
2072
2073local tree_desc near l_desc =
2074{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
2075
2076local tree_desc near d_desc =
2077{dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0};
2078
2079local tree_desc near bl_desc =
2080{bl_tree, (ct_data near *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0};
2081
2082
2083local ush near bl_count[MAX_BITS+1];
2084/* number of codes at each bit length for an optimal tree */
2085
2086local uch near bl_order[BL_CODES]
2087 = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
2088/* The lengths of the bit length codes are sent in order of decreasing
2089 * probability, to avoid transmitting the lengths for unused bit length codes.
2090 */
2091
2092local int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
2093local int heap_len; /* number of elements in the heap */
2094local int heap_max; /* element of largest frequency */
2095/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
2096 * The same heap array is used to build all trees.
2097 */
2098
2099local uch near depth[2*L_CODES+1];
2100/* Depth of each subtree used as tie breaker for trees of equal frequency */
2101
2102local uch length_code[MAX_MATCH-MIN_MATCH+1];
2103/* length code for each normalized match length (0 == MIN_MATCH) */
2104
2105local uch dist_code[512];
2106/* distance codes. The first 256 values correspond to the distances
2107 * 3 .. 258, the last 256 values correspond to the top 8 bits of
2108 * the 15 bit distances.
2109 */
2110
2111local int near base_length[LENGTH_CODES];
2112/* First normalized length for each code (0 = MIN_MATCH) */
2113
2114local int near base_dist[D_CODES];
2115/* First normalized distance for each code (0 = distance of 1) */
2116
2117#define l_buf inbuf
2118/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */
2119
2120/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
2121
2122local uch near flag_buf[(LIT_BUFSIZE/8)];
2123/* flag_buf is a bit array distinguishing literals from lengths in
2124 * l_buf, thus indicating the presence or absence of a distance.
2125 */
2126
2127local unsigned last_lit; /* running index in l_buf */
2128local unsigned last_dist; /* running index in d_buf */
2129local unsigned last_flags; /* running index in flag_buf */
2130local uch flags; /* current flags not yet saved in flag_buf */
2131local uch flag_bit; /* current bit used in flags */
2132/* bits are filled in flags starting at bit 0 (least significant).
2133 * Note: these flags are overkill in the current code since we don't
2134 * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
2135 */
2136
2137local ulg opt_len; /* bit length of current block with optimal trees */
2138local ulg static_len; /* bit length of current block with static trees */
2139
2140local ulg compressed_len; /* total bit length of compressed file */
2141
2142local ulg input_len; /* total byte length of input file */
2143/* input_len is for debugging only since we can get it by other means. */
2144
2145ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
2146int *file_method; /* pointer to DEFLATE or STORE */
2147
2148#ifdef DEBUG
2149extern ulg bits_sent; /* bit length of the compressed data */
2150extern long isize; /* byte length of input file */
2151#endif
2152
2153extern long block_start; /* window offset of current block */
2154extern unsigned near strstart; /* window offset of current string */
2155
2156/* ===========================================================================
2157 * Local (static) routines in this file.
2158 */
2159
2160local void init_block OF((void));
2161local void pqdownheap OF((ct_data near *tree, int k));
2162local void gen_bitlen OF((tree_desc near *desc));
2163local void gen_codes OF((ct_data near *tree, int max_code));
2164local void build_tree OF((tree_desc near *desc));
2165local void scan_tree OF((ct_data near *tree, int max_code));
2166local void send_tree OF((ct_data near *tree, int max_code));
2167local int build_bl_tree OF((void));
2168local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
2169local void compress_block OF((ct_data near *ltree, ct_data near *dtree));
2170local void set_file_type OF((void));
2171
2172
2173#ifndef DEBUG
2174# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
2175 /* Send a code of the given tree. c and tree must not have side effects */
2176
2177#else /* DEBUG */
2178# define send_code(c, tree) \
2179 { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
2180 send_bits(tree[c].Code, tree[c].Len); }
2181#endif
2182
2183#define d_code(dist) \
2184 ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
2185/* Mapping from a distance to a distance code. dist is the distance - 1 and
2186 * must not have side effects. dist_code[256] and dist_code[257] are never
2187 * used.
2188 */
2189
2190#define MAX(a,b) (a >= b ? a : b)
2191/* the arguments must not have side effects */
2192
2193/* ===========================================================================
2194 * Allocate the match buffer, initialize the various tables and save the
2195 * location of the internal file attribute (ascii/binary) and method
2196 * (DEFLATE/STORE).
2197 */
2198void ct_init(attr, methodp)
2199 ush *attr; /* pointer to internal file attribute */
2200 int *methodp; /* pointer to compression method */
2201{
2202 int n; /* iterates over tree elements */
2203 int bits; /* bit counter */
2204 int length; /* length value */
2205 int code; /* code value */
2206 int dist; /* distance index */
2207
2208 file_type = attr;
2209 file_method = methodp;
2210 compressed_len = input_len = 0L;
2211
2212 if (static_dtree[0].Len != 0) return; /* ct_init already called */
2213
2214 /* Initialize the mapping length (0..255) -> length code (0..28) */
2215 length = 0;
2216 for (code = 0; code < LENGTH_CODES-1; code++) {
2217 base_length[code] = length;
2218 for (n = 0; n < (1<<extra_lbits[code]); n++) {
2219 length_code[length++] = (uch)code;
2220 }
2221 }
2222 Assert (length == 256, "ct_init: length != 256");
2223 /* Note that the length 255 (match length 258) can be represented
2224 * in two different ways: code 284 + 5 bits or code 285, so we
2225 * overwrite length_code[255] to use the best encoding:
2226 */
2227 length_code[length-1] = (uch)code;
2228
2229 /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
2230 dist = 0;
2231 for (code = 0 ; code < 16; code++) {
2232 base_dist[code] = dist;
2233 for (n = 0; n < (1<<extra_dbits[code]); n++) {
2234 dist_code[dist++] = (uch)code;
2235 }
2236 }
2237 Assert (dist == 256, "ct_init: dist != 256");
2238 dist >>= 7; /* from now on, all distances are divided by 128 */
2239 for ( ; code < D_CODES; code++) {
2240 base_dist[code] = dist << 7;
2241 for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
2242 dist_code[256 + dist++] = (uch)code;
2243 }
2244 }
2245 Assert (dist == 256, "ct_init: 256+dist != 512");
2246
2247 /* Construct the codes of the static literal tree */
2248 for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
2249 n = 0;
2250 while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
2251 while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
2252 while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
2253 while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
2254 /* Codes 286 and 287 do not exist, but we must include them in the
2255 * tree construction to get a canonical Huffman tree (longest code
2256 * all ones)
2257 */
2258 gen_codes((ct_data near *)static_ltree, L_CODES+1);
2259
2260 /* The static distance tree is trivial: */
2261 for (n = 0; n < D_CODES; n++) {
2262 static_dtree[n].Len = 5;
2263 static_dtree[n].Code = bi_reverse(n, 5);
2264 }
2265
2266 /* Initialize the first block of the first file: */
2267 init_block();
2268}
2269
2270/* ===========================================================================
2271 * Initialize a new block.
2272 */
2273local void init_block()
2274{
2275 int n; /* iterates over tree elements */
2276
2277 /* Initialize the trees. */
2278 for (n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0;
2279 for (n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0;
2280 for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
2281
2282 dyn_ltree[END_BLOCK].Freq = 1;
2283 opt_len = static_len = 0L;
2284 last_lit = last_dist = last_flags = 0;
2285 flags = 0; flag_bit = 1;
2286}
2287
2288#define SMALLEST 1
2289/* Index within the heap array of least frequent node in the Huffman tree */
2290
2291
2292/* ===========================================================================
2293 * Remove the smallest element from the heap and recreate the heap with
2294 * one less element. Updates heap and heap_len.
2295 */
2296#define pqremove(tree, top) \
2297{\
2298 top = heap[SMALLEST]; \
2299 heap[SMALLEST] = heap[heap_len--]; \
2300 pqdownheap(tree, SMALLEST); \
2301}
2302
2303/* ===========================================================================
2304 * Compares to subtrees, using the tree depth as tie breaker when
2305 * the subtrees have equal frequency. This minimizes the worst case length.
2306 */
2307#define smaller(tree, n, m) \
2308 (tree[n].Freq < tree[m].Freq || \
2309 (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
2310
2311/* ===========================================================================
2312 * Restore the heap property by moving down the tree starting at node k,
2313 * exchanging a node with the smallest of its two sons if necessary, stopping
2314 * when the heap property is re-established (each father smaller than its
2315 * two sons).
2316 */
2317local void pqdownheap(tree, k)
2318 ct_data near *tree; /* the tree to restore */
2319 int k; /* node to move down */
2320{
2321 int v = heap[k];
2322 int j = k << 1; /* left son of k */
2323 while (j <= heap_len) {
2324 /* Set j to the smallest of the two sons: */
2325 if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
2326
2327 /* Exit if v is smaller than both sons */
2328 if (smaller(tree, v, heap[j])) break;
2329
2330 /* Exchange v with the smallest son */
2331 heap[k] = heap[j]; k = j;
2332
2333 /* And continue down the tree, setting j to the left son of k */
2334 j <<= 1;
2335 }
2336 heap[k] = v;
2337}
2338
2339/* ===========================================================================
2340 * Compute the optimal bit lengths for a tree and update the total bit length
2341 * for the current block.
2342 * IN assertion: the fields freq and dad are set, heap[heap_max] and
2343 * above are the tree nodes sorted by increasing frequency.
2344 * OUT assertions: the field len is set to the optimal bit length, the
2345 * array bl_count contains the frequencies for each bit length.
2346 * The length opt_len is updated; static_len is also updated if stree is
2347 * not null.
2348 */
2349local void gen_bitlen(desc)
2350 tree_desc near *desc; /* the tree descriptor */
2351{
2352 ct_data near *tree = desc->dyn_tree;
2353 int near *extra = desc->extra_bits;
2354 int base = desc->extra_base;
2355 int max_code = desc->max_code;
2356 int max_length = desc->max_length;
2357 ct_data near *stree = desc->static_tree;
2358 int h; /* heap index */
2359 int n, m; /* iterate over the tree elements */
2360 int bits; /* bit length */
2361 int xbits; /* extra bits */
2362 ush f; /* frequency */
2363 int overflow = 0; /* number of elements with bit length too large */
2364
2365 for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
2366
2367 /* In a first pass, compute the optimal bit lengths (which may
2368 * overflow in the case of the bit length tree).
2369 */
2370 tree[heap[heap_max]].Len = 0; /* root of the heap */
2371
2372 for (h = heap_max+1; h < HEAP_SIZE; h++) {
2373 n = heap[h];
2374 bits = tree[tree[n].Dad].Len + 1;
2375 if (bits > max_length) bits = max_length, overflow++;
2376 tree[n].Len = (ush)bits;
2377 /* We overwrite tree[n].Dad which is no longer needed */
2378
2379 if (n > max_code) continue; /* not a leaf node */
2380
2381 bl_count[bits]++;
2382 xbits = 0;
2383 if (n >= base) xbits = extra[n-base];
2384 f = tree[n].Freq;
2385 opt_len += (ulg)f * (bits + xbits);
2386 if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
2387 }
2388 if (overflow == 0) return;
2389
2390 Trace((stderr,"\nbit length overflow\n"));
2391 /* This happens for example on obj2 and pic of the Calgary corpus */
2392
2393 /* Find the first bit length which could increase: */
2394 do {
2395 bits = max_length-1;
2396 while (bl_count[bits] == 0) bits--;
2397 bl_count[bits]--; /* move one leaf down the tree */
2398 bl_count[bits+1] += 2; /* move one overflow item as its brother */
2399 bl_count[max_length]--;
2400 /* The brother of the overflow item also moves one step up,
2401 * but this does not affect bl_count[max_length]
2402 */
2403 overflow -= 2;
2404 } while (overflow > 0);
2405
2406 /* Now recompute all bit lengths, scanning in increasing frequency.
2407 * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
2408 * lengths instead of fixing only the wrong ones. This idea is taken
2409 * from 'ar' written by Haruhiko Okumura.)
2410 */
2411 for (bits = max_length; bits != 0; bits--) {
2412 n = bl_count[bits];
2413 while (n != 0) {
2414 m = heap[--h];
2415 if (m > max_code) continue;
2416 if (tree[m].Len != (unsigned) bits) {
2417 Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
2418 opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
2419 tree[m].Len = (ush)bits;
2420 }
2421 n--;
2422 }
2423 }
2424}
2425
2426/* ===========================================================================
2427 * Generate the codes for a given tree and bit counts (which need not be
2428 * optimal).
2429 * IN assertion: the array bl_count contains the bit length statistics for
2430 * the given tree and the field len is set for all tree elements.
2431 * OUT assertion: the field code is set for all tree elements of non
2432 * zero code length.
2433 */
2434local void gen_codes (tree, max_code)
2435 ct_data near *tree; /* the tree to decorate */
2436 int max_code; /* largest code with non zero frequency */
2437{
2438 ush next_code[MAX_BITS+1]; /* next code value for each bit length */
2439 ush code = 0; /* running code value */
2440 int bits; /* bit index */
2441 int n; /* code index */
2442
2443 /* The distribution counts are first used to generate the code values
2444 * without bit reversal.
2445 */
2446 for (bits = 1; bits <= MAX_BITS; bits++) {
2447 next_code[bits] = code = (code + bl_count[bits-1]) << 1;
2448 }
2449 /* Check that the bit counts in bl_count are consistent. The last code
2450 * must be all ones.
2451 */
2452 Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
2453 "inconsistent bit counts");
2454 Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
2455
2456 for (n = 0; n <= max_code; n++) {
2457 int len = tree[n].Len;
2458 if (len == 0) continue;
2459 /* Now reverse the bits */
2460 tree[n].Code = bi_reverse(next_code[len]++, len);
2461
2462 Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
2463 n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
2464 }
2465}
2466
2467/* ===========================================================================
2468 * Construct one Huffman tree and assigns the code bit strings and lengths.
2469 * Update the total bit length for the current block.
2470 * IN assertion: the field freq is set for all tree elements.
2471 * OUT assertions: the fields len and code are set to the optimal bit length
2472 * and corresponding code. The length opt_len is updated; static_len is
2473 * also updated if stree is not null. The field max_code is set.
2474 */
2475local void build_tree(desc)
2476 tree_desc near *desc; /* the tree descriptor */
2477{
2478 ct_data near *tree = desc->dyn_tree;
2479 ct_data near *stree = desc->static_tree;
2480 int elems = desc->elems;
2481 int n, m; /* iterate over heap elements */
2482 int max_code = -1; /* largest code with non zero frequency */
2483 int node = elems; /* next internal node of the tree */
2484
2485 /* Construct the initial heap, with least frequent element in
2486 * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
2487 * heap[0] is not used.
2488 */
2489 heap_len = 0, heap_max = HEAP_SIZE;
2490
2491 for (n = 0; n < elems; n++) {
2492 if (tree[n].Freq != 0) {
2493 heap[++heap_len] = max_code = n;
2494 depth[n] = 0;
2495 } else {
2496 tree[n].Len = 0;
2497 }
2498 }
2499
2500 /* The pkzip format requires that at least one distance code exists,
2501 * and that at least one bit should be sent even if there is only one
2502 * possible code. So to avoid special checks later on we force at least
2503 * two codes of non zero frequency.
2504 */
2505 while (heap_len < 2) {
2506 int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
2507 tree[new].Freq = 1;
2508 depth[new] = 0;
2509 opt_len--; if (stree) static_len -= stree[new].Len;
2510 /* new is 0 or 1 so it does not have extra bits */
2511 }
2512 desc->max_code = max_code;
2513
2514 /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
2515 * establish sub-heaps of increasing lengths:
2516 */
2517 for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
2518
2519 /* Construct the Huffman tree by repeatedly combining the least two
2520 * frequent nodes.
2521 */
2522 do {
2523 pqremove(tree, n); /* n = node of least frequency */
2524 m = heap[SMALLEST]; /* m = node of next least frequency */
2525
2526 heap[--heap_max] = n; /* keep the nodes sorted by frequency */
2527 heap[--heap_max] = m;
2528
2529 /* Create a new node father of n and m */
2530 tree[node].Freq = tree[n].Freq + tree[m].Freq;
2531 depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
2532 tree[n].Dad = tree[m].Dad = (ush)node;
2533#ifdef DUMP_BL_TREE
2534 if (tree == bl_tree) {
2535 fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
2536 node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
2537 }
2538#endif
2539 /* and insert the new node in the heap */
2540 heap[SMALLEST] = node++;
2541 pqdownheap(tree, SMALLEST);
2542
2543 } while (heap_len >= 2);
2544
2545 heap[--heap_max] = heap[SMALLEST];
2546
2547 /* At this point, the fields freq and dad are set. We can now
2548 * generate the bit lengths.
2549 */
2550 gen_bitlen((tree_desc near *)desc);
2551
2552 /* The field len is now set, we can generate the bit codes */
2553 gen_codes ((ct_data near *)tree, max_code);
2554}
2555
2556/* ===========================================================================
2557 * Scan a literal or distance tree to determine the frequencies of the codes
2558 * in the bit length tree. Updates opt_len to take into account the repeat
2559 * counts. (The contribution of the bit length codes will be added later
2560 * during the construction of bl_tree.)
2561 */
2562local void scan_tree (tree, max_code)
2563 ct_data near *tree; /* the tree to be scanned */
2564 int max_code; /* and its largest code of non zero frequency */
2565{
2566 int n; /* iterates over all tree elements */
2567 int prevlen = -1; /* last emitted length */
2568 int curlen; /* length of current code */
2569 int nextlen = tree[0].Len; /* length of next code */
2570 int count = 0; /* repeat count of the current code */
2571 int max_count = 7; /* max repeat count */
2572 int min_count = 4; /* min repeat count */
2573
2574 if (nextlen == 0) max_count = 138, min_count = 3;
2575 tree[max_code+1].Len = (ush)0xffff; /* guard */
2576
2577 for (n = 0; n <= max_code; n++) {
2578 curlen = nextlen; nextlen = tree[n+1].Len;
2579 if (++count < max_count && curlen == nextlen) {
2580 continue;
2581 } else if (count < min_count) {
2582 bl_tree[curlen].Freq += count;
2583 } else if (curlen != 0) {
2584 if (curlen != prevlen) bl_tree[curlen].Freq++;
2585 bl_tree[REP_3_6].Freq++;
2586 } else if (count <= 10) {
2587 bl_tree[REPZ_3_10].Freq++;
2588 } else {
2589 bl_tree[REPZ_11_138].Freq++;
2590 }
2591 count = 0; prevlen = curlen;
2592 if (nextlen == 0) {
2593 max_count = 138, min_count = 3;
2594 } else if (curlen == nextlen) {
2595 max_count = 6, min_count = 3;
2596 } else {
2597 max_count = 7, min_count = 4;
2598 }
2599 }
2600}
2601
2602/* ===========================================================================
2603 * Send a literal or distance tree in compressed form, using the codes in
2604 * bl_tree.
2605 */
2606local void send_tree (tree, max_code)
2607 ct_data near *tree; /* the tree to be scanned */
2608 int max_code; /* and its largest code of non zero frequency */
2609{
2610 int n; /* iterates over all tree elements */
2611 int prevlen = -1; /* last emitted length */
2612 int curlen; /* length of current code */
2613 int nextlen = tree[0].Len; /* length of next code */
2614 int count = 0; /* repeat count of the current code */
2615 int max_count = 7; /* max repeat count */
2616 int min_count = 4; /* min repeat count */
2617
2618 /* tree[max_code+1].Len = -1; */ /* guard already set */
2619 if (nextlen == 0) max_count = 138, min_count = 3;
2620
2621 for (n = 0; n <= max_code; n++) {
2622 curlen = nextlen; nextlen = tree[n+1].Len;
2623 if (++count < max_count && curlen == nextlen) {
2624 continue;
2625 } else if (count < min_count) {
2626 do { send_code(curlen, bl_tree); } while (--count != 0);
2627
2628 } else if (curlen != 0) {
2629 if (curlen != prevlen) {
2630 send_code(curlen, bl_tree); count--;
2631 }
2632 Assert(count >= 3 && count <= 6, " 3_6?");
2633 send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
2634
2635 } else if (count <= 10) {
2636 send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
2637
2638 } else {
2639 send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
2640 }
2641 count = 0; prevlen = curlen;
2642 if (nextlen == 0) {
2643 max_count = 138, min_count = 3;
2644 } else if (curlen == nextlen) {
2645 max_count = 6, min_count = 3;
2646 } else {
2647 max_count = 7, min_count = 4;
2648 }
2649 }
2650}
2651
2652/* ===========================================================================
2653 * Construct the Huffman tree for the bit lengths and return the index in
2654 * bl_order of the last bit length code to send.
2655 */
2656local int build_bl_tree()
2657{
2658 int max_blindex; /* index of last bit length code of non zero freq */
2659
2660 /* Determine the bit length frequencies for literal and distance trees */
2661 scan_tree((ct_data near *)dyn_ltree, l_desc.max_code);
2662 scan_tree((ct_data near *)dyn_dtree, d_desc.max_code);
2663
2664 /* Build the bit length tree: */
2665 build_tree((tree_desc near *)(&bl_desc));
2666 /* opt_len now includes the length of the tree representations, except
2667 * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
2668 */
2669
2670 /* Determine the number of bit length codes to send. The pkzip format
2671 * requires that at least 4 bit length codes be sent. (appnote.txt says
2672 * 3 but the actual value used is 4.)
2673 */
2674 for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
2675 if (bl_tree[bl_order[max_blindex]].Len != 0) break;
2676 }
2677 /* Update opt_len to include the bit length tree and counts */
2678 opt_len += 3*(max_blindex+1) + 5+5+4;
2679 Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
2680
2681 return max_blindex;
2682}
2683
2684/* ===========================================================================
2685 * Send the header for a block using dynamic Huffman trees: the counts, the
2686 * lengths of the bit length codes, the literal tree and the distance tree.
2687 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
2688 */
2689local void send_all_trees(lcodes, dcodes, blcodes)
2690 int lcodes, dcodes, blcodes; /* number of codes for each tree */
2691{
2692 int rank; /* index in bl_order */
2693
2694 Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
2695 Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
2696 "too many codes");
2697 Tracev((stderr, "\nbl counts: "));
2698 send_bits(lcodes-257, 5); /* not +255 as stated in appnote.txt */
2699 send_bits(dcodes-1, 5);
2700 send_bits(blcodes-4, 4); /* not -3 as stated in appnote.txt */
2701 for (rank = 0; rank < blcodes; rank++) {
2702 Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
2703 send_bits(bl_tree[bl_order[rank]].Len, 3);
2704 }
2705 Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
2706
2707 send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */
2708 Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
2709
2710 send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */
2711 Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
2712}
2713
2714/* ===========================================================================
2715 * Determine the best encoding for the current block: dynamic trees, static
2716 * trees or store, and output the encoded block to the zip file. This function
2717 * returns the total compressed length for the file so far.
2718 */
2719ulg flush_block(buf, stored_len, eof)
2720 char *buf; /* input block, or NULL if too old */
2721 ulg stored_len; /* length of input block */
2722 int eof; /* true if this is the last block for a file */
2723{
2724 ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
2725 int max_blindex; /* index of last bit length code of non zero freq */
2726
2727 flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
2728
2729 /* Check if the file is ascii or binary */
2730 if (*file_type == (ush)UNKNOWN) set_file_type();
2731
2732 /* Construct the literal and distance trees */
2733 build_tree((tree_desc near *)(&l_desc));
2734 Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
2735
2736 build_tree((tree_desc near *)(&d_desc));
2737 Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
2738 /* At this point, opt_len and static_len are the total bit lengths of
2739 * the compressed block data, excluding the tree representations.
2740 */
2741
2742 /* Build the bit length tree for the above two trees, and get the index
2743 * in bl_order of the last bit length code to send.
2744 */
2745 max_blindex = build_bl_tree();
2746
2747 /* Determine the best encoding. Compute first the block length in bytes */
2748 opt_lenb = (opt_len+3+7)>>3;
2749 static_lenb = (static_len+3+7)>>3;
2750 input_len += stored_len; /* for debugging only */
2751
2752 Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
2753 opt_lenb, opt_len, static_lenb, static_len, stored_len,
2754 last_lit, last_dist));
2755
2756 if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
2757
2758 /* If compression failed and this is the first and last block,
2759 * and if the zip file can be seeked (to rewrite the local header),
2760 * the whole file is transformed into a stored file:
2761 */
2762#ifdef FORCE_METHOD
2763#else
2764 if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
2765#endif
2766 /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
2767 if (buf == (char*)0) error ("block vanished");
2768
2769 copy_block(buf, (unsigned)stored_len, 0); /* without header */
2770 compressed_len = stored_len << 3;
2771 *file_method = STORED;
2772
2773#ifdef FORCE_METHOD
2774#else
2775 } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
2776 /* 4: two words for the lengths */
2777#endif
2778 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
2779 * Otherwise we can't have processed more than WSIZE input bytes since
2780 * the last block flush, because compression would have been
2781 * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
2782 * transform a block into a stored block.
2783 */
2784 send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
2785 compressed_len = (compressed_len + 3 + 7) & ~7L;
2786 compressed_len += (stored_len + 4) << 3;
2787
2788 copy_block(buf, (unsigned)stored_len, 1); /* with header */
2789
2790#ifdef FORCE_METHOD
2791#else
2792 } else if (static_lenb == opt_lenb) {
2793#endif
2794 send_bits((STATIC_TREES<<1)+eof, 3);
2795 compress_block((ct_data near *)static_ltree, (ct_data near *)static_dtree);
2796 compressed_len += 3 + static_len;
2797 } else {
2798 send_bits((DYN_TREES<<1)+eof, 3);
2799 send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
2800 compress_block((ct_data near *)dyn_ltree, (ct_data near *)dyn_dtree);
2801 compressed_len += 3 + opt_len;
2802 }
2803 Assert (compressed_len == bits_sent, "bad compressed size");
2804 init_block();
2805
2806 if (eof) {
2807 Assert (input_len == isize, "bad input size");
2808 bi_windup();
2809 compressed_len += 7; /* align on byte boundary */
2810 }
2811 Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
2812 compressed_len-7*eof));
2813
2814 return compressed_len >> 3;
2815}
2816
2817/* ===========================================================================
2818 * Save the match info and tally the frequency counts. Return true if
2819 * the current block must be flushed.
2820 */
2821int ct_tally (dist, lc)
2822 int dist; /* distance of matched string */
2823 int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
2824{
2825 l_buf[last_lit++] = (uch)lc;
2826 if (dist == 0) {
2827 /* lc is the unmatched char */
2828 dyn_ltree[lc].Freq++;
2829 } else {
2830 /* Here, lc is the match length - MIN_MATCH */
2831 dist--; /* dist = match distance - 1 */
2832 Assert((ush)dist < (ush)MAX_DIST &&
2833 (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
2834 (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
2835
2836 dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
2837 dyn_dtree[d_code(dist)].Freq++;
2838
2839 d_buf[last_dist++] = (ush)dist;
2840 flags |= flag_bit;
2841 }
2842 flag_bit <<= 1;
2843
2844 /* Output the flags if they fill a byte: */
2845 if ((last_lit & 7) == 0) {
2846 flag_buf[last_flags++] = flags;
2847 flags = 0, flag_bit = 1;
2848 }
2849 /* Try to guess if it is profitable to stop the current block here */
2850 if ((last_lit & 0xfff) == 0) {
2851 /* Compute an upper bound for the compressed length */
2852 ulg out_length = (ulg)last_lit*8L;
2853 ulg in_length = (ulg)strstart-block_start;
2854 int dcode;
2855 for (dcode = 0; dcode < D_CODES; dcode++) {
2856 out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
2857 }
2858 out_length >>= 3;
2859 Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
2860 last_lit, last_dist, in_length, out_length,
2861 100L - out_length*100L/in_length));
2862 if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
2863 }
2864 return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
2865 /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
2866 * on 16 bit machines and because stored blocks are restricted to
2867 * 64K-1 bytes.
2868 */
2869}
2870
2871/* ===========================================================================
2872 * Send the block data compressed using the given Huffman trees
2873 */
2874local void compress_block(ltree, dtree)
2875 ct_data near *ltree; /* literal tree */
2876 ct_data near *dtree; /* distance tree */
2877{
2878 unsigned dist; /* distance of matched string */
2879 int lc; /* match length or unmatched char (if dist == 0) */
2880 unsigned lx = 0; /* running index in l_buf */
2881 unsigned dx = 0; /* running index in d_buf */
2882 unsigned fx = 0; /* running index in flag_buf */
2883 uch flag = 0; /* current flags */
2884 unsigned code; /* the code to send */
2885 int extra; /* number of extra bits to send */
2886
2887 if (last_lit != 0) do {
2888 if ((lx & 7) == 0) flag = flag_buf[fx++];
2889 lc = l_buf[lx++];
2890 if ((flag & 1) == 0) {
2891 send_code(lc, ltree); /* send a literal byte */
2892 Tracecv(isgraph(lc), (stderr," '%c' ", lc));
2893 } else {
2894 /* Here, lc is the match length - MIN_MATCH */
2895 code = length_code[lc];
2896 send_code(code+LITERALS+1, ltree); /* send the length code */
2897 extra = extra_lbits[code];
2898 if (extra != 0) {
2899 lc -= base_length[code];
2900 send_bits(lc, extra); /* send the extra length bits */
2901 }
2902 dist = d_buf[dx++];
2903 /* Here, dist is the match distance - 1 */
2904 code = d_code(dist);
2905 Assert (code < D_CODES, "bad d_code");
2906
2907 send_code(code, dtree); /* send the distance code */
2908 extra = extra_dbits[code];
2909 if (extra != 0) {
2910 dist -= base_dist[code];
2911 send_bits(dist, extra); /* send the extra distance bits */
2912 }
2913 } /* literal or match pair ? */
2914 flag >>= 1;
2915 } while (lx < last_lit);
2916
2917 send_code(END_BLOCK, ltree);
2918}
2919
2920/* ===========================================================================
2921 * Set the file type to ASCII or BINARY, using a crude approximation:
2922 * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
2923 * IN assertion: the fields freq of dyn_ltree are set and the total of all
2924 * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
2925 */
2926local void set_file_type()
2927{
2928 int n = 0;
2929 unsigned ascii_freq = 0;
2930 unsigned bin_freq = 0;
2931 while (n < 7) bin_freq += dyn_ltree[n++].Freq;
2932 while (n < 128) ascii_freq += dyn_ltree[n++].Freq;
2933 while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
2934 *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
2935 if (*file_type == BINARY && translate_eol) {
2936 warn("-l used on binary file", "");
2937 }
2938}
2939/* util.c -- utility functions for gzip support
2940 * Copyright (C) 1992-1993 Jean-loup Gailly
2941 * This is free software; you can redistribute it and/or modify it under the
2942 * terms of the GNU General Public License, see the file COPYING.
2943 */
2944
2945#ifdef RCSID
2946static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
2947#endif
2948
2949#include <ctype.h>
2950#include <errno.h>
2951#include <sys/types.h>
2952
2953#ifdef HAVE_UNISTD_H
2954# include <unistd.h>
2955#endif
2956#ifndef NO_FCNTL_H
2957# include <fcntl.h>
2958#endif
2959
2960#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
2961# include <stdlib.h>
2962#else
2963 extern int errno;
2964#endif
2965
2966extern ulg crc_32_tab[]; /* crc table, defined below */
2967
2968/* ===========================================================================
2969 * Copy input to output unchanged: zcat == cat with --force.
2970 * IN assertion: insize bytes have already been read in inbuf.
2971 */
2972int copy(in, out)
2973 int in, out; /* input and output file descriptors */
2974{
2975 errno = 0;
2976 while (insize != 0 && (int)insize != EOF) {
2977 write_buf(out, (char*)inbuf, insize);
2978 bytes_out += insize;
2979 insize = read(in, (char*)inbuf, INBUFSIZ);
2980 }
2981 if ((int)insize == EOF && errno != 0) {
2982 read_error();
2983 }
2984 bytes_in = bytes_out;
2985 return OK;
2986}
2987
2988/* ========================================================================
2989 * Put string s in lower case, return s.
2990 */
2991char *strlwr(s)
2992 char *s;
2993{
2994 char *t;
2995 for (t = s; *t; t++) *t = tolow(*t);
2996 return s;
2997}
2998
2999#if defined(NO_STRING_H) && !defined(STDC_HEADERS)
3000
3001/* Provide missing strspn and strcspn functions. */
3002
3003# ifndef __STDC__
3004# define const
3005# endif
3006
3007int strspn OF((const char *s, const char *accept));
3008int strcspn OF((const char *s, const char *reject));
3009
3010/* ========================================================================
3011 * Return the length of the maximum initial segment
3012 * of s which contains only characters in accept.
3013 */
3014int strspn(s, accept)
3015 const char *s;
3016 const char *accept;
3017{
3018 register const char *p;
3019 register const char *a;
3020 register int count = 0;
3021
3022 for (p = s; *p != '\0'; ++p) {
3023 for (a = accept; *a != '\0'; ++a) {
3024 if (*p == *a) break;
3025 }
3026 if (*a == '\0') return count;
3027 ++count;
3028 }
3029 return count;
3030}
3031
3032/* ========================================================================
3033 * Return the length of the maximum inital segment of s
3034 * which contains no characters from reject.
3035 */
3036int strcspn(s, reject)
3037 const char *s;
3038 const char *reject;
3039{
3040 register int count = 0;
3041
3042 while (*s != '\0') {
3043 if (strchr(reject, *s++) != NULL) return count;
3044 ++count;
3045 }
3046 return count;
3047}
3048
3049#endif /* NO_STRING_H */
3050
3051/* ========================================================================
3052 * Add an environment variable (if any) before argv, and update argc.
3053 * Return the expanded environment variable to be freed later, or NULL
3054 * if no options were added to argv.
3055 */
3056#define SEPARATOR " \t" /* separators in env variable */
3057
3058char *add_envopt(argcp, argvp, env)
3059 int *argcp; /* pointer to argc */
3060 char ***argvp; /* pointer to argv */
3061 char *env; /* name of environment variable */
3062{
3063 char *p; /* running pointer through env variable */
3064 char **oargv; /* runs through old argv array */
3065 char **nargv; /* runs through new argv array */
3066 int oargc = *argcp; /* old argc */
3067 int nargc = 0; /* number of arguments in env variable */
3068
3069 env = (char*)getenv(env);
3070 if (env == NULL) return NULL;
3071
3072 p = (char*)xmalloc(strlen(env)+1);
3073 env = strcpy(p, env); /* keep env variable intact */
3074
3075 for (p = env; *p; nargc++ ) { /* move through env */
3076 p += strspn(p, SEPARATOR); /* skip leading separators */
3077 if (*p == '\0') break;
3078
3079 p += strcspn(p, SEPARATOR); /* find end of word */
3080 if (*p) *p++ = '\0'; /* mark it */
3081 }
3082 if (nargc == 0) {
3083 free(env);
3084 return NULL;
3085 }
3086 *argcp += nargc;
3087 /* Allocate the new argv array, with an extra element just in case
3088 * the original arg list did not end with a NULL.
3089 */
3090 nargv = (char**)calloc(*argcp+1, sizeof(char *));
3091 if (nargv == NULL) error("out of memory");
3092 oargv = *argvp;
3093 *argvp = nargv;
3094
3095 /* Copy the program name first */
3096 if (oargc-- < 0) error("argc<=0");
3097 *(nargv++) = *(oargv++);
3098
3099 /* Then copy the environment args */
3100 for (p = env; nargc > 0; nargc--) {
3101 p += strspn(p, SEPARATOR); /* skip separators */
3102 *(nargv++) = p; /* store start */
3103 while (*p++) ; /* skip over word */
3104 }
3105
3106 /* Finally copy the old args and add a NULL (usual convention) */
3107 while (oargc--) *(nargv++) = *(oargv++);
3108 *nargv = NULL;
3109 return env;
3110}
3111/* ========================================================================
3112 * Display compression ratio on the given stream on 6 characters.
3113 */
3114void display_ratio(num, den, file)
3115 long num;
3116 long den;
3117 FILE *file;
3118{
3119 long ratio; /* 1000 times the compression ratio */
3120
3121 if (den == 0) {
3122 ratio = 0; /* no compression */
3123 } else if (den < 2147483L) { /* (2**31 -1)/1000 */
3124 ratio = 1000L*num/den;
3125 } else {
3126 ratio = num/(den/1000L);
3127 }
3128 if (ratio < 0) {
3129 putc('-', file);
3130 ratio = -ratio;
3131 } else {
3132 putc(' ', file);
3133 }
3134 fprintf(file, "%2ld.%1ld%%", ratio / 10L, ratio % 10L);
3135}
3136
3137
3138/* zip.c -- compress files to the gzip or pkzip format
3139 * Copyright (C) 1992-1993 Jean-loup Gailly
3140 * This is free software; you can redistribute it and/or modify it under the
3141 * terms of the GNU General Public License, see the file COPYING.
3142 */
3143
3144#ifdef RCSID
3145static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
3146#endif
3147
3148#include <ctype.h>
3149#include <sys/types.h>
3150
3151#ifdef HAVE_UNISTD_H
3152# include <unistd.h>
3153#endif
3154#ifndef NO_FCNTL_H
3155# include <fcntl.h>
3156#endif
3157
3158local ulg crc; /* crc on uncompressed file data */
3159long header_bytes; /* number of bytes in gzip header */
3160
3161/* ===========================================================================
3162 * Deflate in to out.
3163 * IN assertions: the input and output buffers are cleared.
3164 * The variables time_stamp and save_orig_name are initialized.
3165 */
3166int zip(in, out)
3167 int in, out; /* input and output file descriptors */
3168{
3169 uch flags = 0; /* general purpose bit flags */
3170 ush attr = 0; /* ascii/binary flag */
3171 ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
3172
3173 ifd = in;
3174 ofd = out;
3175 outcnt = 0;
3176
3177 /* Write the header to the gzip file. See algorithm.doc for the format */
3178
3179 method = DEFLATED;
3180 put_byte(GZIP_MAGIC[0]); /* magic header */
3181 put_byte(GZIP_MAGIC[1]);
3182 put_byte(DEFLATED); /* compression method */
3183
3184 put_byte(flags); /* general flags */
3185 put_long(time_stamp);
3186
3187 /* Write deflated file to zip file */
3188 crc = updcrc(0, 0);
3189
3190 bi_init(out);
3191 ct_init(&attr, &method);
3192 lm_init(&deflate_flags);
3193
3194 put_byte((uch)deflate_flags); /* extra flags */
3195 put_byte(OS_CODE); /* OS identifier */
3196
3197 header_bytes = (long)outcnt;
3198
3199 (void)deflate();
3200
3201 /* Write the crc and uncompressed size */
3202 put_long(crc);
3203 put_long(isize);
3204 header_bytes += 2*sizeof(long);
3205
3206 flush_outbuf();
3207 return OK;
3208}
3209
3210
3211/* ===========================================================================
3212 * Read a new buffer from the current input file, perform end-of-line
3213 * translation, and update the crc and input file size.
3214 * IN assertion: size >= 2 (for end-of-line translation)
3215 */
3216int file_read(buf, size)
3217 char *buf;
3218 unsigned size;
3219{
3220 unsigned len;
3221
3222 Assert(insize == 0, "inbuf not empty");
3223
3224 len = read(ifd, buf, size);
3225 if (len == (unsigned)(-1) || len == 0) return (int)len;
3226
3227 crc = updcrc((uch*)buf, len);
3228 isize += (ulg)len;
3229 return (int)len;
3230}
3231#endif
diff --git a/archival/tar.c b/archival/tar.c
new file mode 100644
index 000000000..03da96735
--- /dev/null
+++ b/archival/tar.c
@@ -0,0 +1,1425 @@
1/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "tar" command, taken from sash.
7 * This allows creation, extraction, and listing of tar files.
8 *
9 * Permission to distribute this code under the GPL has been granted.
10 * Modified for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
11 */
12
13
14#include "internal.h"
15
16#ifdef BB_TAR
17
18const char tar_usage[] =
19"Create, extract, or list files from a TAR file\n\n"
20"usage: tar -[cxtvOf] [tarFileName] [FILE] ...\n"
21"\tc=create, x=extract, t=list contents, v=verbose,\n"
22"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
23
24
25
26#include <stdio.h>
27#include <dirent.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <signal.h>
31#include <time.h>
32
33/*
34 * Tar file constants.
35 */
36#define TAR_BLOCK_SIZE 512
37#define TAR_NAME_SIZE 100
38
39
40/*
41 * The POSIX (and basic GNU) tar header format.
42 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
43 * with zero padding. We only process this information minimally.
44 */
45typedef struct
46{
47 char name[TAR_NAME_SIZE];
48 char mode[8];
49 char uid[8];
50 char gid[8];
51 char size[12];
52 char mtime[12];
53 char checkSum[8];
54 char typeFlag;
55 char linkName[TAR_NAME_SIZE];
56 char magic[6];
57 char version[2];
58 char uname[32];
59 char gname[32];
60 char devMajor[8];
61 char devMinor[8];
62 char prefix[155];
63} TarHeader;
64
65#define TAR_MAGIC "ustar"
66#define TAR_VERSION "00"
67
68#define TAR_TYPE_REGULAR '0'
69#define TAR_TYPE_HARD_LINK '1'
70#define TAR_TYPE_SOFT_LINK '2'
71
72
73/*
74 * Static data.
75 */
76static BOOL listFlag;
77static BOOL extractFlag;
78static BOOL createFlag;
79static BOOL verboseFlag;
80static BOOL tostdoutFlag;
81
82static BOOL inHeader;
83static BOOL badHeader;
84static BOOL errorFlag;
85static BOOL skipFileFlag;
86static BOOL warnedRoot;
87static BOOL eofFlag;
88static long dataCc;
89static int outFd;
90static char outName[TAR_NAME_SIZE];
91
92
93/*
94 * Static data associated with the tar file.
95 */
96static const char * tarName;
97static int tarFd;
98static dev_t tarDev;
99static ino_t tarInode;
100
101
102/*
103 * Local procedures to restore files from a tar file.
104 */
105static void readTarFile(int fileCount, char ** fileTable);
106static void readData(const char * cp, int count);
107static void createPath(const char * name, int mode);
108static long getOctal(const char * cp, int len);
109
110static void readHeader(const TarHeader * hp,
111 int fileCount, char ** fileTable);
112
113
114/*
115 * Local procedures to save files into a tar file.
116 */
117static void saveFile(const char * fileName, BOOL seeLinks);
118
119static void saveRegularFile(const char * fileName,
120 const struct stat * statbuf);
121
122static void saveDirectory(const char * fileName,
123 const struct stat * statbuf);
124
125static BOOL wantFileName(const char * fileName,
126 int fileCount, char ** fileTable);
127
128static void writeHeader(const char * fileName,
129 const struct stat * statbuf);
130
131static void writeTarFile(int fileCount, char ** fileTable);
132static void writeTarBlock(const char * buf, int len);
133static BOOL putOctal(char * cp, int len, long value);
134extern const char * modeString(int mode);
135extern const char * timeString(time_t timeVal);
136extern int fullWrite(int fd, const char * buf, int len);
137extern int fullRead(int fd, char * buf, int len);
138
139
140extern int
141tar_main(struct FileInfo *unused, int argc, char ** argv)
142{
143 const char * options;
144
145 argc--;
146 argv++;
147
148 if (argc < 1)
149 {
150 fprintf(stderr, "%s", tar_usage);
151 return 1;
152 }
153
154
155 errorFlag = FALSE;
156 extractFlag = FALSE;
157 createFlag = FALSE;
158 listFlag = FALSE;
159 verboseFlag = FALSE;
160 tostdoutFlag = FALSE;
161 tarName = NULL;
162 tarDev = 0;
163 tarInode = 0;
164 tarFd = -1;
165
166 /*
167 * Parse the options.
168 */
169 options = *argv++;
170 argc--;
171
172 if (**argv == '-') {
173 for (; *options; options++)
174 {
175 switch (*options)
176 {
177 case 'f':
178 if (tarName != NULL)
179 {
180 fprintf(stderr, "Only one 'f' option allowed\n");
181
182 return 1;
183 }
184
185 tarName = *argv++;
186 argc--;
187
188 break;
189
190 case 't':
191 listFlag = TRUE;
192 break;
193
194 case 'x':
195 extractFlag = TRUE;
196 break;
197
198 case 'c':
199 createFlag = TRUE;
200 break;
201
202 case 'v':
203 verboseFlag = TRUE;
204 break;
205
206 case 'O':
207 tostdoutFlag = TRUE;
208 break;
209
210 case '-':
211 break;
212
213 default:
214 fprintf(stderr, "Unknown tar flag '%c'\n", *options);
215
216 return 1;
217 }
218 }
219 }
220
221 /*
222 * Validate the options.
223 */
224 if (extractFlag + listFlag + createFlag != 1)
225 {
226 fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
227
228 return 1;
229 }
230
231 /*
232 * Do the correct type of action supplying the rest of the
233 * command line arguments as the list of files to process.
234 */
235 if (createFlag)
236 writeTarFile(argc, argv);
237 else
238 readTarFile(argc, argv);
239 if (errorFlag)
240 fprintf(stderr, "\n");
241 return( errorFlag);
242}
243
244
245/*
246 * Read a tar file and extract or list the specified files within it.
247 * If the list is empty than all files are extracted or listed.
248 */
249static void
250readTarFile(int fileCount, char ** fileTable)
251{
252 const char * cp;
253 int cc;
254 int inCc;
255 int blockSize;
256 char buf[BUF_SIZE];
257
258 skipFileFlag = FALSE;
259 badHeader = FALSE;
260 warnedRoot = FALSE;
261 eofFlag = FALSE;
262 inHeader = TRUE;
263 inCc = 0;
264 dataCc = 0;
265 outFd = -1;
266 blockSize = sizeof(buf);
267 cp = buf;
268
269 /*
270 * Open the tar file for reading.
271 */
272 if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
273 tarFd = STDIN;
274 }
275 else
276 tarFd = open(tarName, O_RDONLY);
277
278 if (tarFd < 0)
279 {
280 perror(tarName);
281 errorFlag = TRUE;
282 return;
283 }
284
285 /*
286 * Read blocks from the file until an end of file header block
287 * has been seen. (A real end of file from a read is an error.)
288 */
289 while (!eofFlag)
290 {
291 /*
292 * Read the next block of data if necessary.
293 * This will be a large block if possible, which we will
294 * then process in the small tar blocks.
295 */
296 if (inCc <= 0)
297 {
298 cp = buf;
299 inCc = fullRead(tarFd, buf, blockSize);
300
301 if (inCc < 0)
302 {
303 perror(tarName);
304 errorFlag=TRUE;
305 goto done;
306 }
307
308 if (inCc == 0)
309 {
310 fprintf(stderr,
311 "Unexpected end of file from \"%s\"",
312 tarName);
313 errorFlag=TRUE;
314 goto done;
315 }
316 }
317
318 /*
319 * If we are expecting a header block then examine it.
320 */
321 if (inHeader)
322 {
323 readHeader((const TarHeader *) cp, fileCount, fileTable);
324
325 cp += TAR_BLOCK_SIZE;
326 inCc -= TAR_BLOCK_SIZE;
327
328 continue;
329 }
330
331 /*
332 * We are currently handling the data for a file.
333 * Process the minimum of the amount of data we have available
334 * and the amount left to be processed for the file.
335 */
336 cc = inCc;
337
338 if (cc > dataCc)
339 cc = dataCc;
340
341 readData(cp, cc);
342
343 /*
344 * If the amount left isn't an exact multiple of the tar block
345 * size then round it up to the next block boundary since there
346 * is padding at the end of the file.
347 */
348 if (cc % TAR_BLOCK_SIZE)
349 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
350
351 cp += cc;
352 inCc -= cc;
353 }
354
355done:
356 /*
357 * Close the tar file if needed.
358 */
359 if ((tarFd >= 0) && (close(tarFd) < 0))
360 perror(tarName);
361
362 /*
363 * Close the output file if needed.
364 * This is only done here on a previous error and so no
365 * message is required on errors.
366 */
367 if (tostdoutFlag==FALSE) {
368 if (outFd >= 0)
369 (void) close(outFd);
370 }
371}
372
373
374/*
375 * Examine the header block that was just read.
376 * This can specify the information for another file, or it can mark
377 * the end of the tar file.
378 */
379static void
380readHeader(const TarHeader * hp, int fileCount, char ** fileTable)
381{
382 int mode;
383 int uid;
384 int gid;
385 int checkSum;
386 long size;
387 time_t mtime;
388 const char * name;
389 int cc;
390 BOOL hardLink;
391 BOOL softLink;
392
393 /*
394 * If the block is completely empty, then this is the end of the
395 * archive file. If the name is null, then just skip this header.
396 */
397 name = hp->name;
398
399 if (*name == '\0')
400 {
401 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
402 {
403 if (*name++)
404 return;
405 }
406
407 eofFlag = TRUE;
408
409 return;
410 }
411
412 /*
413 * There is another file in the archive to examine.
414 * Extract the encoded information and check it.
415 */
416 mode = getOctal(hp->mode, sizeof(hp->mode));
417 uid = getOctal(hp->uid, sizeof(hp->uid));
418 gid = getOctal(hp->gid, sizeof(hp->gid));
419 size = getOctal(hp->size, sizeof(hp->size));
420 mtime = getOctal(hp->mtime, sizeof(hp->mtime));
421 checkSum = getOctal(hp->checkSum, sizeof(hp->checkSum));
422
423 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
424 {
425 if (!badHeader)
426 fprintf(stderr, "Bad tar header, skipping\n");
427
428 badHeader = TRUE;
429
430 return;
431 }
432
433 badHeader = FALSE;
434 skipFileFlag = FALSE;
435
436 /*
437 * Check for the file modes.
438 */
439 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
440 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
441
442 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
443 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
444
445 /*
446 * Check for a directory or a regular file.
447 */
448 if (name[strlen(name) - 1] == '/')
449 mode |= S_IFDIR;
450 else if ((mode & S_IFMT) == 0)
451 mode |= S_IFREG;
452
453 /*
454 * Check for absolute paths in the file.
455 * If we find any, then warn the user and make them relative.
456 */
457 if (*name == '/')
458 {
459 while (*name == '/')
460 name++;
461
462 if (!warnedRoot)
463 {
464 fprintf(stderr,
465 "Absolute path detected, removing leading slashes\n");
466 }
467
468 warnedRoot = TRUE;
469 }
470
471 /*
472 * See if we want this file to be restored.
473 * If not, then set up to skip it.
474 */
475 if (!wantFileName(name, fileCount, fileTable))
476 {
477 if (!hardLink && !softLink && S_ISREG(mode))
478 {
479 inHeader = (size == 0);
480 dataCc = size;
481 }
482
483 skipFileFlag = TRUE;
484
485 return;
486 }
487
488 /*
489 * This file is to be handled.
490 * If we aren't extracting then just list information about the file.
491 */
492 if (!extractFlag)
493 {
494 if (verboseFlag)
495 {
496 printf("%s %3d/%-d %9ld %s %s", modeString(mode),
497 uid, gid, size, timeString(mtime), name);
498 }
499 else
500 printf("%s", name);
501
502 if (hardLink)
503 printf(" (link to \"%s\")", hp->linkName);
504 else if (softLink)
505 printf(" (symlink to \"%s\")", hp->linkName);
506 else if (S_ISREG(mode))
507 {
508 inHeader = (size == 0);
509 dataCc = size;
510 }
511
512 printf("\n");
513
514 return;
515 }
516
517 /*
518 * We really want to extract the file.
519 */
520 if (verboseFlag)
521 printf("x %s\n", name);
522
523 if (hardLink)
524 {
525 if (link(hp->linkName, name) < 0)
526 perror(name);
527
528 return;
529 }
530
531 if (softLink)
532 {
533#ifdef S_ISLNK
534 if (symlink(hp->linkName, name) < 0)
535 perror(name);
536#else
537 fprintf(stderr, "Cannot create symbolic links\n");
538#endif
539 return;
540 }
541
542 /*
543 * If the file is a directory, then just create the path.
544 */
545 if (S_ISDIR(mode))
546 {
547 createPath(name, mode);
548
549 return;
550 }
551
552 /*
553 * There is a file to write.
554 * First create the path to it if necessary with a default permission.
555 */
556 createPath(name, 0777);
557
558 inHeader = (size == 0);
559 dataCc = size;
560
561 /*
562 * Start the output file.
563 */
564 if (tostdoutFlag==TRUE)
565 outFd = STDOUT;
566 else
567 outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
568
569 if (outFd < 0)
570 {
571 perror(name);
572 skipFileFlag = TRUE;
573 return;
574 }
575
576 /*
577 * If the file is empty, then that's all we need to do.
578 */
579 if (size == 0 && tostdoutFlag == FALSE)
580 {
581 (void) close(outFd);
582 outFd = -1;
583 }
584}
585
586
587/*
588 * Handle a data block of some specified size that was read.
589 */
590static void
591readData(const char * cp, int count)
592{
593 /*
594 * Reduce the amount of data left in this file.
595 * If there is no more data left, then we need to read
596 * the header again.
597 */
598 dataCc -= count;
599
600 if (dataCc <= 0)
601 inHeader = TRUE;
602
603 /*
604 * If we aren't extracting files or this file is being
605 * skipped then do nothing more.
606 */
607 if (!extractFlag || skipFileFlag)
608 return;
609
610 /*
611 * Write the data to the output file.
612 */
613 if (fullWrite(outFd, cp, count) < 0)
614 {
615 perror(outName);
616 if (tostdoutFlag==FALSE) {
617 (void) close(outFd);
618 outFd = -1;
619 }
620 skipFileFlag = TRUE;
621 return;
622 }
623
624 /*
625 * If the write failed, close the file and disable further
626 * writes to this file.
627 */
628 if (dataCc <= 0 && tostdoutFlag==FALSE)
629 {
630 if (close(outFd))
631 perror(outName);
632
633 outFd = -1;
634 }
635}
636
637
638/*
639 * Write a tar file containing the specified files.
640 */
641static void
642writeTarFile(int fileCount, char ** fileTable)
643{
644 struct stat statbuf;
645
646 /*
647 * Make sure there is at least one file specified.
648 */
649 if (fileCount <= 0)
650 {
651 fprintf(stderr, "No files specified to be saved\n");
652 errorFlag=TRUE;
653 }
654
655 /*
656 * Create the tar file for writing.
657 */
658 if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
659 tostdoutFlag = TRUE;
660 tarFd = STDOUT;
661 }
662 else
663 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
664
665 if (tarFd < 0)
666 {
667 perror(tarName);
668 errorFlag=TRUE;
669 return;
670 }
671
672 /*
673 * Get the device and inode of the tar file for checking later.
674 */
675 if (fstat(tarFd, &statbuf) < 0)
676 {
677 perror(tarName);
678 errorFlag = TRUE;
679 goto done;
680 }
681
682 tarDev = statbuf.st_dev;
683 tarInode = statbuf.st_ino;
684
685 /*
686 * Append each file name into the archive file.
687 * Follow symbolic links for these top level file names.
688 */
689 while (!errorFlag && (fileCount-- > 0))
690 {
691 saveFile(*fileTable++, FALSE);
692 }
693
694 /*
695 * Now write an empty block of zeroes to end the archive.
696 */
697 writeTarBlock("", 1);
698
699
700done:
701 /*
702 * Close the tar file and check for errors if it was opened.
703 */
704 if ( (tostdoutFlag==FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
705 perror(tarName);
706}
707
708
709/*
710 * Save one file into the tar file.
711 * If the file is a directory, then this will recursively save all of
712 * the files and directories within the directory. The seeLinks
713 * flag indicates whether or not we want to see symbolic links as
714 * they really are, instead of blindly following them.
715 */
716static void
717saveFile(const char * fileName, BOOL seeLinks)
718{
719 int status;
720 int mode;
721 struct stat statbuf;
722
723 if (verboseFlag)
724 printf("a %s\n", fileName);
725
726 /*
727 * Check that the file name will fit in the header.
728 */
729 if (strlen(fileName) >= TAR_NAME_SIZE)
730 {
731 fprintf(stderr, "%s: File name is too long\n", fileName);
732
733 return;
734 }
735
736 /*
737 * Find out about the file.
738 */
739#ifdef S_ISLNK
740 if (seeLinks)
741 status = lstat(fileName, &statbuf);
742 else
743#endif
744 status = stat(fileName, &statbuf);
745
746 if (status < 0)
747 {
748 perror(fileName);
749
750 return;
751 }
752
753 /*
754 * Make sure we aren't trying to save our file into itself.
755 */
756 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode))
757 {
758 fprintf(stderr, "Skipping saving of archive file itself\n");
759
760 return;
761 }
762
763 /*
764 * Check the type of file.
765 */
766 mode = statbuf.st_mode;
767
768 if (S_ISDIR(mode))
769 {
770 saveDirectory(fileName, &statbuf);
771
772 return;
773 }
774
775 if (S_ISREG(mode))
776 {
777 saveRegularFile(fileName, &statbuf);
778
779 return;
780 }
781
782 /*
783 * The file is a strange type of file, ignore it.
784 */
785 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
786}
787
788
789/*
790 * Save a regular file to the tar file.
791 */
792static void
793saveRegularFile(const char * fileName, const struct stat * statbuf)
794{
795 BOOL sawEof;
796 int fileFd;
797 int cc;
798 int dataCount;
799 long fullDataCount;
800 char data[TAR_BLOCK_SIZE * 16];
801
802 /*
803 * Open the file for reading.
804 */
805 fileFd = open(fileName, O_RDONLY);
806
807 if (fileFd < 0)
808 {
809 perror(fileName);
810
811 return;
812 }
813
814 /*
815 * Write out the header for the file.
816 */
817 writeHeader(fileName, statbuf);
818
819 /*
820 * Write the data blocks of the file.
821 * We must be careful to write the amount of data that the stat
822 * buffer indicated, even if the file has changed size. Otherwise
823 * the tar file will be incorrect.
824 */
825 fullDataCount = statbuf->st_size;
826 sawEof = FALSE;
827
828 while (fullDataCount > 0)
829 {
830 /*
831 * Get the amount to write this iteration which is
832 * the minumum of the amount left to write and the
833 * buffer size.
834 */
835 dataCount = sizeof(data);
836
837 if (dataCount > fullDataCount)
838 dataCount = (int) fullDataCount;
839
840 /*
841 * Read the data from the file if we haven't seen the
842 * end of file yet.
843 */
844 cc = 0;
845
846 if (!sawEof)
847 {
848 cc = fullRead(fileFd, data, dataCount);
849
850 if (cc < 0)
851 {
852 perror(fileName);
853
854 (void) close(fileFd);
855 errorFlag = TRUE;
856
857 return;
858 }
859
860 /*
861 * If the file ended too soon, complain and set
862 * a flag so we will zero fill the rest of it.
863 */
864 if (cc < dataCount)
865 {
866 fprintf(stderr,
867 "%s: Short read - zero filling",
868 fileName);
869
870 sawEof = TRUE;
871 }
872 }
873
874 /*
875 * Zero fill the rest of the data if necessary.
876 */
877 if (cc < dataCount)
878 memset(data + cc, 0, dataCount - cc);
879
880 /*
881 * Write the buffer to the TAR file.
882 */
883 writeTarBlock(data, dataCount);
884
885 fullDataCount -= dataCount;
886 }
887
888 /*
889 * Close the file.
890 */
891 if ( (tostdoutFlag==FALSE) && close(fileFd) < 0)
892 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
893}
894
895
896/*
897 * Save a directory and all of its files to the tar file.
898 */
899static void
900saveDirectory(const char * dirName, const struct stat * statbuf)
901{
902 DIR * dir;
903 struct dirent * entry;
904 BOOL needSlash;
905 char fullName[PATH_LEN];
906
907 /*
908 * Construct the directory name as used in the tar file by appending
909 * a slash character to it.
910 */
911 strcpy(fullName, dirName);
912 strcat(fullName, "/");
913
914 /*
915 * Write out the header for the directory entry.
916 */
917 writeHeader(fullName, statbuf);
918
919 /*
920 * Open the directory.
921 */
922 dir = opendir(dirName);
923
924 if (dir == NULL)
925 {
926 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
927 dirName, strerror(errno));
928
929 return;
930 }
931
932 /*
933 * See if a slash is needed.
934 */
935 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
936
937 /*
938 * Read all of the directory entries and check them,
939 * except for the current and parent directory entries.
940 */
941 while (!errorFlag && ((entry = readdir(dir)) != NULL))
942 {
943 if ((strcmp(entry->d_name, ".") == 0) ||
944 (strcmp(entry->d_name, "..") == 0))
945 {
946 continue;
947 }
948
949 /*
950 * Build the full path name to the file.
951 */
952 strcpy(fullName, dirName);
953
954 if (needSlash)
955 strcat(fullName, "/");
956
957 strcat(fullName, entry->d_name);
958
959 /*
960 * Write this file to the tar file, noticing whether or not
961 * the file is a symbolic link.
962 */
963 saveFile(fullName, TRUE);
964 }
965
966 /*
967 * All done, close the directory.
968 */
969 closedir(dir);
970}
971
972
973/*
974 * Write a tar header for the specified file name and status.
975 * It is assumed that the file name fits.
976 */
977static void
978writeHeader(const char * fileName, const struct stat * statbuf)
979{
980 long checkSum;
981 const unsigned char * cp;
982 int len;
983 TarHeader header;
984
985 /*
986 * Zero the header block in preparation for filling it in.
987 */
988 memset((char *) &header, 0, sizeof(header));
989
990 /*
991 * Fill in the header.
992 */
993 strcpy(header.name, fileName);
994
995 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
996 strncpy(header.version, TAR_VERSION, sizeof(header.version));
997
998 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
999 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1000 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1001 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1002 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
1003
1004 header.typeFlag = TAR_TYPE_REGULAR;
1005
1006 /*
1007 * Calculate and store the checksum.
1008 * This is the sum of all of the bytes of the header,
1009 * with the checksum field itself treated as blanks.
1010 */
1011 memset(header.checkSum, ' ', sizeof(header.checkSum));
1012
1013 cp = (const unsigned char *) &header;
1014 len = sizeof(header);
1015 checkSum = 0;
1016
1017 while (len-- > 0)
1018 checkSum += *cp++;
1019
1020 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
1021
1022 /*
1023 * Write the tar header.
1024 */
1025 writeTarBlock((const char *) &header, sizeof(header));
1026}
1027
1028
1029/*
1030 * Write data to one or more blocks of the tar file.
1031 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1032 * The errorFlag static variable is set on an error.
1033 */
1034static void
1035writeTarBlock(const char * buf, int len)
1036{
1037 int partialLength;
1038 int completeLength;
1039 char fullBlock[TAR_BLOCK_SIZE];
1040
1041 /*
1042 * If we had a write error before, then do nothing more.
1043 */
1044 if (errorFlag)
1045 return;
1046
1047 /*
1048 * Get the amount of complete and partial blocks.
1049 */
1050 partialLength = len % TAR_BLOCK_SIZE;
1051 completeLength = len - partialLength;
1052
1053 /*
1054 * Write all of the complete blocks.
1055 */
1056 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength))
1057 {
1058 perror(tarName);
1059
1060 errorFlag = TRUE;
1061
1062 return;
1063 }
1064
1065 /*
1066 * If there are no partial blocks left, we are done.
1067 */
1068 if (partialLength == 0)
1069 return;
1070
1071 /*
1072 * Copy the partial data into a complete block, and pad the rest
1073 * of it with zeroes.
1074 */
1075 memcpy(fullBlock, buf + completeLength, partialLength);
1076 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1077
1078 /*
1079 * Write the last complete block.
1080 */
1081 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE))
1082 {
1083 perror(tarName);
1084
1085 errorFlag = TRUE;
1086 }
1087}
1088
1089
1090/*
1091 * Attempt to create the directories along the specified path, except for
1092 * the final component. The mode is given for the final directory only,
1093 * while all previous ones get default protections. Errors are not reported
1094 * here, as failures to restore files can be reported later.
1095 */
1096static void
1097createPath(const char * name, int mode)
1098{
1099 char * cp;
1100 char * cpOld;
1101 char buf[TAR_NAME_SIZE];
1102
1103 strcpy(buf, name);
1104
1105 cp = strchr(buf, '/');
1106
1107 while (cp)
1108 {
1109 cpOld = cp;
1110 cp = strchr(cp + 1, '/');
1111
1112 *cpOld = '\0';
1113
1114 if (mkdir(buf, cp ? 0777 : mode) == 0)
1115 printf("Directory \"%s\" created\n", buf);
1116
1117 *cpOld = '/';
1118 }
1119}
1120
1121
1122/*
1123 * Read an octal value in a field of the specified width, with optional
1124 * spaces on both sides of the number and with an optional null character
1125 * at the end. Returns -1 on an illegal format.
1126 */
1127static long
1128getOctal(const char * cp, int len)
1129{
1130 long val;
1131
1132 while ((len > 0) && (*cp == ' '))
1133 {
1134 cp++;
1135 len--;
1136 }
1137
1138 if ((len == 0) || !isOctal(*cp))
1139 return -1;
1140
1141 val = 0;
1142
1143 while ((len > 0) && isOctal(*cp))
1144 {
1145 val = val * 8 + *cp++ - '0';
1146 len--;
1147 }
1148
1149 while ((len > 0) && (*cp == ' '))
1150 {
1151 cp++;
1152 len--;
1153 }
1154
1155 if ((len > 0) && *cp)
1156 return -1;
1157
1158 return val;
1159}
1160
1161
1162/*
1163 * Put an octal string into the specified buffer.
1164 * The number is zero and space padded and possibly null padded.
1165 * Returns TRUE if successful.
1166 */
1167static BOOL
1168putOctal(char * cp, int len, long value)
1169{
1170 int tempLength;
1171 char * tempString;
1172 char tempBuffer[32];
1173
1174 /*
1175 * Create a string of the specified length with an initial space,
1176 * leading zeroes and the octal number, and a trailing null.
1177 */
1178 tempString = tempBuffer;
1179
1180 sprintf(tempString, " %0*lo", len - 2, value);
1181
1182 tempLength = strlen(tempString) + 1;
1183
1184 /*
1185 * If the string is too large, suppress the leading space.
1186 */
1187 if (tempLength > len)
1188 {
1189 tempLength--;
1190 tempString++;
1191 }
1192
1193 /*
1194 * If the string is still too large, suppress the trailing null.
1195 */
1196 if (tempLength > len)
1197 tempLength--;
1198
1199 /*
1200 * If the string is still too large, fail.
1201 */
1202 if (tempLength > len)
1203 return FALSE;
1204
1205 /*
1206 * Copy the string to the field.
1207 */
1208 memcpy(cp, tempString, len);
1209
1210 return TRUE;
1211}
1212
1213
1214/*
1215 * See if the specified file name belongs to one of the specified list
1216 * of path prefixes. An empty list implies that all files are wanted.
1217 * Returns TRUE if the file is selected.
1218 */
1219static BOOL
1220wantFileName(const char * fileName, int fileCount, char ** fileTable)
1221{
1222 const char * pathName;
1223 int fileLength;
1224 int pathLength;
1225
1226 /*
1227 * If there are no files in the list, then the file is wanted.
1228 */
1229 if (fileCount == 0)
1230 return TRUE;
1231
1232 fileLength = strlen(fileName);
1233
1234 /*
1235 * Check each of the test paths.
1236 */
1237 while (fileCount-- > 0)
1238 {
1239 pathName = *fileTable++;
1240
1241 pathLength = strlen(pathName);
1242
1243 if (fileLength < pathLength)
1244 continue;
1245
1246 if (memcmp(fileName, pathName, pathLength) != 0)
1247 continue;
1248
1249 if ((fileLength == pathLength) ||
1250 (fileName[pathLength] == '/'))
1251 {
1252 return TRUE;
1253 }
1254 }
1255
1256 return FALSE;
1257}
1258
1259
1260
1261/*
1262 * Return the standard ls-like mode string from a file mode.
1263 * This is static and so is overwritten on each call.
1264 */
1265const char *
1266modeString(int mode)
1267{
1268 static char buf[12];
1269
1270 strcpy(buf, "----------");
1271
1272 /*
1273 * Fill in the file type.
1274 */
1275 if (S_ISDIR(mode))
1276 buf[0] = 'd';
1277 if (S_ISCHR(mode))
1278 buf[0] = 'c';
1279 if (S_ISBLK(mode))
1280 buf[0] = 'b';
1281 if (S_ISFIFO(mode))
1282 buf[0] = 'p';
1283#ifdef S_ISLNK
1284 if (S_ISLNK(mode))
1285 buf[0] = 'l';
1286#endif
1287#ifdef S_ISSOCK
1288 if (S_ISSOCK(mode))
1289 buf[0] = 's';
1290#endif
1291
1292 /*
1293 * Now fill in the normal file permissions.
1294 */
1295 if (mode & S_IRUSR)
1296 buf[1] = 'r';
1297 if (mode & S_IWUSR)
1298 buf[2] = 'w';
1299 if (mode & S_IXUSR)
1300 buf[3] = 'x';
1301 if (mode & S_IRGRP)
1302 buf[4] = 'r';
1303 if (mode & S_IWGRP)
1304 buf[5] = 'w';
1305 if (mode & S_IXGRP)
1306 buf[6] = 'x';
1307 if (mode & S_IROTH)
1308 buf[7] = 'r';
1309 if (mode & S_IWOTH)
1310 buf[8] = 'w';
1311 if (mode & S_IXOTH)
1312 buf[9] = 'x';
1313
1314 /*
1315 * Finally fill in magic stuff like suid and sticky text.
1316 */
1317 if (mode & S_ISUID)
1318 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
1319 if (mode & S_ISGID)
1320 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
1321 if (mode & S_ISVTX)
1322 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
1323
1324 return buf;
1325}
1326
1327
1328/*
1329 * Get the time string to be used for a file.
1330 * This is down to the minute for new files, but only the date for old files.
1331 * The string is returned from a static buffer, and so is overwritten for
1332 * each call.
1333 */
1334const char *
1335timeString(time_t timeVal)
1336{
1337 time_t now;
1338 char * str;
1339 static char buf[26];
1340
1341 time(&now);
1342
1343 str = ctime(&timeVal);
1344
1345 strcpy(buf, &str[4]);
1346 buf[12] = '\0';
1347
1348 if ((timeVal > now) || (timeVal < now - 365*24*60*60L))
1349 {
1350 strcpy(&buf[7], &str[20]);
1351 buf[11] = '\0';
1352 }
1353
1354 return buf;
1355}
1356
1357
1358
1359/*
1360 * Write all of the supplied buffer out to a file.
1361 * This does multiple writes as necessary.
1362 * Returns the amount written, or -1 on an error.
1363 */
1364int
1365fullWrite(int fd, const char * buf, int len)
1366{
1367 int cc;
1368 int total;
1369
1370 total = 0;
1371
1372 while (len > 0)
1373 {
1374 cc = write(fd, buf, len);
1375
1376 if (cc < 0)
1377 return -1;
1378
1379 buf += cc;
1380 total+= cc;
1381 len -= cc;
1382 }
1383
1384 return total;
1385}
1386
1387
1388/*
1389 * Read all of the supplied buffer from a file.
1390 * This does multiple reads as necessary.
1391 * Returns the amount read, or -1 on an error.
1392 * A short read is returned on an end of file.
1393 */
1394int
1395fullRead(int fd, char * buf, int len)
1396{
1397 int cc;
1398 int total;
1399
1400 total = 0;
1401
1402 while (len > 0)
1403 {
1404 cc = read(fd, buf, len);
1405
1406 if (cc < 0)
1407 return -1;
1408
1409 if (cc == 0)
1410 break;
1411
1412 buf += cc;
1413 total+= cc;
1414 len -= cc;
1415 }
1416
1417 return total;
1418}
1419
1420
1421
1422#endif
1423/* END CODE */
1424
1425
diff --git a/block_device.c b/block_device.c
new file mode 100644
index 000000000..87e7209c0
--- /dev/null
+++ b/block_device.c
@@ -0,0 +1,64 @@
1#include "internal.h"
2#include <dirent.h>
3#include <string.h>
4#include <stdio.h>
5
6const char block_device_usage[] = "block_device mount-point";
7
8static dev_t *my_device;
9static char *my_device_name;
10
11int
12match_mount(const struct FileInfo * i) {
13 if ( S_ISBLK(i->stat.st_mode)
14 && (i->stat.st_rdev == *my_device)) {
15 my_device_name=strdup(i->source);
16 return 1;
17 } else
18 return 0;
19}
20
21extern int
22block_device_main(struct FileInfo * i, int argc, char * * argv)
23{
24 char *device_name = block_device(argv[1],i);
25 if ( device_name == NULL )
26 return -1;
27 printf("%s\n", device_name);
28 exit(0);
29}
30
31char * block_device(const char *name, struct FileInfo *i)
32{
33 struct stat s;
34 char *buf;
35 int dinam=0;
36
37 if ( stat(name, &s) ) return (char *) NULL;
38 if (!i) {
39 i=(struct FileInfo*)malloc(sizeof(struct FileInfo));
40 dinam = 1;
41 }
42 memset((void *)i, 0, sizeof(struct FileInfo));
43 my_device=(dev_t *)malloc(sizeof(dev_t));
44 *my_device = s.st_dev;
45 my_device_name = NULL;
46 i->source = "/dev";
47 i->stat = s;
48 i->processDirectoriesAfterTheirContents=1;
49 descend(i, match_mount);
50 if (dinam) free(i);
51 if ( my_device_name ) {
52 buf = strdup(my_device_name);
53 free(my_device);
54 free(my_device_name);
55 return buf;
56 } else {
57 fprintf( stderr
58 ,"Can't find special file for block device %d, %d.\n"
59 ,(int) *my_device >> 8 & 0xff
60 ,(int) *my_device & 0xff);
61 free(my_device);
62 return (char *) NULL;
63 }
64}
diff --git a/busybox.c b/busybox.c
new file mode 100644
index 000000000..b7b2b6009
--- /dev/null
+++ b/busybox.c
@@ -0,0 +1,230 @@
1#include "internal.h"
2#include <stdio.h>
3#include <string.h>
4#include <errno.h>
5
6static int been_there_done_that = 0;
7
8static const struct Applet applets[] = {
9
10#ifdef BB_BUSYBOX //bin
11 {"busybox", busybox_main},
12#endif
13#ifdef BB_BLOCK_DEVICE //sbin
14 {"block_device", block_device_main},
15#endif
16#ifdef BB_CAT //bin
17 {"cat", cat_more_main},
18#endif
19#ifdef BB_CHGRP //bin
20 {"chgrp", chgrp_main},
21#endif
22#ifdef BB_CHMOD //bin
23 {"chmod", chmod_main},
24#endif
25#ifdef BB_CHOWN //bin
26 {"chown", chown_main},
27#endif
28#ifdef BB_CHROOT //sbin
29 {"chroot", chroot_main},
30#endif
31#ifdef BB_CLEAR //usr/bin
32 {"clear", clear_main},
33#endif
34#ifdef BB_CP //bin
35 {"cp", dyadic_main},
36#endif
37#ifdef BB_DATE //bin
38 {"date", date_main},
39#endif
40#ifdef BB_DD //bin
41 {"dd", dd_main},
42#endif
43#ifdef BB_DF //bin
44 {"df", df_main},
45#endif
46#ifdef BB_DMESG //bin
47 {"dmesg", dmesg_main},
48#endif
49#ifdef BB_DUTMP //usr/sbin
50 {"dutmp", cat_more_main},
51#endif
52#ifdef BB_FALSE //bin
53 {"false", false_main},
54#endif
55#ifdef BB_FDFLUSH //bin
56 {"fdflush", monadic_main},
57#endif
58#ifdef BB_FIND //usr/bin
59 {"find", find_main},
60#endif
61#ifdef BB_GREP //bin
62 {"grep", grep_main},
63#endif
64#ifdef BB_HALT //sbin
65 {"halt", halt_main},
66#endif
67#ifdef BB_INIT //sbin
68 {"init", init_main},
69#endif
70#ifdef BB_KILL //bin
71 {"kill", kill_main},
72#endif
73#ifdef BB_LENGTH //usr/bin
74 {"length", length_main},
75#endif
76#ifdef BB_LN //bin
77 {"ln", dyadic_main},
78#endif
79#ifdef BB_LOADKMAP //sbin
80 {"loadkmap", loadkmap_main},
81#endif
82#ifdef BB_LOSETUP //sbin
83 {"losetup", losetup_main},
84#endif
85#ifdef BB_LS //bin
86 {"ls", ls_main},
87#endif
88#ifdef BB_MAKEDEVS //sbin
89 {"makedevs", makedevs_main},
90#endif
91#ifdef BB_MATH //usr/bin
92 {"math", math_main},
93#endif
94#ifdef BB_MKDIR //bin
95 {"mkdir", monadic_main},
96#endif
97#ifdef BB_MKNOD //bin
98 {"mknod", mknod_main},
99#endif
100#ifdef BB_MKSWAP //sbin
101 {"mkswap", mkswap_main},
102#endif
103#ifdef BB_MNC //usr/bin
104 {"mnc", mnc_main},
105#endif
106#ifdef BB_MORE //bin
107 {"more", cat_more_main},
108#endif
109#ifdef BB_MOUNT //bin
110 {"mount", mount_main},
111#endif
112#ifdef BB_MT //bin
113 {"mt", mt_main},
114#endif
115#ifdef BB_MV //bin
116 {"mv", dyadic_main},
117#endif
118#ifdef BB_PRINTF //usr/bin
119 {"printf", printf_main},
120#endif
121#ifdef BB_PWD //bin
122 {"pwd", pwd_main},
123#endif
124#ifdef BB_REBOOT //sbin
125 {"reboot", reboot_main},
126#endif
127#ifdef BB_RM //bin
128 {"rm", rm_main},
129#endif
130#ifdef BB_RMDIR //bin
131 {"rmdir", monadic_main},
132#endif
133#ifdef BB_SLEEP //bin
134 {"sleep", sleep_main},
135#endif
136#ifdef BB_TAR //bin
137 {"tar", tar_main},
138#endif
139#ifdef BB_SWAPOFF //sbin
140 {"swapoff", monadic_main},
141#endif
142#ifdef BB_SWAPON //sbin
143 {"swapon", monadic_main},
144#endif
145#ifdef BB_SYNC //bin
146 {"sync", sync_main},
147#endif
148#ifdef BB_TOUCH //usr/bin
149 {"touch", monadic_main},
150#endif
151#ifdef BB_TRUE //bin
152 {"true", true_main},
153#endif
154#ifdef BB_UMOUNT //bin
155 {"umount", umount_main},
156#endif
157#ifdef BB_UPDATE //sbin
158 {"update", update_main},
159#endif
160#ifdef BB_ZCAT //bin
161 {"zcat", zcat_main},
162 {"gunzip", zcat_main},
163#endif
164#ifdef BB_GZIP //bin
165 {"gzip", gzip_main},
166#endif
167 {0}
168};
169
170int main(int argc, char **argv)
171{
172 char *s = argv[0];
173 char *name = argv[0];
174 const struct Applet *a = applets;
175
176 while (*s != '\0') {
177 if (*s++ == '/')
178 name = s;
179 }
180
181 while (a->name != 0) {
182 if (strcmp(name, a->name) == 0) {
183 int status;
184
185 status = ((*(a->main)) (argc, argv));
186 if (status < 0) {
187 fprintf(stderr, "%s: %s\n", a->name, strerror(errno));
188 }
189 fprintf(stderr, "\n");
190 exit(status);
191 }
192 a++;
193 }
194 return (busybox_main(argc, argv));
195}
196
197
198int busybox_main(int argc, char **argv)
199{
200 argc--;
201 argv++;
202
203 /* If we've already been here once, exit now */
204 if (been_there_done_that == 1)
205 return -1;
206 been_there_done_that = 1;
207
208 if (argc < 1) {
209 const struct Applet *a = applets;
210 fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n",
211 BB_VER, BB_BT);
212 fprintf(stderr, "Usage: busybox [function] [arguments]...\n");
213 fprintf(stderr,
214 "\n\tMost people will create a symlink to busybox for each\n"
215 "\tfunction name, and busybox will act like whatever you invoke it as.\n");
216 fprintf(stderr, "\nCurrently defined functions:\n");
217
218 if (a->name != 0) {
219 fprintf(stderr, "%s", a->name);
220 a++;
221 }
222 while (a->name != 0) {
223 fprintf(stderr, ", %s", a->name);
224 a++;
225 }
226 fprintf(stderr, "\n\n");
227 exit(-1);
228 } else
229 return (main(argc, argv));
230}
diff --git a/busybox.def.h b/busybox.def.h
new file mode 100644
index 000000000..ad6480a25
--- /dev/null
+++ b/busybox.def.h
@@ -0,0 +1,64 @@
1/*
2 * This file is parsed by sed. You MUST use single line comments.
3 * IE //#define BB_BLAH
4 */
5
6//#define BB_BLOCK_DEVICE
7#define BB_BUSYBOX
8#define BB_CAT
9#define BB_CHGRP
10//#define BB_CHMOD
11//#define BB_CHOWN
12//#define BB_CHROOT
13//#define BB_CLEAR
14//#define BB_CP
15//#define BB_DATE
16//#define BB_DD
17//#define BB_DESCEND
18//#define BB_DF
19//#define BB_DMESG
20//#define BB_DUTMP
21//#define BB_DYADIC
22//#define BB_FALSE
23//#define BB_FDFLUSH
24//#define BB_FIND
25//#define BB_FINDMOUNT
26//#define BB_GREP
27////#define BB_HALT
28//#define BB_INIT
29//#define BB_KILL
30////#define BB_LENGTH
31//#define BB_LN
32//#define BB_LOADKMAP
33////#define BB_LOSETUP
34//#define BB_LS
35//#define BB_MAIN
36//#define BB_MAKEDEVS
37////#define BB_MATH
38//#define BB_MKDIR
39//#define BB_MKNOD
40////#define BB_MKSWAP
41//#define BB_MNC
42//#define BB_MONADIC
43//#define BB_MORE
44//#define BB_MOUNT
45////#define BB_MT
46//#define BB_MV
47//#define BB_POSTPROCESS
48//#define BB_PRINTF
49//#define BB_PWD
50//#define BB_REBOOT
51//#define BB_RM
52//#define BB_RMDIR
53//#define BB_SLEEP
54////#define BB_SWAPOFF
55//#define BB_SWAPON
56//#define BB_SYNC
57//#define BB_TAR
58//#define BB_TOUCH
59//#define BB_TRUE
60//#define BB_UMOUNT
61//#define BB_UPDATE
62//#define BB_UTILITY
63//#define BB_ZCAT
64//#define BB_GZIP
diff --git a/busybox.mkll b/busybox.mkll
new file mode 100755
index 000000000..e43a1ccb0
--- /dev/null
+++ b/busybox.mkll
@@ -0,0 +1,17 @@
1#!/bin/sh
2#Make busybox links list file
3
4DF="busybox.def.h"
5MF="main.c"
6
7LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)"
8
9 for def in ${LIST}; do
10
11 set -- $(sed -n '/^#ifdef '$def'[ +| +].*/,/^#endif/{s/.*\/\///p; /^{ /{ s/^{ "//; s/",.*$//p;}; }' $MF)
12 path=$1; shift
13
14 for n in $@; do
15 echo "$path/$n"
16 done
17 done
diff --git a/busybox.spec b/busybox.spec
new file mode 100644
index 000000000..46bd7f484
--- /dev/null
+++ b/busybox.spec
@@ -0,0 +1,43 @@
1Name: busybox
2Version: 0.29alpha
3Release: 1
4Group: System/Utilities
5Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
6Copyright: GPL
7Packager : Erik Andersen <andersen@lineo.com>
8Conflicts: fileutils grep shellutils
9Buildroot: /tmp/%{Name}-%{Version}
10Source: busybox-0.29a1.tar.gz
11
12%Description
13BusyBox is a suite of "tiny" Unix utilities in a multi-call binary. It
14provides a pretty complete environment that fits on a floppy or in a
15ROM. Just add "ash" (Keith Almquists tiny Bourne shell clone) and "ae",
16and a kernel and you have a full system. This is used on the Debian
17install disk and in an internet router, and it makes a good environment
18for a "rescue" disk or any small or embedded system.
19
20%Prep
21%setup -q -n busybox
22
23%Build
24make
25
26%Install
27rm -rf $RPM_BUILD_ROOT
28mkdir -p $RPM_BUILD_ROOT/bin
29h=`cat busybox.links`
30
31for i in $h ; do
32 mkdir -p $RPM_BUILD_ROOT/`echo $i | sed -e 's/\(^.*\/\)\(.*\)/\1/g' `
33 (cd $RPM_BUILD_ROOT/bin ; ln -s ln `echo $i | sed -e 's/\(^.*\/\)\(.*\)/\2/g' ` );
34done
35rm -f $RPM_BUILD_ROOT/bin/ln
36install -m 755 busybox $RPM_BUILD_ROOT/bin/ln
37
38%Clean
39rm -rf $RPM_BUILD_ROOT
40
41%Files
42%defattr(-,root,root)
43/
diff --git a/busybox_functions.h b/busybox_functions.h
new file mode 100644
index 000000000..61fc48438
--- /dev/null
+++ b/busybox_functions.h
@@ -0,0 +1,11 @@
1#ifndef __BUSYBOX_FUNCTIONS_H__
2#define __BUSYBOX_FUNCTIONS_H__
3
4int
5mkswap(char *device_name, int pages, int check);
6/* pages = 0 for autodetection */
7
8int
9fdflush(char *filename);
10
11#endif /* __BUSYBOX_FUNCTIONS_H__ */
diff --git a/cat.c b/cat.c
new file mode 100644
index 000000000..12faf55ab
--- /dev/null
+++ b/cat.c
@@ -0,0 +1,54 @@
1/*
2 * Mini Cat implementation for busybox
3 *
4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "internal.h"
23#include <stdio.h>
24
25const char cat_usage[] = "[file ...]";
26
27extern int cat_more_main(int argc, char **argv)
28{
29 int c;
30 FILE *file = stdin;
31
32 if (argc < 2) {
33 fprintf(stderr, "Usage: %s %s", *argv, cat_usage);
34 return 1;
35 }
36 argc--;
37 argv++;
38
39 while (argc-- > 0) {
40 file = fopen(*argv, "r");
41 if (file == NULL) {
42 name_and_error(*argv);
43 return 1;
44 }
45 while ((c = getc(file)) != EOF)
46 putc(c, stdout);
47 fclose(file);
48 fflush(stdout);
49
50 argc--;
51 argv++;
52 }
53 return 0;
54}
diff --git a/chgrp.c b/chgrp.c
new file mode 100644
index 000000000..038c665dd
--- /dev/null
+++ b/chgrp.c
@@ -0,0 +1,89 @@
1/*
2 * Mini chgrp implementation for busybox
3 *
4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "internal.h"
23#include <grp.h>
24#include <stdio.h>
25
26const char chgrp_usage[] = "chgrp [OPTION]... GROUP FILE...\n"
27 "Change the group membership of each FILE to GROUP.\n"
28 "\n\tOptions:\n" "\t-R\tchange files and directories recursively\n";
29
30int chgrp_main(int argc, char **argv)
31{
32 const char *cp;
33 int gid;
34 struct group *grp;
35 struct stat statBuf;
36
37 if (argc < 2) {
38 fprintf(stderr, "Usage: %s %s", *argv, chgrp_usage);
39 return 1;
40 }
41 argc--;
42 argv++;
43
44 cp = argv[1];
45 if (isDecimal(*cp)) {
46 gid = 0;
47 while (isDecimal(*cp))
48 gid = gid * 10 + (*cp++ - '0');
49 if (*cp) {
50 fprintf(stderr, "Bad gid value\n");
51 return -1;
52 }
53 } else {
54 grp = getgrnam(cp);
55 if (grp == NULL) {
56 fprintf(stderr, "Unknown group name\n");
57 return -1;
58 }
59 gid = grp->gr_gid;
60 }
61 argc--;
62 argv++;
63 while (argc-- > 1) {
64 argv++;
65 if ((stat(*argv, &statBuf) < 0) ||
66 (chown(*argv, statBuf.st_uid, gid) < 0)) {
67 perror(*argv);
68 }
69 }
70 return 1;
71}
72
73
74
75
76
77
78
79
80
81#if 0
82int
83recursive(const char *fileName, BOOL followLinks, const char *pattern,
84 int (*fileAction) (const char *fileName,
85 const struct stat * statbuf),
86 int (*dirAction) (const char *fileName,
87 const struct stat * statbuf))
88
89#endif
diff --git a/chmod.c b/chmod.c
new file mode 100644
index 000000000..225c92d10
--- /dev/null
+++ b/chmod.c
@@ -0,0 +1,163 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <sys/stat.h>
5#include "internal.h"
6
7const char chmod_usage[] = "chmod [-R] mode file [file ...]\n"
8"\nmode may be an octal integer representing the bit pattern for the\n"
9"\tnew mode, or a symbolic value matching the pattern\n"
10"\t[ugoa]{+|-|=}[rwxst] .\n"
11"\t\tu:\tUser\n"
12"\t\tg:\tGroup\n"
13"\t\to:\tOthers\n"
14"\t\ta:\tAll\n"
15"\n"
16"\n+:\tAdd privilege\n"
17"\n-:\tRemove privilege\n"
18"\n=:\tSet privilege\n"
19"\n"
20"\t\tr:\tRead\n"
21"\t\tw:\tWrite\n"
22"\t\tx:\tExecute\n"
23"\t\ts:\tSet User ID\n"
24"\t\tt:\t\"Sticky\" Text\n"
25"\n"
26"\tModes may be concatenated, as in \"u=rwx,g=rx,o=rx,-t,-s\n"
27"\n"
28"\t-R:\tRecursively change the mode of all files and directories\n"
29"\t\tunder the argument directory.";
30
31int
32parse_mode(
33 const char * s
34,mode_t * or
35,mode_t * and
36,int * group_execute)
37{
38 /* [ugoa]{+|-|=}[rwxstl] */
39 mode_t mode = 0;
40 mode_t groups = S_ISVTX;
41 char type;
42 char c;
43
44 do {
45 for ( ; ; ) {
46 switch ( c = *s++ ) {
47 case '\0':
48 return -1;
49 case 'u':
50 groups |= S_ISUID|S_IRWXU;
51 continue;
52 case 'g':
53 groups |= S_ISGID|S_IRWXG;
54 continue;
55 case 'o':
56 groups |= S_IRWXO;
57 continue;
58 case 'a':
59 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
60 continue;
61 case '+':
62 case '=':
63 case '-':
64 type = c;
65 if ( groups == S_ISVTX ) /* The default is "all" */
66 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
67 break;
68 default:
69 if ( c >= '0' && c <= '7' && mode == 0 && groups == S_ISVTX ) {
70 *and = 0;
71 *or = strtol(--s, 0, 010);
72 return 0;
73 }
74 else
75 return -1;
76 }
77 break;
78 }
79
80 while ( (c = *s++) != '\0' ) {
81 switch ( c ) {
82 case ',':
83 break;
84 case 'r':
85 mode |= S_IRUSR|S_IRGRP|S_IROTH;
86 continue;
87 case 'w':
88 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
89 continue;
90 case 'x':
91 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
92 continue;
93 case 's':
94 if ( group_execute != 0 && (groups & S_IRWXG) ) {
95 if ( *group_execute < 0 )
96 return -1;
97 if ( type != '-' ) {
98 mode |= S_IXGRP;
99 *group_execute = 1;
100 }
101 }
102 mode |= S_ISUID|S_ISGID;
103 continue;
104 case 'l':
105 if ( *group_execute > 0 )
106 return -1;
107 if ( type != '-' ) {
108 *and &= ~S_IXGRP;
109 *group_execute = -1;
110 }
111 mode |= S_ISGID;
112 groups |= S_ISGID;
113 continue;
114 case 't':
115 mode |= S_ISVTX;
116 continue;
117 default:
118 return -1;
119 }
120 break;
121 }
122 switch ( type ) {
123 case '=':
124 *and &= ~(groups);
125 /* fall through */
126 case '+':
127 *or |= mode & groups;
128 break;
129 case '-':
130 *and &= ~(mode & groups);
131 *or &= *and;
132 break;
133 }
134 } while ( c == ',' );
135 return 0;
136}
137
138extern int
139chmod_main(struct FileInfo * i, int argc, char * * argv)
140{
141 i->andWithMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
142 i->orWithMode = 0;
143
144 while ( argc >= 3 ) {
145 if ( parse_mode(argv[1], &i->orWithMode, &i->andWithMode, 0)
146 == 0 ) {
147 argc--;
148 argv++;
149 }
150 else if ( strcmp(argv[1], "-R") == 0 ) {
151 i->recursive = 1;
152 argc--;
153 argv++;
154 }
155 else
156 break;
157 }
158
159 i->changeMode = 1;
160 i->complainInPostProcess = 1;
161
162 return monadic_main(i, argc, argv);
163}
diff --git a/chown.c b/chown.c
new file mode 100644
index 000000000..a611f92f1
--- /dev/null
+++ b/chown.c
@@ -0,0 +1,63 @@
1#include "internal.h"
2#include <pwd.h>
3#include <grp.h>
4#include <string.h>
5#include <stdio.h>
6
7const char chown_usage[] = "chown [-R] user-name file [file ...]\n"
8"\n\tThe group list is kept in the file /etc/groups.\n\n"
9"\t-R:\tRecursively change the mode of all files and directories\n"
10"\t\tunder the argument directory.";
11
12int
13parse_user_name(const char * s, struct FileInfo * i)
14{
15 struct passwd * p;
16 char * dot = strchr(s, '.');
17
18 if (! dot )
19 dot = strchr(s, ':');
20
21 if ( dot )
22 *dot = '\0';
23
24 if ( (p = getpwnam(s)) == 0 ) {
25 fprintf(stderr, "%s: no such user.\n", s);
26 return 1;
27 }
28 i->userID = p->pw_uid;
29
30 if ( dot ) {
31 struct group * g = getgrnam(++dot);
32 if ( g == 0 ) {
33 fprintf(stderr, "%s: no such group.\n", dot);
34 return 1;
35 }
36 i->groupID = g->gr_gid;
37 i->changeGroupID = 1;
38 }
39 return 0;
40}
41
42extern int
43chown_main(struct FileInfo * i, int argc, char * * argv)
44{
45 int status;
46
47 while ( argc >= 3 && strcmp("-R", argv[1]) == 0 ) {
48 i->recursive = 1;
49 argc--;
50 argv++;
51 }
52
53 if ( (status = parse_user_name(argv[1], i)) != 0 )
54 return status;
55
56 argv++;
57 argc--;
58
59 i->changeUserID = 1;
60 i->complainInPostProcess = 1;
61
62 return monadic_main(i, argc, argv);
63}
diff --git a/chroot.c b/chroot.c
new file mode 100644
index 000000000..ca0bfcf3f
--- /dev/null
+++ b/chroot.c
@@ -0,0 +1,32 @@
1#include "internal.h"
2#include <stdio.h>
3#include <unistd.h>
4
5
6const char chroot_usage[] = "chroot directory [command]\n"
7 "Run a command with special root directory.\n";
8
9extern int
10chroot_main (struct FileInfo *i, int argc, char **argv)
11{
12 char *prog;
13
14 if (chroot (argv[1]))
15 {
16 name_and_error ("cannot chroot to that directory");
17 return 1;
18 }
19 if (argc > 2)
20 {
21 execvp (argv[2], argv + 2);
22 }
23 else
24 {
25 prog = getenv ("SHELL");
26 if (!prog)
27 prog = "/bin/sh";
28 execlp (prog, prog, NULL);
29 }
30 name_and_error ("cannot exec");
31 return 1;
32}
diff --git a/clear.c b/clear.c
new file mode 100644
index 000000000..21a890c9e
--- /dev/null
+++ b/clear.c
@@ -0,0 +1,13 @@
1#include "internal.h"
2#include <stdio.h>
3
4const char clear_usage[] = "clear\n"
5"\n"
6"\tClears the screen.\n";
7
8extern int
9clear_main(struct FileInfo * i, int argc, char * * argv)
10{
11 printf("\033[H\033[J");
12 return 0;
13}
diff --git a/console-tools/clear.c b/console-tools/clear.c
new file mode 100644
index 000000000..21a890c9e
--- /dev/null
+++ b/console-tools/clear.c
@@ -0,0 +1,13 @@
1#include "internal.h"
2#include <stdio.h>
3
4const char clear_usage[] = "clear\n"
5"\n"
6"\tClears the screen.\n";
7
8extern int
9clear_main(struct FileInfo * i, int argc, char * * argv)
10{
11 printf("\033[H\033[J");
12 return 0;
13}
diff --git a/console-tools/loadkmap.c b/console-tools/loadkmap.c
new file mode 100644
index 000000000..0f092d193
--- /dev/null
+++ b/console-tools/loadkmap.c
@@ -0,0 +1,68 @@
1#include "internal.h"
2#include <errno.h>
3#include <fcntl.h>
4#include <stdio.h>
5#include <linux/kd.h>
6#include <linux/keyboard.h>
7#include <sys/ioctl.h>
8
9
10const char loadkmap_usage[] = "loadkmap\n"
11"\n"
12"\tLoad a binary keyboard translation table from standard input.\n"
13"\n";
14
15
16int
17loadkmap_main(struct FileInfo * info, int argc, char * * argv)
18{
19 struct kbentry ke;
20 u_short *ibuff;
21 int i,j,fd,readsz,pos,ibuffsz=NR_KEYS * sizeof(u_short);
22 char flags[MAX_NR_KEYMAPS],magic[]="bkeymap",buff[7];
23
24 fd = open("/dev/tty0", O_RDWR);
25 if (fd < 0) {
26 fprintf(stderr, "Error opening /dev/tty0: %s\n", strerror(errno));
27 return 1;
28 }
29
30 read(0,buff,7);
31 if (0 != strncmp(buff,magic,7)) {
32 fprintf(stderr, "This is not a valid binary keymap.\n");
33 return 1;
34 }
35
36 if ( MAX_NR_KEYMAPS != read(0,flags,MAX_NR_KEYMAPS) ) {
37 fprintf(stderr, "Error reading keymap flags: %s\n", strerror(errno));
38 return 1;
39 }
40
41 ibuff=(u_short *) malloc(ibuffsz);
42 if (!ibuff) {
43 fprintf(stderr, "Out of memory.\n");
44 return 1;
45 }
46
47 for(i=0; i<MAX_NR_KEYMAPS; i++) {
48 if (flags[i]==1){
49 pos=0;
50 while (pos < ibuffsz) {
51 if ( (readsz = read(0,ibuff+pos,ibuffsz-pos)) < 0 ) {
52 fprintf(stderr, "Error reading keymap: %s\n",
53 strerror(errno));
54 return 1;
55 }
56 pos += readsz;
57 }
58 for(j=0; j<NR_KEYS; j++) {
59 ke.kb_index = j;
60 ke.kb_table = i;
61 ke.kb_value = ibuff[j];
62 ioctl(fd, KDSKBENT, &ke);
63 }
64 }
65 }
66 close (fd);
67 return 0;
68}
diff --git a/coreutils/cat.c b/coreutils/cat.c
new file mode 100644
index 000000000..12faf55ab
--- /dev/null
+++ b/coreutils/cat.c
@@ -0,0 +1,54 @@
1/*
2 * Mini Cat implementation for busybox
3 *
4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "internal.h"
23#include <stdio.h>
24
25const char cat_usage[] = "[file ...]";
26
27extern int cat_more_main(int argc, char **argv)
28{
29 int c;
30 FILE *file = stdin;
31
32 if (argc < 2) {
33 fprintf(stderr, "Usage: %s %s", *argv, cat_usage);
34 return 1;
35 }
36 argc--;
37 argv++;
38
39 while (argc-- > 0) {
40 file = fopen(*argv, "r");
41 if (file == NULL) {
42 name_and_error(*argv);
43 return 1;
44 }
45 while ((c = getc(file)) != EOF)
46 putc(c, stdout);
47 fclose(file);
48 fflush(stdout);
49
50 argc--;
51 argv++;
52 }
53 return 0;
54}
diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c
new file mode 100644
index 000000000..038c665dd
--- /dev/null
+++ b/coreutils/chgrp.c
@@ -0,0 +1,89 @@
1/*
2 * Mini chgrp implementation for busybox
3 *
4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "internal.h"
23#include <grp.h>
24#include <stdio.h>
25
26const char chgrp_usage[] = "chgrp [OPTION]... GROUP FILE...\n"
27 "Change the group membership of each FILE to GROUP.\n"
28 "\n\tOptions:\n" "\t-R\tchange files and directories recursively\n";
29
30int chgrp_main(int argc, char **argv)
31{
32 const char *cp;
33 int gid;
34 struct group *grp;
35 struct stat statBuf;
36
37 if (argc < 2) {
38 fprintf(stderr, "Usage: %s %s", *argv, chgrp_usage);
39 return 1;
40 }
41 argc--;
42 argv++;
43
44 cp = argv[1];
45 if (isDecimal(*cp)) {
46 gid = 0;
47 while (isDecimal(*cp))
48 gid = gid * 10 + (*cp++ - '0');
49 if (*cp) {
50 fprintf(stderr, "Bad gid value\n");
51 return -1;
52 }
53 } else {
54 grp = getgrnam(cp);
55 if (grp == NULL) {
56 fprintf(stderr, "Unknown group name\n");
57 return -1;
58 }
59 gid = grp->gr_gid;
60 }
61 argc--;
62 argv++;
63 while (argc-- > 1) {
64 argv++;
65 if ((stat(*argv, &statBuf) < 0) ||
66 (chown(*argv, statBuf.st_uid, gid) < 0)) {
67 perror(*argv);
68 }
69 }
70 return 1;
71}
72
73
74
75
76
77
78
79
80
81#if 0
82int
83recursive(const char *fileName, BOOL followLinks, const char *pattern,
84 int (*fileAction) (const char *fileName,
85 const struct stat * statbuf),
86 int (*dirAction) (const char *fileName,
87 const struct stat * statbuf))
88
89#endif
diff --git a/coreutils/chmod.c b/coreutils/chmod.c
new file mode 100644
index 000000000..225c92d10
--- /dev/null
+++ b/coreutils/chmod.c
@@ -0,0 +1,163 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <sys/stat.h>
5#include "internal.h"
6
7const char chmod_usage[] = "chmod [-R] mode file [file ...]\n"
8"\nmode may be an octal integer representing the bit pattern for the\n"
9"\tnew mode, or a symbolic value matching the pattern\n"
10"\t[ugoa]{+|-|=}[rwxst] .\n"
11"\t\tu:\tUser\n"
12"\t\tg:\tGroup\n"
13"\t\to:\tOthers\n"
14"\t\ta:\tAll\n"
15"\n"
16"\n+:\tAdd privilege\n"
17"\n-:\tRemove privilege\n"
18"\n=:\tSet privilege\n"
19"\n"
20"\t\tr:\tRead\n"
21"\t\tw:\tWrite\n"
22"\t\tx:\tExecute\n"
23"\t\ts:\tSet User ID\n"
24"\t\tt:\t\"Sticky\" Text\n"
25"\n"
26"\tModes may be concatenated, as in \"u=rwx,g=rx,o=rx,-t,-s\n"
27"\n"
28"\t-R:\tRecursively change the mode of all files and directories\n"
29"\t\tunder the argument directory.";
30
31int
32parse_mode(
33 const char * s
34,mode_t * or
35,mode_t * and
36,int * group_execute)
37{
38 /* [ugoa]{+|-|=}[rwxstl] */
39 mode_t mode = 0;
40 mode_t groups = S_ISVTX;
41 char type;
42 char c;
43
44 do {
45 for ( ; ; ) {
46 switch ( c = *s++ ) {
47 case '\0':
48 return -1;
49 case 'u':
50 groups |= S_ISUID|S_IRWXU;
51 continue;
52 case 'g':
53 groups |= S_ISGID|S_IRWXG;
54 continue;
55 case 'o':
56 groups |= S_IRWXO;
57 continue;
58 case 'a':
59 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
60 continue;
61 case '+':
62 case '=':
63 case '-':
64 type = c;
65 if ( groups == S_ISVTX ) /* The default is "all" */
66 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
67 break;
68 default:
69 if ( c >= '0' && c <= '7' && mode == 0 && groups == S_ISVTX ) {
70 *and = 0;
71 *or = strtol(--s, 0, 010);
72 return 0;
73 }
74 else
75 return -1;
76 }
77 break;
78 }
79
80 while ( (c = *s++) != '\0' ) {
81 switch ( c ) {
82 case ',':
83 break;
84 case 'r':
85 mode |= S_IRUSR|S_IRGRP|S_IROTH;
86 continue;
87 case 'w':
88 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
89 continue;
90 case 'x':
91 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
92 continue;
93 case 's':
94 if ( group_execute != 0 && (groups & S_IRWXG) ) {
95 if ( *group_execute < 0 )
96 return -1;
97 if ( type != '-' ) {
98 mode |= S_IXGRP;
99 *group_execute = 1;
100 }
101 }
102 mode |= S_ISUID|S_ISGID;
103 continue;
104 case 'l':
105 if ( *group_execute > 0 )
106 return -1;
107 if ( type != '-' ) {
108 *and &= ~S_IXGRP;
109 *group_execute = -1;
110 }
111 mode |= S_ISGID;
112 groups |= S_ISGID;
113 continue;
114 case 't':
115 mode |= S_ISVTX;
116 continue;
117 default:
118 return -1;
119 }
120 break;
121 }
122 switch ( type ) {
123 case '=':
124 *and &= ~(groups);
125 /* fall through */
126 case '+':
127 *or |= mode & groups;
128 break;
129 case '-':
130 *and &= ~(mode & groups);
131 *or &= *and;
132 break;
133 }
134 } while ( c == ',' );
135 return 0;
136}
137
138extern int
139chmod_main(struct FileInfo * i, int argc, char * * argv)
140{
141 i->andWithMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
142 i->orWithMode = 0;
143
144 while ( argc >= 3 ) {
145 if ( parse_mode(argv[1], &i->orWithMode, &i->andWithMode, 0)
146 == 0 ) {
147 argc--;
148 argv++;
149 }
150 else if ( strcmp(argv[1], "-R") == 0 ) {
151 i->recursive = 1;
152 argc--;
153 argv++;
154 }
155 else
156 break;
157 }
158
159 i->changeMode = 1;
160 i->complainInPostProcess = 1;
161
162 return monadic_main(i, argc, argv);
163}
diff --git a/coreutils/chown.c b/coreutils/chown.c
new file mode 100644
index 000000000..a611f92f1
--- /dev/null
+++ b/coreutils/chown.c
@@ -0,0 +1,63 @@
1#include "internal.h"
2#include <pwd.h>
3#include <grp.h>
4#include <string.h>
5#include <stdio.h>
6
7const char chown_usage[] = "chown [-R] user-name file [file ...]\n"
8"\n\tThe group list is kept in the file /etc/groups.\n\n"
9"\t-R:\tRecursively change the mode of all files and directories\n"
10"\t\tunder the argument directory.";
11
12int
13parse_user_name(const char * s, struct FileInfo * i)
14{
15 struct passwd * p;
16 char * dot = strchr(s, '.');
17
18 if (! dot )
19 dot = strchr(s, ':');
20
21 if ( dot )
22 *dot = '\0';
23
24 if ( (p = getpwnam(s)) == 0 ) {
25 fprintf(stderr, "%s: no such user.\n", s);
26 return 1;
27 }
28 i->userID = p->pw_uid;
29
30 if ( dot ) {
31 struct group * g = getgrnam(++dot);
32 if ( g == 0 ) {
33 fprintf(stderr, "%s: no such group.\n", dot);
34 return 1;
35 }
36 i->groupID = g->gr_gid;
37 i->changeGroupID = 1;
38 }
39 return 0;
40}
41
42extern int
43chown_main(struct FileInfo * i, int argc, char * * argv)
44{
45 int status;
46
47 while ( argc >= 3 && strcmp("-R", argv[1]) == 0 ) {
48 i->recursive = 1;
49 argc--;
50 argv++;
51 }
52
53 if ( (status = parse_user_name(argv[1], i)) != 0 )
54 return status;
55
56 argv++;
57 argc--;
58
59 i->changeUserID = 1;
60 i->complainInPostProcess = 1;
61
62 return monadic_main(i, argc, argv);
63}
diff --git a/coreutils/chroot.c b/coreutils/chroot.c
new file mode 100644
index 000000000..ca0bfcf3f
--- /dev/null
+++ b/coreutils/chroot.c
@@ -0,0 +1,32 @@
1#include "internal.h"
2#include <stdio.h>
3#include <unistd.h>
4
5
6const char chroot_usage[] = "chroot directory [command]\n"
7 "Run a command with special root directory.\n";
8
9extern int
10chroot_main (struct FileInfo *i, int argc, char **argv)
11{
12 char *prog;
13
14 if (chroot (argv[1]))
15 {
16 name_and_error ("cannot chroot to that directory");
17 return 1;
18 }
19 if (argc > 2)
20 {
21 execvp (argv[2], argv + 2);
22 }
23 else
24 {
25 prog = getenv ("SHELL");
26 if (!prog)
27 prog = "/bin/sh";
28 execlp (prog, prog, NULL);
29 }
30 name_and_error ("cannot exec");
31 return 1;
32}
diff --git a/coreutils/cp.c b/coreutils/cp.c
new file mode 100644
index 000000000..078a57c56
--- /dev/null
+++ b/coreutils/cp.c
@@ -0,0 +1,89 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/stat.h>
4#include <sys/fcntl.h>
5#include <sys/param.h>
6#include <errno.h>
7
8const char cp_usage[] = "cp [-r] source-file destination-file\n"
9"\t\tcp [-r] source-file [source-file ...] destination-directory\n"
10"\n"
11"\tCopy the source files to the destination.\n"
12"\n"
13"\t-r:\tRecursively copy all files and directories\n"
14"\t\tunder the argument directory.";
15
16extern int
17cp_fn(const struct FileInfo * i)
18{
19 int sourceFd;
20 int destinationFd;
21 const char * destination = i->destination;
22 struct stat destination_stat;
23 int status;
24 char buf[8192];
25 char d[PATH_MAX];
26
27 if ( (i->stat.st_mode & S_IFMT) == S_IFDIR ) {
28 if ( mkdir(destination, i->stat.st_mode & ~S_IFMT)
29 != 0 && errno != EEXIST ) {
30 name_and_error(destination);
31 return 1;
32 }
33 return 0;
34 }
35 if ( (sourceFd = open(i->source, O_RDONLY)) < 0 ) {
36 name_and_error(i->source);
37 return 1;
38 }
39 if ( stat(destination, &destination_stat) == 0 ) {
40 if ( i->stat.st_ino == destination_stat.st_ino
41 && i->stat.st_dev == destination_stat.st_dev ) {
42 fprintf(stderr
43 ,"copy of %s to %s would copy file to itself.\n"
44 ,i->source
45 ,destination);
46 close(sourceFd);
47 return 1;
48 }
49 }
50 /*
51 * If the destination is a directory, create a file within it.
52 */
53 if ( (destination_stat.st_mode & S_IFMT) == S_IFDIR ) {
54 destination = join_paths(
55 d
56 ,i->destination
57 ,&i->source[i->directoryLength]);
58
59 if ( stat(destination, &destination_stat) == 0 ) {
60 if ( i->stat.st_ino == destination_stat.st_ino
61 && i->stat.st_dev == destination_stat.st_dev ) {
62 fprintf(stderr
63 ,"copy of %s to %s would copy file to itself.\n"
64 ,i->source
65 ,destination);
66 close(sourceFd);
67 return 1;
68 }
69 }
70 }
71
72 destinationFd = creat(destination, i->stat.st_mode & 07777);
73
74 while ( (status = read(sourceFd, buf, sizeof(buf))) > 0 ) {
75 if ( write(destinationFd, buf, status) != status ) {
76 name_and_error(destination);
77 close(sourceFd);
78 close(destinationFd);
79 return 1;
80 }
81 }
82 close(sourceFd);
83 close(destinationFd);
84 if ( status < 0 ) {
85 name_and_error(i->source);
86 return 1;
87 }
88 return 0;
89}
diff --git a/coreutils/date.c b/coreutils/date.c
new file mode 100644
index 000000000..a52a9a4a8
--- /dev/null
+++ b/coreutils/date.c
@@ -0,0 +1,305 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <errno.h>
4#include <sys/time.h>
5#include <unistd.h>
6#include <time.h>
7#include <stdio.h>
8#include <getopt.h>
9
10
11/* This 'date' command supports only 2 time setting formats,
12 all the GNU strftime stuff (its in libc, lets use it),
13 setting time using UTC and displaying int, as well as
14 an RFC 822 complient date output for shell scripting
15 mail commands */
16
17const char date_usage[] = "date [-uR] [+FORMAT|+%f] [ [-s|-d] MMDDhhmm[[CC]YY]\n | [[[[CCYY.]MM.DD-]hh:mm[:ss]]]] ]";
18
19static struct option const long_options[] =
20{
21 {"date", required_argument, NULL, 'd'},
22 /* {"rfc-822", no_argument, NULL, 'R'},
23 {"set", required_argument, NULL, 's'},
24 {"uct", no_argument, NULL, 'u'},
25 {"utc", no_argument, NULL, 'u'},
26 {"universal", no_argument, NULL, 'u'}, */
27 {NULL, 0, NULL, 0}
28};
29
30
31
32/* Input parsing code is always bulky - used heavy duty libc stuff as
33 much as possible, missed out a lot of bounds checking */
34
35/* Default input handling to save suprising some people */
36
37struct tm *
38date_conv_time(struct tm *tm_time, const char *t_string) {
39 int nr;
40
41 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
42 &(tm_time->tm_mon),
43 &(tm_time->tm_mday),
44 &(tm_time->tm_hour),
45 &(tm_time->tm_min),
46 &(tm_time->tm_year));
47
48 if(nr < 4 || nr > 5) {
49 fprintf(stderr, "date: invalid date `%s'\n", t_string);
50 exit(1);
51 }
52
53 /* correct for century - minor Y2K problem here? */
54 if(tm_time->tm_year >= 1900)
55 tm_time->tm_year -= 1900;
56 /* adjust date */
57 tm_time->tm_mon -= 1;
58
59 return(tm_time);
60
61}
62
63
64/* The new stuff for LRP */
65
66struct tm *
67date_conv_ftime(struct tm *tm_time, const char *t_string) {
68 struct tm itm_time, jtm_time, ktm_time, \
69 ltm_time, mtm_time, ntm_time;
70
71 itm_time = *tm_time;
72 jtm_time = *tm_time;
73 ktm_time = *tm_time;
74 ltm_time = *tm_time;
75 mtm_time = *tm_time;
76 ntm_time = *tm_time;
77
78 /* Parse input and assign appropriately to tm_time */
79
80 if(sscanf(t_string, "%d:%d:%d",
81 &itm_time.tm_hour,
82 &itm_time.tm_min,
83 &itm_time.tm_sec) == 3 ) {
84
85 *tm_time = itm_time;
86 return(tm_time);
87
88 } else if (sscanf(t_string, "%d:%d",
89 &jtm_time.tm_hour,
90 &jtm_time.tm_min) == 2) {
91
92 *tm_time = jtm_time;
93 return(tm_time);
94
95 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
96 &ktm_time.tm_mon,
97 &ktm_time.tm_mday,
98 &ktm_time.tm_hour,
99 &ktm_time.tm_min,
100 &ktm_time.tm_sec) == 5) {
101
102 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
103 *tm_time = ktm_time;
104 return(tm_time);
105
106 } else if (sscanf(t_string, "%d.%d-%d:%d",
107 &ltm_time.tm_mon,
108 &ltm_time.tm_mday,
109 &ltm_time.tm_hour,
110 &ltm_time.tm_min) == 4) {
111
112 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
113 *tm_time = ltm_time;
114 return(tm_time);
115
116 } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d",
117 &mtm_time.tm_year,
118 &mtm_time.tm_mon,
119 &mtm_time.tm_mday,
120 &mtm_time.tm_hour,
121 &mtm_time.tm_min,
122 &mtm_time.tm_sec) == 6) {
123
124 mtm_time.tm_year -= 1900; /* Adjust years */
125 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
126 *tm_time = mtm_time;
127 return(tm_time);
128
129 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
130 &ntm_time.tm_year,
131 &ntm_time.tm_mon,
132 &ntm_time.tm_mday,
133 &ntm_time.tm_hour,
134 &ntm_time.tm_min) == 5) {
135 ntm_time.tm_year -= 1900; /* Adjust years */
136 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
137 *tm_time = ntm_time;
138 return(tm_time);
139
140 }
141
142 fprintf(stderr, "date: invalid date `%s'\n", t_string);
143
144 exit(1);
145
146}
147
148
149void
150date_err(void) {
151 fprintf(stderr, "date: only one date argument can be given at a time.\n");
152 exit(1);
153}
154
155int
156date_main(struct FileInfo * i, int argc, char * * argv)
157{
158 char *date_str = NULL;
159 char *date_fmt = NULL;
160 char *t_buff;
161 int set_time = 0;
162 int rfc822 = 0;
163 int utc = 0;
164 int use_arg = 0;
165 int n_args;
166 time_t tm;
167 struct tm tm_time;
168 char optc;
169
170 /* Interpret command line args */
171
172
173 while ((optc = getopt_long (argc, argv, "d:Rs:u", long_options, NULL))
174 != EOF) {
175 switch (optc) {
176 case 0:
177 break;
178
179 case 'R':
180 rfc822 = 1;
181 break;
182
183 case 's':
184 set_time = 1;
185 if(date_str != NULL) date_err();
186 date_str = optarg;
187 break;
188
189 case 'u':
190 utc = 1;
191 if (putenv ("TZ=UTC0") != 0) {
192 fprintf(stderr,"date: memory exhausted\n");
193 return(1);
194 }
195#if LOCALTIME_CACHE
196 tzset ();
197#endif break;
198
199 case 'd':
200 use_arg = 1;
201 if(date_str != NULL) date_err();
202 date_str = optarg;
203 break;
204
205 default:
206 usage(date_usage);
207 break;
208 }
209 }
210
211
212 n_args = argc - optind;
213
214 while (n_args--){
215 switch(argv[optind][0]) {
216 case '+':
217 /* Date format strings */
218 if(date_fmt != NULL) {
219 fprintf(stderr, "date: only one date format can be given.\n");
220 return(1);
221 }
222 date_fmt = &argv[optind][1];
223 break;
224
225 case '\0':
226 break;
227
228 default:
229 /* Anything left over must be a date string to set the time */
230 set_time = 1;
231 if(date_str != NULL) date_err();
232 date_str = argv[optind];
233 break;
234 }
235 optind++;
236 }
237
238
239 /* Now we have parsed all the information except the date format
240 which depends on whether the clock is being set or read */
241
242 time(&tm);
243 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
244 /* Zero out fields - take her back to midnight!*/
245 if(date_str != NULL) {
246 tm_time.tm_sec = 0;
247 tm_time.tm_min = 0;
248 tm_time.tm_hour = 0;
249 }
250
251 /* Process any date input to UNIX time since 1 Jan 1970 */
252 if(date_str != NULL) {
253
254 if(strchr(date_str, ':') != NULL) {
255 date_conv_ftime(&tm_time, date_str);
256 } else {
257 date_conv_time(&tm_time, date_str);
258 }
259
260 /* Correct any day of week and day of year etc fields */
261 tm = mktime(&tm_time);
262 if (tm < 0 ) {
263 fprintf(stderr, "date: invalid date `%s'\n", date_str);
264 exit(1);
265 }
266
267 /* if setting time, set it */
268 if(set_time) {
269 if( stime(&tm) < 0) {
270 fprintf(stderr, "date: can't set date.\n");
271 exit(1);
272 }
273 }
274 }
275
276 /* Display output */
277
278 /* Deal with format string */
279 if(date_fmt == NULL) {
280 date_fmt = (rfc822
281 ? (utc
282 ? "%a, %_d %b %Y %H:%M:%S GMT"
283 : "%a, %_d %b %Y %H:%M:%S %z")
284 : "%a %b %e %H:%M:%S %Z %Y");
285
286 } else if ( *date_fmt == '\0' ) {
287 /* Imitate what GNU 'date' does with NO format string! */
288 printf ("\n");
289 return(0);
290 }
291
292 /* Handle special conversions */
293
294 if( strncmp( date_fmt, "%f", 2) == 0 ) {
295 date_fmt = "%Y.%m.%d-%H:%M:%S";
296 }
297
298 /* Print OUTPUT (after ALL that!) */
299 t_buff = malloc(201);
300 strftime(t_buff, 200, date_fmt, &tm_time);
301 printf("%s\n", t_buff);
302
303 return(0);
304
305}
diff --git a/coreutils/dd.c b/coreutils/dd.c
new file mode 100644
index 000000000..8f1b9d409
--- /dev/null
+++ b/coreutils/dd.c
@@ -0,0 +1,307 @@
1/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "dd" command, originally taken from sash.
7 *
8 * Permission to distribute this code under the GPL has been granted.
9 * Majorly modified, and bugs fixed for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
10 */
11
12#include "internal.h"
13#ifdef BB_DD
14
15const char dd_usage[] =
16"Copy a file, converting and formatting according to options\n\
17\n\
18usage: [if=name] [of=name] [bs=n] [count=n]\n\
19\tif=FILE\tread from FILE instead of stdin\n\
20\tof=FILE\twrite to FILE instead of stout\n\
21\tbs=n\tread and write N bytes at a time\n\
22\tcount=n\tcopy only n input blocks\n\
23\n\
24BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n";
25
26
27#include <stdio.h>
28#include <dirent.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <signal.h>
32#include <time.h>
33
34
35#define PAR_NONE 0
36#define PAR_IF 1
37#define PAR_OF 2
38#define PAR_BS 3
39#define PAR_COUNT 4
40
41
42typedef struct
43{
44 const char * name;
45 int value;
46} PARAM;
47
48
49static const PARAM params[] =
50{
51 {"if", PAR_IF},
52 {"of", PAR_OF},
53 {"bs", PAR_BS},
54 {"count", PAR_COUNT},
55 {NULL, PAR_NONE}
56};
57
58
59static long getNum(const char * cp);
60
61extern int
62dd_main (struct FileInfo *unused, int argc, char **argv)
63{
64 const char * str;
65 const PARAM * par;
66 const char * inFile;
67 const char * outFile;
68 char * cp;
69 int inFd;
70 int outFd;
71 int inCc=0;
72 int outCc;
73 int blockSize;
74 long count;
75 long intotal;
76 long outTotal;
77 unsigned char* buf;
78 unsigned char localBuf[BUF_SIZE];
79
80 inFile = NULL;
81 outFile = NULL;
82 blockSize = 512;
83 count = 1;
84
85
86 while (--argc > 0)
87 {
88 str = *++argv;
89 cp = strchr(str, '=');
90
91 if (cp == NULL)
92 {
93 fprintf(stderr, "Bad dd argument\n");
94 goto usage;
95 }
96
97 *cp++ = '\0';
98
99 for (par = params; par->name; par++)
100 {
101 if (strcmp(str, par->name) == 0)
102 break;
103 }
104
105 switch (par->value)
106 {
107 case PAR_IF:
108 if (inFile)
109 {
110 fprintf(stderr, "Multiple input files illegal\n");
111 goto usage;
112 }
113
114 //fprintf(stderr, "if=%s\n", cp);
115 inFile = cp;
116 break;
117
118 case PAR_OF:
119 if (outFile)
120 {
121 fprintf(stderr, "Multiple output files illegal\n");
122 goto usage;
123 }
124
125 //fprintf(stderr, "of=%s\n", cp);
126 outFile = cp;
127 break;
128
129 case PAR_BS:
130 blockSize = getNum(cp);
131 //fprintf(stderr, "bs=%d\n", blockSize);
132
133 if (blockSize <= 0)
134 {
135 fprintf(stderr, "Bad block size value\n");
136 goto usage;
137 }
138
139 break;
140
141 case PAR_COUNT:
142 count = getNum(cp);
143 //fprintf(stderr, "count=%ld\n", count);
144
145 if (count < 0)
146 {
147 fprintf(stderr, "Bad count value\n");
148 goto usage;
149 }
150
151 break;
152
153 default:
154 goto usage;
155 }
156 }
157
158 buf = localBuf;
159
160 if (blockSize > sizeof(localBuf))
161 {
162 buf = malloc(blockSize);
163
164 if (buf == NULL)
165 {
166 fprintf(stderr, "Cannot allocate buffer\n");
167 return 1;
168 }
169 }
170
171 intotal = 0;
172 outTotal = 0;
173
174 if (inFile == NULL)
175 inFd = STDIN;
176 else
177 inFd = open(inFile, 0);
178
179 if (inFd < 0)
180 {
181 perror(inFile);
182
183 if (buf != localBuf)
184 free(buf);
185
186 return 1;
187 }
188
189 if (outFile == NULL)
190 outFd = STDOUT;
191 else
192 outFd = creat(outFile, 0666);
193
194 if (outFd < 0)
195 {
196 perror(outFile);
197 close(inFd);
198
199 if (buf != localBuf)
200 free(buf);
201
202 return 1;
203 }
204
205 while ( outTotal < count*blockSize )
206 {
207 inCc = read(inFd, buf, blockSize);
208 if (inCc < 0) {
209 perror(inFile);
210 goto cleanup;
211 }
212 //fprintf(stderr, "read in =%d\n", inCc);
213 intotal += inCc;
214 cp = buf;
215
216
217 while ( intotal > outTotal )
218 {
219 if (outTotal+inCc > count*blockSize)
220 inCc=count*blockSize-outTotal;
221 outCc = write(outFd, cp, inCc);
222 if (outCc < 0)
223 {
224 perror(outFile);
225 goto cleanup;
226 }
227 //fprintf(stderr, "wrote out =%d\n", outCc);
228
229 inCc -= outCc;
230 cp += outCc;
231 outTotal += outCc;
232 //fprintf(stderr, "outTotal=%ld\n", outTotal);
233 }
234 }
235
236 if (inCc < 0)
237 perror(inFile);
238
239cleanup:
240 close(inFd);
241
242 if (close(outFd) < 0)
243 perror(outFile);
244
245 if (buf != localBuf)
246 free(buf);
247
248 printf("%ld+%d records in\n", intotal / blockSize,
249 (intotal % blockSize) != 0);
250
251 printf("%ld+%d records out\n", outTotal / blockSize,
252 (outTotal % blockSize) != 0);
253 return 0;
254usage:
255
256 fprintf(stderr, "%s", dd_usage);
257 return 1;
258}
259
260
261/*
262 * Read a number with a possible multiplier.
263 * Returns -1 if the number format is illegal.
264 */
265static long
266getNum(const char * cp)
267{
268 long value;
269
270 if (!isDecimal(*cp))
271 return -1;
272
273 value = 0;
274
275 while (isDecimal(*cp))
276 value = value * 10 + *cp++ - '0';
277
278 switch (*cp++)
279 {
280 case 'k':
281 value *= 1024;
282 break;
283
284 case 'b':
285 value *= 512;
286 break;
287
288 case 'w':
289 value *= 2;
290 break;
291
292 case '\0':
293 return value;
294
295 default:
296 return -1;
297 }
298
299 if (*cp)
300 return -1;
301
302 return value;
303}
304
305#endif
306/* END CODE */
307
diff --git a/coreutils/df.c b/coreutils/df.c
new file mode 100644
index 000000000..a0692afc5
--- /dev/null
+++ b/coreutils/df.c
@@ -0,0 +1,103 @@
1#include "internal.h"
2#include <stdio.h>
3#include <mntent.h>
4#include <sys/stat.h>
5#include <sys/vfs.h>
6
7const char df_usage[] = "df [filesystem ...]\n"
8"\n"
9"\tPrint the filesystem space used and space available.\n";
10
11
12static int
13df(const char * device, const char * mountPoint)
14{
15 struct statfs s;
16 long blocks_used;
17 long blocks_percent_used;
18
19 if ( statfs(mountPoint, &s) != 0 ) {
20 name_and_error(mountPoint);
21 return 1;
22 }
23
24 if ( s.f_blocks > 0 ) {
25 blocks_used = s.f_blocks - s.f_bfree;
26 blocks_percent_used = (long)
27 (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5);
28
29/*
30 printf(
31 "%-20s %7ld %7ld %7ld %5ld%% %s\n"
32 ,device
33 ,s.f_blocks
34 ,s.f_blocks - s.f_bfree
35 ,s.f_bavail
36 ,blocks_percent_used
37 ,mountPoint);
38*/
39
40 printf(
41 "%-20s %7.0f %7.0f %7.0f %5ld%% %s\n"
42 ,device
43 ,s.f_blocks * (s.f_bsize / 1024.0)
44 ,(s.f_blocks - s.f_bfree) * (s.f_bsize / 1024.0)
45 ,s.f_bavail * (s.f_bsize / 1024.0)
46 ,blocks_percent_used
47 ,mountPoint);
48
49 }
50
51 return 0;
52}
53
54extern int
55df_main(struct FileInfo * i, int argc, char * * argv)
56{
57 static const char header[] =
58 "Filesystem 1024-blocks Used Available Capacity Mounted on\n";
59 printf(header);
60
61 if ( argc > 1 ) {
62 struct mntent * mountEntry;
63 int status;
64
65 while ( argc > 1 ) {
66 if ( (mountEntry = findMountPoint(argv[1], "/etc/mtab")) == 0
67 && (mountEntry = findMountPoint(argv[1], "/proc/mounts")) == 0 )
68 {
69 fprintf(stderr, "%s: can't find mount point.\n"
70 ,argv[1]);
71 return 1;
72 }
73 status = df(mountEntry->mnt_fsname, mountEntry->mnt_dir);
74 if ( status != 0 )
75 return status;
76 argc--;
77 argv++;
78 }
79 return 0;
80 }
81 else {
82 FILE * mountTable;
83 struct mntent * mountEntry;
84
85 if ( (mountTable = setmntent("/etc/mtab", "r")) == 0
86 && (mountTable = setmntent("/proc/mounts", "r")) == 0
87 ) {
88 name_and_error("/etc/mtab");
89 return 1;
90 }
91
92 while ( (mountEntry = getmntent(mountTable)) != 0 ) {
93 int status = df(
94 mountEntry->mnt_fsname
95 ,mountEntry->mnt_dir);
96 if ( status != 0 )
97 return status;
98 }
99 endmntent(mountTable);
100 }
101
102 return 0;
103}
diff --git a/coreutils/length.c b/coreutils/length.c
new file mode 100644
index 000000000..284bbfdf9
--- /dev/null
+++ b/coreutils/length.c
@@ -0,0 +1,13 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5
6const char length_usage[] = "length string";
7
8int
9length_main(struct FileInfo * i, int argc, char * * argv)
10{
11 printf("%d\n", strlen(argv[1]));
12 return 0;
13}
diff --git a/coreutils/ln.c b/coreutils/ln.c
new file mode 100644
index 000000000..3e87b579e
--- /dev/null
+++ b/coreutils/ln.c
@@ -0,0 +1,52 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/stat.h>
4#include <sys/param.h>
5#include <errno.h>
6
7const char ln_usage[] = "ln [-s] [-f] original-name additional-name\n"
8"\n"
9"\tAdd a new name that refers to the same file as \"original-name\"\n"
10"\n"
11"\t-s:\tUse a \"symbolic\" link, instead of a \"hard\" link.\n"
12"\t-f:\tRemove existing destination files.\n";
13
14int
15ln_fn(const struct FileInfo * i)
16{
17 int status = 0;
18 char d[PATH_MAX];
19 const char * destination = i->destination;
20
21 if ( !i->makeSymbolicLink && (i->stat.st_mode & S_IFMT) == S_IFDIR ) {
22 fprintf(stderr, "Please use \"ln -s\" to link directories.\n");
23 return 1;
24 }
25
26 /*
27 * If the destination is a directory, create a file within it.
28 */
29 if ( is_a_directory(i->destination) ) {
30 destination = join_paths(
31 d
32 ,i->destination
33 ,&i->source[i->directoryLength]);
34 }
35
36 if ( i->force )
37 status = ( unlink(destination) && errno != ENOENT );
38
39 if ( status == 0 ) {
40 if ( i->makeSymbolicLink )
41 status = symlink(i->source, destination);
42 else
43 status = link(i->source, destination);
44 }
45
46 if ( status != 0 ) {
47 name_and_error(destination);
48 return 1;
49 }
50 else
51 return 0;
52}
diff --git a/coreutils/ls.c b/coreutils/ls.c
new file mode 100644
index 000000000..2566beea0
--- /dev/null
+++ b/coreutils/ls.c
@@ -0,0 +1,542 @@
1#include "internal.h"
2/*
3 * tiny-ls.c version 0.1.0: A minimalist 'ls'
4 * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/*
22 * To achieve a small memory footprint, this version of 'ls' doesn't do any
23 * file sorting, and only has the most essential command line switches
24 * (i.e. the ones I couldn't live without :-) All features which involve
25 * linking in substantial chunks of libc can be disabled.
26 *
27 * Although I don't really want to add new features to this program to
28 * keep it small, I *am* interested to receive bug fixes and ways to make
29 * it more portable.
30 *
31 * KNOWN BUGS:
32 * 1. messy output if you mix files and directories on the command line
33 * 2. ls -l of a directory doesn't give "total <blocks>" header
34 * 3. ls of a symlink to a directory doesn't list directory contents
35 * 4. hidden files can make column width too large
36 * NON-OPTIMAL BEHAVIOUR:
37 * 1. autowidth reads directories twice
38 * 2. if you do a short directory listing without filetype characters
39 * appended, there's no need to stat each one
40 * PORTABILITY:
41 * 1. requires lstat (BSD) - how do you do it without?
42 */
43
44#define FEATURE_USERNAME /* show username/groupnames (libc6 uses NSS) */
45#define FEATURE_TIMESTAMPS /* show file timestamps */
46#define FEATURE_AUTOWIDTH /* calculate terminal & column widths */
47#define FEATURE_FILETYPECHAR /* enable -p and -F */
48
49#undef OP_BUF_SIZE 1024 /* leave undefined for unbuffered output */
50
51#define TERMINAL_WIDTH 80 /* use 79 if your terminal has linefold bug */
52#define COLUMN_WIDTH 14 /* default if AUTOWIDTH not defined */
53#define COLUMN_GAP 2 /* includes the file type char, if present */
54
55/************************************************************************/
56
57#define HAS_REWINDDIR
58
59#if 1 /* FIXME libc 6 */
60# include <linux/types.h>
61#else
62# include <sys/types.h>
63#endif
64#include <sys/stat.h>
65#include <stdio.h>
66#include <unistd.h>
67#include <dirent.h>
68#include <errno.h>
69#include <stdio.h>
70#ifdef FEATURE_USERNAME
71#include <pwd.h>
72#include <grp.h>
73#endif
74#ifdef FEATURE_TIMESTAMPS
75#include <time.h>
76#endif
77
78#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
79#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
80#ifdef FEATURE_FILETYPECHAR
81#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
82#endif
83
84#ifndef MAJOR
85#define MAJOR(dev) (((dev)>>8)&0xff)
86#define MINOR(dev) ((dev)&0xff)
87#endif
88
89#define MODE1 "rwxrwxrwx"
90#define MODE0 "---------"
91#define SMODE1 "..s..s..t"
92#define SMODE0 "..S..S..T"
93
94/* The 9 mode bits to test */
95
96static const umode_t MBIT[] = {
97 S_IRUSR, S_IWUSR, S_IXUSR,
98 S_IRGRP, S_IWGRP, S_IXGRP,
99 S_IROTH, S_IWOTH, S_IXOTH
100};
101
102/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
103
104static const umode_t SBIT[] = {
105 0, 0, S_ISUID,
106 0, 0, S_ISGID,
107 0, 0, S_ISVTX
108};
109
110#define FMT_AUTO 0
111#define FMT_LONG 1 /* one record per line, extended info */
112#define FMT_SINGLE 2 /* one record per line */
113#define FMT_ROWS 3 /* print across rows */
114#define FMT_COLUMNS 3 /* fill columns (same, since we don't sort) */
115
116#define TIME_MOD 0
117#define TIME_CHANGE 1
118#define TIME_ACCESS 2
119
120#define DISP_FTYPE 1 /* show character for file type */
121#define DISP_EXEC 2 /* show '*' if regular executable file */
122#define DISP_HIDDEN 4 /* show files starting . (except . and ..) */
123#define DISP_DOT 8 /* show . and .. */
124#define DISP_NUMERIC 16 /* numeric uid and gid */
125#define DISP_FULLTIME 32 /* show extended time display */
126#define DIR_NOLIST 64 /* show directory as itself, not contents */
127#define DISP_DIRNAME 128 /* show directory name (for internal use) */
128#define DIR_RECURSE 256 /* -R (not yet implemented) */
129
130static unsigned char display_fmt = FMT_AUTO;
131static unsigned short opts = 0;
132static unsigned short column = 0;
133
134#ifdef FEATURE_AUTOWIDTH
135static unsigned short terminal_width = 0, column_width = 0;
136#else
137#define terminal_width TERMINAL_WIDTH
138#define column_width COLUMN_WIDTH
139#endif
140
141#ifdef FEATURE_TIMESTAMPS
142static unsigned char time_fmt = TIME_MOD;
143#endif
144
145#define wr(data,len) fwrite(data, 1, len, stdout)
146
147static void writenum(long val, short minwidth)
148{
149 char scratch[20];
150
151 char *p = scratch + sizeof(scratch);
152 short len = 0;
153 short neg = (val < 0);
154
155 if (neg) val = -val;
156 do
157 *--p = (val % 10) + '0', len++, val /= 10;
158 while (val);
159 if (neg)
160 *--p = '-', len++;
161 while (len < minwidth)
162 *--p = ' ', len++;
163 wr(p, len);
164 column += len;
165}
166
167static void newline(void)
168{
169 if (column > 0) {
170 wr("\n", 1);
171 column = 0;
172 }
173}
174
175static void tab(short col)
176{
177 static const char spaces[] = " ";
178 #define nspaces ((sizeof spaces)-1) /* null terminator! */
179
180 short n = col - column;
181
182 if (n > 0) {
183 column = col;
184 while (n > nspaces) {
185 wr(spaces, nspaces);
186 n -= nspaces;
187 }
188 /* must be 1...(sizeof spaces) left */
189 wr(spaces, n);
190 }
191 #undef nspaces
192}
193
194#ifdef FEATURE_FILETYPECHAR
195static char append_char(umode_t mode)
196{
197 if (!(opts & DISP_FTYPE))
198 return '\0';
199 if ((opts & DISP_EXEC) && S_ISREG(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
200 return '*';
201 return APPCHAR(mode);
202}
203#endif
204
205/**
206 **
207 ** Display a file or directory as a single item
208 ** (in either long or short format)
209 **
210 **/
211
212static void list_single(const char *name, struct stat *info)
213{
214 char scratch[20];
215 short len = strlen(name);
216#ifdef FEATURE_FILETYPECHAR
217 char append = append_char(info->st_mode);
218#endif
219
220 if (display_fmt == FMT_LONG) {
221 umode_t mode = info->st_mode;
222 int i;
223
224 scratch[0] = TYPECHAR(mode);
225 for (i=0; i<9; i++)
226 if (mode & SBIT[i])
227 scratch[i+1] = (mode & MBIT[i])
228 ? SMODE1[i]
229 : SMODE0[i];
230 else
231 scratch[i+1] = (mode & MBIT[i])
232 ? MODE1[i]
233 : MODE0[i];
234 newline();
235 wr(scratch, 10);
236 column=10;
237 writenum((long)info->st_nlink,(short)4);
238 fputs(" ", stdout);
239#ifdef FEATURE_USERNAME
240 if (!(opts & DISP_NUMERIC)) {
241 struct passwd *pw = getpwuid(info->st_uid);
242 if (pw)
243 fputs(pw->pw_name, stdout);
244 else
245 writenum((long)info->st_uid,(short)0);
246 } else
247#endif
248 writenum((long)info->st_uid,(short)0);
249 tab(24);
250#ifdef FEATURE_USERNAME
251 if (!(opts & DISP_NUMERIC)) {
252 struct group *gr = getgrgid(info->st_gid);
253 if (gr)
254 fputs(gr->gr_name, stdout);
255 else
256 writenum((long)info->st_gid,(short)0);
257 } else
258#endif
259 writenum((long)info->st_gid,(short)0);
260 tab(33);
261 if (S_ISBLK(mode) || S_ISCHR(mode)) {
262 writenum((long)MAJOR(info->st_rdev),(short)3);
263 fputs(", ", stdout);
264 writenum((long)MINOR(info->st_rdev),(short)3);
265 }
266 else
267 writenum((long)info->st_size,(short)8);
268 fputs(" ", stdout);
269#ifdef FEATURE_TIMESTAMPS
270 {
271 time_t cal;
272 char *string;
273
274 switch(time_fmt) {
275 case TIME_CHANGE:
276 cal=info->st_ctime; break;
277 case TIME_ACCESS:
278 cal=info->st_atime; break;
279 default:
280 cal=info->st_mtime; break;
281 }
282 string=ctime(&cal);
283 if (opts & DISP_FULLTIME)
284 wr(string,24);
285 else {
286 time_t age = time(NULL) - cal;
287 wr(string+4,7); /* mmm_dd_ */
288 if(age < 3600L*24*365/2 && age > -15*60)
289 /* hh:mm if less than 6 months old */
290 wr(string+11,5);
291 else
292 /* _yyyy otherwise */
293 wr(string+19,5);
294 }
295 wr(" ", 1);
296 }
297#else
298 fputs("--- -- ----- ", stdout);
299#endif
300 wr(name, len);
301 if (S_ISLNK(mode)) {
302 wr(" -> ", 4);
303 len = readlink(name, scratch, sizeof scratch);
304 if (len > 0) fwrite(scratch, 1, len, stdout);
305#ifdef FEATURE_FILETYPECHAR
306 /* show type of destination */
307 if (opts & DISP_FTYPE) {
308 if (!stat(name, info)) {
309 append = append_char(info->st_mode);
310 if (append)
311 fputc(append, stdout);
312 }
313 }
314#endif
315 }
316#ifdef FEATURE_FILETYPECHAR
317 else if (append)
318 wr(&append, 1);
319#endif
320 } else {
321 static short nexttab = 0;
322
323 /* sort out column alignment */
324 if (column == 0)
325 ; /* nothing to do */
326 else if (display_fmt == FMT_SINGLE)
327 newline();
328 else {
329 if (nexttab + column_width > terminal_width
330#ifndef FEATURE_AUTOWIDTH
331 || nexttab + len >= terminal_width
332#endif
333 )
334 newline();
335 else
336 tab(nexttab);
337 }
338 /* work out where next column starts */
339#ifdef FEATURE_AUTOWIDTH
340 /* we know the calculated width is big enough */
341 nexttab = column + column_width + COLUMN_GAP;
342#else
343 /* might cover more than one fixed-width column */
344 nexttab = column;
345 do
346 nexttab += column_width + COLUMN_GAP;
347 while (nexttab < (column + len + COLUMN_GAP));
348#endif
349 /* now write the data */
350 wr(name, len);
351 column = column + len;
352#ifdef FEATURE_FILETYPECHAR
353 if (append)
354 wr(&append, 1), column++;
355#endif
356 }
357}
358
359/**
360 **
361 ** List the given file or directory, expanding a directory
362 ** to show its contents if required
363 **
364 **/
365
366static int list_item(const char *name)
367{
368 struct stat info;
369 DIR *dir;
370 struct dirent *entry;
371 char fullname[MAXNAMLEN+1], *fnend;
372
373 if (lstat(name, &info))
374 goto listerr;
375
376 if (!S_ISDIR(info.st_mode) ||
377 (opts & DIR_NOLIST)) {
378 list_single(name, &info);
379 return 0;
380 }
381
382 /* Otherwise, it's a directory we want to list the contents of */
383
384 if (opts & DISP_DIRNAME) { /* identify the directory */
385 if (column)
386 wr("\n\n", 2), column = 0;
387 wr(name, strlen(name));
388 wr(":\n", 2);
389 }
390
391 dir = opendir(name);
392 if (!dir) goto listerr;
393#ifdef FEATURE_AUTOWIDTH
394 column_width = 0;
395 while ((entry = readdir(dir)) != NULL) {
396 short w = strlen(entry->d_name);
397 if (column_width < w)
398 column_width = w;
399 }
400#ifdef HAS_REWINDDIR
401 rewinddir(dir);
402#else
403 closedir(dir);
404 dir = opendir(name);
405 if (!dir) goto listerr;
406#endif
407#endif
408
409 /* List the contents */
410
411 strcpy(fullname,name); /* *** ignore '.' by itself */
412 fnend=fullname+strlen(fullname);
413 if (fnend[-1] != '/')
414 *fnend++ = '/';
415
416 while ((entry = readdir(dir)) != NULL) {
417 const char *en=entry->d_name;
418 if (en[0] == '.') {
419 if (!en[1] || (en[1] == '.' && !en[2])) { /* . or .. */
420 if (!(opts & DISP_DOT))
421 continue;
422 }
423 else if (!(opts & DISP_HIDDEN))
424 continue;
425 }
426 /* FIXME: avoid stat if not required */
427 strcpy(fnend, entry->d_name);
428 if (lstat(fullname, &info))
429 goto direrr; /* (shouldn't fail) */
430 list_single(entry->d_name, &info);
431 }
432 closedir(dir);
433 return 0;
434
435direrr:
436 closedir(dir);
437listerr:
438 newline();
439 name_and_error(name);
440 return 1;
441}
442
443const char ls_usage[] = "Usage: ls [-1a"
444#ifdef FEATURE_TIMESTAMPS
445 "c"
446#endif
447 "d"
448#ifdef FEATURE_TIMESTAMPS
449 "e"
450#endif
451 "ln"
452#ifdef FEATURE_FILETYPECHAR
453 "p"
454#endif
455#ifdef FEATURE_TIMESTAMPS
456 "u"
457#endif
458 "xAC"
459#ifdef FEATURE_FILETYPECHAR
460 "F"
461#endif
462#ifdef FEATURE_RECURSIVE
463 "R"
464#endif
465 "] [filenames...]\n";
466
467extern int
468ls_main(struct FileInfo * not_used, int argc, char * * argv)
469{
470 int argi=1, i;
471
472 /* process options */
473 while (argi < argc && argv[argi][0] == '-') {
474 const char *p = &argv[argi][1];
475
476 if (!*p) goto print_usage_message; /* "-" by itself not allowed */
477 if (*p == '-') {
478 if (!p[1]) { /* "--" forces end of options */
479 argi++;
480 break;
481 }
482 /* it's a long option name - we don't support them */
483 goto print_usage_message;
484 }
485
486 while (*p)
487 switch (*p++) {
488 case 'l': display_fmt = FMT_LONG; break;
489 case '1': display_fmt = FMT_SINGLE; break;
490 case 'x': display_fmt = FMT_ROWS; break;
491 case 'C': display_fmt = FMT_COLUMNS; break;
492#ifdef FEATURE_FILETYPECHAR
493 case 'p': opts |= DISP_FTYPE; break;
494 case 'F': opts |= DISP_FTYPE|DISP_EXEC; break;
495#endif
496 case 'A': opts |= DISP_HIDDEN; break;
497 case 'a': opts |= DISP_HIDDEN|DISP_DOT; break;
498 case 'n': opts |= DISP_NUMERIC; break;
499 case 'd': opts |= DIR_NOLIST; break;
500#ifdef FEATURE_RECURSIVE
501 case 'R': opts |= DIR_RECURSE; break;
502#endif
503#ifdef FEATURE_TIMESTAMPS
504 case 'u': time_fmt = TIME_ACCESS; break;
505 case 'c': time_fmt = TIME_CHANGE; break;
506 case 'e': opts |= DISP_FULLTIME; break;
507#endif
508 default: goto print_usage_message;
509 }
510
511 argi++;
512 }
513
514 /* choose a display format */
515 if (display_fmt == FMT_AUTO)
516 display_fmt = isatty(STDOUT_FILENO) ? FMT_COLUMNS : FMT_SINGLE;
517 if (argi < argc - 1)
518 opts |= DISP_DIRNAME; /* 2 or more items? label directories */
519#ifdef FEATURE_AUTOWIDTH
520 /* could add a -w option and/or TIOCGWINSZ call */
521 if (terminal_width < 1) terminal_width = TERMINAL_WIDTH;
522
523 for (i = argi; i < argc; i++) {
524 int len = strlen(argv[i]);
525 if (column_width < len)
526 column_width = len;
527 }
528#endif
529
530 /* process files specified, or current directory if none */
531 i=0;
532 if (argi == argc)
533 i = list_item(".");
534 while (argi < argc)
535 i |= list_item(argv[argi++]);
536 newline();
537 return i;
538
539print_usage_message:
540 usage(ls_usage);
541 return 1;
542}
diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c
new file mode 100644
index 000000000..8f1fa04db
--- /dev/null
+++ b/coreutils/mkdir.c
@@ -0,0 +1,58 @@
1#include "internal.h"
2#include <errno.h>
3#include <sys/param.h>
4
5const char mkdir_usage[] = "mkdir [-m mode] directory [directory ...]\n"
6"\tCreate directories.\n"
7"\n"
8"\t-m mode:\tSpecifiy the mode for the new directory\n"
9"\t\tunder the argument directory.";
10
11/*make directories skipping the last part of the path. Used here and by untar*/
12int mkdir_until(const char *fpath, const struct FileInfo * fi)
13{
14 char path[PATH_MAX];
15 char * s = path;
16
17 strcpy(path, fpath);
18 if ( s[0] == '\0' && s[1] == '\0' ) {
19 usage(mkdir_usage);
20 return 1;
21 }
22 s++;
23 while ( *s != '\0' ) {
24 if ( *s == '/' ) {
25 int status;
26
27 *s = '\0';
28 status = mkdir(path, (fi?fi->orWithMode:0700) );
29 *s = '/';
30
31 if ( status != 0 ) {
32 if ( errno != EEXIST ) {
33 name_and_error(fpath);
34 return 1;
35 }
36 }
37
38 }
39 s++;
40 }
41 return 0;
42}
43
44int
45mkdir_fn(const struct FileInfo * i)
46{
47 if ( i->makeParentDirectories ) {
48 if(mkdir_until(i->source, i)) return 1;
49 }
50
51 if ( mkdir(i->source, i->orWithMode) != 0 && errno != EEXIST ) {
52 name_and_error(i->source);
53 return 1;
54 }
55 else
56 return 0;
57}
58
diff --git a/coreutils/mknod.c b/coreutils/mknod.c
new file mode 100644
index 000000000..b18394bec
--- /dev/null
+++ b/coreutils/mknod.c
@@ -0,0 +1,52 @@
1#include "internal.h"
2#include <errno.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <fcntl.h>
6#include <unistd.h>
7
8const char mknod_usage[] = "mknod file b|c|u|p major minor\n"
9"\tMake special files.\n"
10"\n"
11"\tb:\tMake a block (buffered) device.\n"
12"\tc or u:\tMake a character (un-buffered) device.\n"
13"\tp:\tMake a named pipe. Major and minor are ignored for named pipes.\n";
14
15int
16mknod_main(struct FileInfo * i, int argc, char * * argv)
17{
18 mode_t mode = 0;
19 dev_t dev = 0;
20
21 switch(argv[2][0]) {
22 case 'c':
23 case 'u':
24 mode = S_IFCHR;
25 break;
26 case 'b':
27 mode = S_IFBLK;
28 break;
29 case 'p':
30 mode = S_IFIFO;
31 break;
32 default:
33 usage(mknod_usage);
34 return 1;
35 }
36
37 if ( mode == S_IFCHR || mode == S_IFBLK ) {
38 dev = (atoi(argv[3]) << 8) | atoi(argv[4]);
39 if ( argc != 5 ) {
40 usage(mknod_usage);
41 return 1;
42 }
43 }
44
45 mode |= 0666;
46
47 if ( mknod(argv[1], mode, dev) != 0 ) {
48 name_and_error(argv[1]);
49 return 1;
50 }
51 return 0;
52}
diff --git a/coreutils/mv.c b/coreutils/mv.c
new file mode 100644
index 000000000..22c4a1207
--- /dev/null
+++ b/coreutils/mv.c
@@ -0,0 +1,38 @@
1#include "internal.h"
2#include <stdio.h>
3#include <errno.h>
4
5const char mv_usage[] = "mv source-file destination-file\n"
6"\t\tmv source-file [source-file ...] destination-directory\n"
7"\n"
8"\tMove the source files to the destination.\n"
9"\n";
10
11extern int
12mv_fn(const struct FileInfo * i)
13{
14 struct stat destination_stat;
15 char d[1024];
16 struct FileInfo n;
17
18 if ( stat(i->destination, &destination_stat) == 0 ) {
19 if ( i->stat.st_ino == destination_stat.st_ino
20 && i->stat.st_dev == destination_stat.st_dev )
21 return 0; /* Move file to itself. */
22 }
23 if ( (destination_stat.st_mode & S_IFMT) == S_IFDIR ) {
24 n = *i;
25 n.destination = join_paths(d, i->destination, basename(i->source));
26 i = &n;
27 }
28 if ( rename(i->source, i->destination) == 0 )
29 return 0;
30 else if ( errno == EXDEV && is_a_directory(i->source) ) {
31 fprintf(stderr
32 ,"%s: Can't move directory across filesystems.\n"
33 ,i->source);
34 return 1;
35 }
36 else
37 return cp_fn(i);
38}
diff --git a/coreutils/printf.c b/coreutils/printf.c
new file mode 100644
index 000000000..e79843c80
--- /dev/null
+++ b/coreutils/printf.c
@@ -0,0 +1,531 @@
1// I may still need some more cleaning...fix my error checking
2
3#include "internal.h"
4#ifdef BB_PRINTF
5
6/* printf - format and print data
7 Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23/* Usage: printf format [argument...]
24
25 A front end to the printf function that lets it be used from the shell.
26
27 Backslash escapes:
28
29 \" = double quote
30 \\ = backslash
31 \a = alert (bell)
32 \b = backspace
33 \c = produce no further output
34 \f = form feed
35 \n = new line
36 \r = carriage return
37 \t = horizontal tab
38 \v = vertical tab
39 \0ooo = octal number (ooo is 0 to 3 digits)
40 \xhhh = hexadecimal number (hhh is 1 to 3 digits)
41
42 Additional directive:
43
44 %b = print an argument string, interpreting backslash escapes
45
46 The `format' argument is re-used as many times as necessary
47 to convert all of the given arguments.
48
49 David MacKenzie <djm@gnu.ai.mit.edu> */
50
51
52// 19990508 Busy Boxed! Dave Cinege
53
54#include <unistd.h>
55#include <stdio.h>
56#include <sys/types.h>
57#include <getopt.h>
58#include <sys/stat.h>
59#include <string.h>
60#include <errno.h>
61#include <stdlib.h>
62#include <fcntl.h>
63#include <ctype.h>
64#include <libintl.h>
65
66
67#ifndef S_IFMT
68# define S_IFMT 0170000
69#endif
70#if !defined(S_ISBLK) && defined(S_IFBLK)
71# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
72#endif
73#if !defined(S_ISCHR) && defined(S_IFCHR)
74# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
75#endif
76#if !defined(S_ISDIR) && defined(S_IFDIR)
77# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
78#endif
79#if !defined(S_ISREG) && defined(S_IFREG)
80# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
81#endif
82#if !defined(S_ISFIFO) && defined(S_IFIFO)
83# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
84#endif
85#if !defined(S_ISLNK) && defined(S_IFLNK)
86# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
87#endif
88#if !defined(S_ISSOCK) && defined(S_IFSOCK)
89# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
90#endif
91#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
92# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
93# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
94#endif
95#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
96# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
97#endif
98
99#define IN_CTYPE_DOMAIN(c) 1
100
101#ifdef isblank
102# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c))
103#else
104# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
105#endif
106#ifdef isgraph
107# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c))
108#else
109# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c))
110#endif
111
112#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
113#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c))
114#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
115#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
116#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
117#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c))
118#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
119#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
120#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
121#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
122#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
123
124#define isodigit(c) ((c) >= '0' && (c) <= '7')
125#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
126#define octtobin(c) ((c) - '0')
127
128char *xmalloc ();
129
130static double xstrtod __P ((char *s));
131static int print_esc __P ((char *escstart));
132static int print_formatted __P ((char *format, int argc, char **argv));
133static long xstrtol __P ((char *s));
134static unsigned long xstrtoul __P ((char *s));
135static void print_direc __P ((char *start, size_t length, int field_width, int precision, char *argument));
136static void print_esc_char __P ((int c));
137static void print_esc_string __P ((char *str));
138static void verify __P ((char *s, char *end));
139
140/* The value to return to the calling program. */
141static int exit_status;
142
143const char printf_usage[] = "Usage: printf format [argument...]\n";
144
145int
146printf_main(struct FileInfo * i, int argc, char * * argv)
147{
148 char *format;
149 int args_used;
150
151 exit_status = 0;
152
153 format = argv[1];
154 argc -= 2;
155 argv += 2;
156
157 do
158 {
159 args_used = print_formatted (format, argc, argv);
160 argc -= args_used;
161 argv += args_used;
162 }
163 while (args_used > 0 && argc > 0);
164
165/*
166 if (argc > 0)
167 fprintf(stderr, "excess args ignored");
168*/
169
170 exit (exit_status);
171}
172
173/* Print the text in FORMAT, using ARGV (with ARGC elements) for
174 arguments to any `%' directives.
175 Return the number of elements of ARGV used. */
176
177static int
178print_formatted (char *format, int argc, char **argv)
179{
180 int save_argc = argc; /* Preserve original value. */
181 char *f; /* Pointer into `format'. */
182 char *direc_start; /* Start of % directive. */
183 size_t direc_length; /* Length of % directive. */
184 int field_width; /* Arg to first '*', or -1 if none. */
185 int precision; /* Arg to second '*', or -1 if none. */
186
187 for (f = format; *f; ++f)
188 {
189 switch (*f)
190 {
191 case '%':
192 direc_start = f++;
193 direc_length = 1;
194 field_width = precision = -1;
195 if (*f == '%')
196 {
197 putchar ('%');
198 break;
199 }
200 if (*f == 'b')
201 {
202 if (argc > 0)
203 {
204 print_esc_string (*argv);
205 ++argv;
206 --argc;
207 }
208 break;
209 }
210 if (strchr ("-+ #", *f))
211 {
212 ++f;
213 ++direc_length;
214 }
215 if (*f == '*')
216 {
217 ++f;
218 ++direc_length;
219 if (argc > 0)
220 {
221 field_width = xstrtoul (*argv);
222 ++argv;
223 --argc;
224 }
225 else
226 field_width = 0;
227 }
228 else
229 while (ISDIGIT (*f))
230 {
231 ++f;
232 ++direc_length;
233 }
234 if (*f == '.')
235 {
236 ++f;
237 ++direc_length;
238 if (*f == '*')
239 {
240 ++f;
241 ++direc_length;
242 if (argc > 0)
243 {
244 precision = xstrtoul (*argv);
245 ++argv;
246 --argc;
247 }
248 else
249 precision = 0;
250 }
251 else
252 while (ISDIGIT (*f))
253 {
254 ++f;
255 ++direc_length;
256 }
257 }
258 if (*f == 'l' || *f == 'L' || *f == 'h')
259 {
260 ++f;
261 ++direc_length;
262 }
263 /*
264 if (!strchr ("diouxXfeEgGcs", *f))
265 fprintf(stderr, "%%%c: invalid directive", *f);
266 */
267 ++direc_length;
268 if (argc > 0)
269 {
270 print_direc (direc_start, direc_length, field_width,
271 precision, *argv);
272 ++argv;
273 --argc;
274 }
275 else
276 print_direc (direc_start, direc_length, field_width,
277 precision, "");
278 break;
279
280 case '\\':
281 f += print_esc (f);
282 break;
283
284 default:
285 putchar (*f);
286 }
287 }
288
289 return save_argc - argc;
290}
291
292/* Print a \ escape sequence starting at ESCSTART.
293 Return the number of characters in the escape sequence
294 besides the backslash. */
295
296static int
297print_esc (char *escstart)
298{
299 register char *p = escstart + 1;
300 int esc_value = 0; /* Value of \nnn escape. */
301 int esc_length; /* Length of \nnn escape. */
302
303 /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
304 if (*p == 'x')
305 {
306 for (esc_length = 0, ++p;
307 esc_length < 3 && ISXDIGIT (*p);
308 ++esc_length, ++p)
309 esc_value = esc_value * 16 + hextobin (*p);
310/* if (esc_length == 0)
311 fprintf(stderr, "missing hex in esc");
312*/
313 putchar (esc_value);
314 }
315 else if (*p == '0')
316 {
317 for (esc_length = 0, ++p;
318 esc_length < 3 && isodigit (*p);
319 ++esc_length, ++p)
320 esc_value = esc_value * 8 + octtobin (*p);
321 putchar (esc_value);
322 }
323 else if (strchr ("\"\\abcfnrtv", *p))
324 print_esc_char (*p++);
325/* else
326 fprintf(stderr, "\\%c: invalid esc", *p);
327*/
328 return p - escstart - 1;
329}
330
331/* Output a single-character \ escape. */
332
333static void
334print_esc_char (int c)
335{
336 switch (c)
337 {
338 case 'a': /* Alert. */
339 putchar (7);
340 break;
341 case 'b': /* Backspace. */
342 putchar (8);
343 break;
344 case 'c': /* Cancel the rest of the output. */
345 exit (0);
346 break;
347 case 'f': /* Form feed. */
348 putchar (12);
349 break;
350 case 'n': /* New line. */
351 putchar (10);
352 break;
353 case 'r': /* Carriage return. */
354 putchar (13);
355 break;
356 case 't': /* Horizontal tab. */
357 putchar (9);
358 break;
359 case 'v': /* Vertical tab. */
360 putchar (11);
361 break;
362 default:
363 putchar (c);
364 break;
365 }
366}
367
368/* Print string STR, evaluating \ escapes. */
369
370static void
371print_esc_string (char *str)
372{
373 for (; *str; str++)
374 if (*str == '\\')
375 str += print_esc (str);
376 else
377 putchar (*str);
378}
379
380static void
381print_direc (char *start, size_t length, int field_width, int precision, char *argument)
382{
383 char *p; /* Null-terminated copy of % directive. */
384
385 p = xmalloc ((unsigned) (length + 1));
386 strncpy (p, start, length);
387 p[length] = 0;
388
389 switch (p[length - 1])
390 {
391 case 'd':
392 case 'i':
393 if (field_width < 0)
394 {
395 if (precision < 0)
396 printf (p, xstrtol (argument));
397 else
398 printf (p, precision, xstrtol (argument));
399 }
400 else
401 {
402 if (precision < 0)
403 printf (p, field_width, xstrtol (argument));
404 else
405 printf (p, field_width, precision, xstrtol (argument));
406 }
407 break;
408
409 case 'o':
410 case 'u':
411 case 'x':
412 case 'X':
413 if (field_width < 0)
414 {
415 if (precision < 0)
416 printf (p, xstrtoul (argument));
417 else
418 printf (p, precision, xstrtoul (argument));
419 }
420 else
421 {
422 if (precision < 0)
423 printf (p, field_width, xstrtoul (argument));
424 else
425 printf (p, field_width, precision, xstrtoul (argument));
426 }
427 break;
428
429 case 'f':
430 case 'e':
431 case 'E':
432 case 'g':
433 case 'G':
434 if (field_width < 0)
435 {
436 if (precision < 0)
437 printf (p, xstrtod (argument));
438 else
439 printf (p, precision, xstrtod (argument));
440 }
441 else
442 {
443 if (precision < 0)
444 printf (p, field_width, xstrtod (argument));
445 else
446 printf (p, field_width, precision, xstrtod (argument));
447 }
448 break;
449
450 case 'c':
451 printf (p, *argument);
452 break;
453
454 case 's':
455 if (field_width < 0)
456 {
457 if (precision < 0)
458 printf (p, argument);
459 else
460 printf (p, precision, argument);
461 }
462 else
463 {
464 if (precision < 0)
465 printf (p, field_width, argument);
466 else
467 printf (p, field_width, precision, argument);
468 }
469 break;
470 }
471
472 free (p);
473}
474
475static unsigned long
476xstrtoul (char *s)
477{
478 char *end;
479 unsigned long val;
480
481 errno = 0;
482 val = strtoul (s, &end, 0);
483 verify (s, end);
484 return val;
485}
486
487static long
488xstrtol (char *s)
489{
490 char *end;
491 long val;
492
493 errno = 0;
494 val = strtol (s, &end, 0);
495 verify (s, end);
496 return val;
497}
498
499static double
500xstrtod (char *s)
501{
502 char *end;
503 double val;
504
505 errno = 0;
506 val = strtod (s, &end);
507 verify (s, end);
508 return val;
509}
510
511static void
512verify (char *s, char *end)
513{
514 if (errno)
515 {
516 fprintf(stderr, "%s", s);
517 exit_status = 1;
518 }
519 else if (*end)
520 {
521 /*
522 if (s == end)
523 fprintf(stderr, "%s: expected numeric", s);
524 else
525 fprintf(stderr, "%s: not completely converted", s);
526 */
527 exit_status = 1;
528 }
529}
530
531#endif
diff --git a/coreutils/pwd.c b/coreutils/pwd.c
new file mode 100644
index 000000000..d9ab54e48
--- /dev/null
+++ b/coreutils/pwd.c
@@ -0,0 +1,18 @@
1#include "internal.h"
2#include <stdio.h>
3
4const char pwd_usage[] = "Print the current directory.\n";
5
6extern int
7pwd_main(struct FileInfo * i, int argc, char * * argv)
8{
9 char buf[1024];
10
11 if ( getcwd(buf, sizeof(buf)) == NULL ) {
12 name_and_error("get working directory");
13 return 1;
14 }
15
16 printf("%s\n", buf);
17 return 0;
18}
diff --git a/coreutils/rm.c b/coreutils/rm.c
new file mode 100644
index 000000000..dc35b0297
--- /dev/null
+++ b/coreutils/rm.c
@@ -0,0 +1,30 @@
1#include "internal.h"
2#include <errno.h>
3
4const char rm_usage[] = "rm [-r] file [file ...]\n"
5"\n"
6"\tDelete files.\n"
7"\n"
8"\t-r:\tRecursively remove files and directories.\n";
9
10extern int
11rm_main(struct FileInfo * i, int argc, char * * argv)
12{
13 i->processDirectoriesAfterTheirContents = 1;
14 return monadic_main(i, argc, argv);
15}
16
17extern int
18rm_fn(const struct FileInfo * i)
19{
20 if ( i->recursive
21 && !i->isSymbolicLink
22 && (i->stat.st_mode & S_IFMT) == S_IFDIR )
23 return rmdir_fn(i);
24 else if ( unlink(i->source) != 0 && errno != ENOENT && !i->force ) {
25 name_and_error(i->source);
26 return 1;
27 }
28 else
29 return 0;
30}
diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c
new file mode 100644
index 000000000..069e68546
--- /dev/null
+++ b/coreutils/rmdir.c
@@ -0,0 +1,17 @@
1#include "internal.h"
2#include <errno.h>
3
4const char rmdir_usage[] = "rmdir directory [directory ...]\n"
5"\n"
6"\tDelete directories.\n";
7
8extern int
9rmdir_fn(const struct FileInfo * i)
10{
11 if ( rmdir(i->source) != 0 && errno != ENOENT && !i->force ) {
12 name_and_error(i->source);
13 return 1;
14 }
15 else
16 return 0;
17}
diff --git a/coreutils/sleep.c b/coreutils/sleep.c
new file mode 100644
index 000000000..e48e14b2f
--- /dev/null
+++ b/coreutils/sleep.c
@@ -0,0 +1,15 @@
1#include "internal.h"
2#include <stdio.h>
3
4const char sleep_usage[] = "sleep seconds\n"
5"\n"
6"\tPause program execution for the given number of seconds.\n";
7
8extern int
9sleep_main(struct FileInfo * i, int argc, char * * argv)
10{
11 if ( sleep(atoi(argv[1])) != 0 )
12 return -1;
13 else
14 return 0;
15}
diff --git a/coreutils/sync.c b/coreutils/sync.c
new file mode 100644
index 000000000..6fa5b380b
--- /dev/null
+++ b/coreutils/sync.c
@@ -0,0 +1,11 @@
1#include "internal.h"
2
3const char sync_usage[] = "sync\n"
4"\n"
5"\tWrite all buffered filesystem blocks to disk.\n";
6
7extern int
8sync_main(struct FileInfo * i, int argc, char * * argv)
9{
10 return sync();
11}
diff --git a/coreutils/touch.c b/coreutils/touch.c
new file mode 100644
index 000000000..ca4b98108
--- /dev/null
+++ b/coreutils/touch.c
@@ -0,0 +1,20 @@
1#include "internal.h"
2#include <sys/types.h>
3#include <stdio.h>
4#include <utime.h>
5
6const char touch_usage[] = "touch [-c] file [file ...]\n"
7"\n"
8"\tUpdate the last-modified date on the given file[s].\n";
9
10extern int
11touch_fn(const struct FileInfo * i)
12{
13 if ( (utime(i->source, 0) != 0) && (i->create != 1) ) {
14 if ( fopen(i->source, "w") == NULL ) {
15 name_and_error(i->source);
16 return 1;
17 }
18 }
19 return 0;
20}
diff --git a/cp.c b/cp.c
new file mode 100644
index 000000000..078a57c56
--- /dev/null
+++ b/cp.c
@@ -0,0 +1,89 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/stat.h>
4#include <sys/fcntl.h>
5#include <sys/param.h>
6#include <errno.h>
7
8const char cp_usage[] = "cp [-r] source-file destination-file\n"
9"\t\tcp [-r] source-file [source-file ...] destination-directory\n"
10"\n"
11"\tCopy the source files to the destination.\n"
12"\n"
13"\t-r:\tRecursively copy all files and directories\n"
14"\t\tunder the argument directory.";
15
16extern int
17cp_fn(const struct FileInfo * i)
18{
19 int sourceFd;
20 int destinationFd;
21 const char * destination = i->destination;
22 struct stat destination_stat;
23 int status;
24 char buf[8192];
25 char d[PATH_MAX];
26
27 if ( (i->stat.st_mode & S_IFMT) == S_IFDIR ) {
28 if ( mkdir(destination, i->stat.st_mode & ~S_IFMT)
29 != 0 && errno != EEXIST ) {
30 name_and_error(destination);
31 return 1;
32 }
33 return 0;
34 }
35 if ( (sourceFd = open(i->source, O_RDONLY)) < 0 ) {
36 name_and_error(i->source);
37 return 1;
38 }
39 if ( stat(destination, &destination_stat) == 0 ) {
40 if ( i->stat.st_ino == destination_stat.st_ino
41 && i->stat.st_dev == destination_stat.st_dev ) {
42 fprintf(stderr
43 ,"copy of %s to %s would copy file to itself.\n"
44 ,i->source
45 ,destination);
46 close(sourceFd);
47 return 1;
48 }
49 }
50 /*
51 * If the destination is a directory, create a file within it.
52 */
53 if ( (destination_stat.st_mode & S_IFMT) == S_IFDIR ) {
54 destination = join_paths(
55 d
56 ,i->destination
57 ,&i->source[i->directoryLength]);
58
59 if ( stat(destination, &destination_stat) == 0 ) {
60 if ( i->stat.st_ino == destination_stat.st_ino
61 && i->stat.st_dev == destination_stat.st_dev ) {
62 fprintf(stderr
63 ,"copy of %s to %s would copy file to itself.\n"
64 ,i->source
65 ,destination);
66 close(sourceFd);
67 return 1;
68 }
69 }
70 }
71
72 destinationFd = creat(destination, i->stat.st_mode & 07777);
73
74 while ( (status = read(sourceFd, buf, sizeof(buf))) > 0 ) {
75 if ( write(destinationFd, buf, status) != status ) {
76 name_and_error(destination);
77 close(sourceFd);
78 close(destinationFd);
79 return 1;
80 }
81 }
82 close(sourceFd);
83 close(destinationFd);
84 if ( status < 0 ) {
85 name_and_error(i->source);
86 return 1;
87 }
88 return 0;
89}
diff --git a/date.c b/date.c
new file mode 100644
index 000000000..a52a9a4a8
--- /dev/null
+++ b/date.c
@@ -0,0 +1,305 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <errno.h>
4#include <sys/time.h>
5#include <unistd.h>
6#include <time.h>
7#include <stdio.h>
8#include <getopt.h>
9
10
11/* This 'date' command supports only 2 time setting formats,
12 all the GNU strftime stuff (its in libc, lets use it),
13 setting time using UTC and displaying int, as well as
14 an RFC 822 complient date output for shell scripting
15 mail commands */
16
17const char date_usage[] = "date [-uR] [+FORMAT|+%f] [ [-s|-d] MMDDhhmm[[CC]YY]\n | [[[[CCYY.]MM.DD-]hh:mm[:ss]]]] ]";
18
19static struct option const long_options[] =
20{
21 {"date", required_argument, NULL, 'd'},
22 /* {"rfc-822", no_argument, NULL, 'R'},
23 {"set", required_argument, NULL, 's'},
24 {"uct", no_argument, NULL, 'u'},
25 {"utc", no_argument, NULL, 'u'},
26 {"universal", no_argument, NULL, 'u'}, */
27 {NULL, 0, NULL, 0}
28};
29
30
31
32/* Input parsing code is always bulky - used heavy duty libc stuff as
33 much as possible, missed out a lot of bounds checking */
34
35/* Default input handling to save suprising some people */
36
37struct tm *
38date_conv_time(struct tm *tm_time, const char *t_string) {
39 int nr;
40
41 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
42 &(tm_time->tm_mon),
43 &(tm_time->tm_mday),
44 &(tm_time->tm_hour),
45 &(tm_time->tm_min),
46 &(tm_time->tm_year));
47
48 if(nr < 4 || nr > 5) {
49 fprintf(stderr, "date: invalid date `%s'\n", t_string);
50 exit(1);
51 }
52
53 /* correct for century - minor Y2K problem here? */
54 if(tm_time->tm_year >= 1900)
55 tm_time->tm_year -= 1900;
56 /* adjust date */
57 tm_time->tm_mon -= 1;
58
59 return(tm_time);
60
61}
62
63
64/* The new stuff for LRP */
65
66struct tm *
67date_conv_ftime(struct tm *tm_time, const char *t_string) {
68 struct tm itm_time, jtm_time, ktm_time, \
69 ltm_time, mtm_time, ntm_time;
70
71 itm_time = *tm_time;
72 jtm_time = *tm_time;
73 ktm_time = *tm_time;
74 ltm_time = *tm_time;
75 mtm_time = *tm_time;
76 ntm_time = *tm_time;
77
78 /* Parse input and assign appropriately to tm_time */
79
80 if(sscanf(t_string, "%d:%d:%d",
81 &itm_time.tm_hour,
82 &itm_time.tm_min,
83 &itm_time.tm_sec) == 3 ) {
84
85 *tm_time = itm_time;
86 return(tm_time);
87
88 } else if (sscanf(t_string, "%d:%d",
89 &jtm_time.tm_hour,
90 &jtm_time.tm_min) == 2) {
91
92 *tm_time = jtm_time;
93 return(tm_time);
94
95 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
96 &ktm_time.tm_mon,
97 &ktm_time.tm_mday,
98 &ktm_time.tm_hour,
99 &ktm_time.tm_min,
100 &ktm_time.tm_sec) == 5) {
101
102 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
103 *tm_time = ktm_time;
104 return(tm_time);
105
106 } else if (sscanf(t_string, "%d.%d-%d:%d",
107 &ltm_time.tm_mon,
108 &ltm_time.tm_mday,
109 &ltm_time.tm_hour,
110 &ltm_time.tm_min) == 4) {
111
112 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
113 *tm_time = ltm_time;
114 return(tm_time);
115
116 } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d",
117 &mtm_time.tm_year,
118 &mtm_time.tm_mon,
119 &mtm_time.tm_mday,
120 &mtm_time.tm_hour,
121 &mtm_time.tm_min,
122 &mtm_time.tm_sec) == 6) {
123
124 mtm_time.tm_year -= 1900; /* Adjust years */
125 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
126 *tm_time = mtm_time;
127 return(tm_time);
128
129 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
130 &ntm_time.tm_year,
131 &ntm_time.tm_mon,
132 &ntm_time.tm_mday,
133 &ntm_time.tm_hour,
134 &ntm_time.tm_min) == 5) {
135 ntm_time.tm_year -= 1900; /* Adjust years */
136 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
137 *tm_time = ntm_time;
138 return(tm_time);
139
140 }
141
142 fprintf(stderr, "date: invalid date `%s'\n", t_string);
143
144 exit(1);
145
146}
147
148
149void
150date_err(void) {
151 fprintf(stderr, "date: only one date argument can be given at a time.\n");
152 exit(1);
153}
154
155int
156date_main(struct FileInfo * i, int argc, char * * argv)
157{
158 char *date_str = NULL;
159 char *date_fmt = NULL;
160 char *t_buff;
161 int set_time = 0;
162 int rfc822 = 0;
163 int utc = 0;
164 int use_arg = 0;
165 int n_args;
166 time_t tm;
167 struct tm tm_time;
168 char optc;
169
170 /* Interpret command line args */
171
172
173 while ((optc = getopt_long (argc, argv, "d:Rs:u", long_options, NULL))
174 != EOF) {
175 switch (optc) {
176 case 0:
177 break;
178
179 case 'R':
180 rfc822 = 1;
181 break;
182
183 case 's':
184 set_time = 1;
185 if(date_str != NULL) date_err();
186 date_str = optarg;
187 break;
188
189 case 'u':
190 utc = 1;
191 if (putenv ("TZ=UTC0") != 0) {
192 fprintf(stderr,"date: memory exhausted\n");
193 return(1);
194 }
195#if LOCALTIME_CACHE
196 tzset ();
197#endif break;
198
199 case 'd':
200 use_arg = 1;
201 if(date_str != NULL) date_err();
202 date_str = optarg;
203 break;
204
205 default:
206 usage(date_usage);
207 break;
208 }
209 }
210
211
212 n_args = argc - optind;
213
214 while (n_args--){
215 switch(argv[optind][0]) {
216 case '+':
217 /* Date format strings */
218 if(date_fmt != NULL) {
219 fprintf(stderr, "date: only one date format can be given.\n");
220 return(1);
221 }
222 date_fmt = &argv[optind][1];
223 break;
224
225 case '\0':
226 break;
227
228 default:
229 /* Anything left over must be a date string to set the time */
230 set_time = 1;
231 if(date_str != NULL) date_err();
232 date_str = argv[optind];
233 break;
234 }
235 optind++;
236 }
237
238
239 /* Now we have parsed all the information except the date format
240 which depends on whether the clock is being set or read */
241
242 time(&tm);
243 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
244 /* Zero out fields - take her back to midnight!*/
245 if(date_str != NULL) {
246 tm_time.tm_sec = 0;
247 tm_time.tm_min = 0;
248 tm_time.tm_hour = 0;
249 }
250
251 /* Process any date input to UNIX time since 1 Jan 1970 */
252 if(date_str != NULL) {
253
254 if(strchr(date_str, ':') != NULL) {
255 date_conv_ftime(&tm_time, date_str);
256 } else {
257 date_conv_time(&tm_time, date_str);
258 }
259
260 /* Correct any day of week and day of year etc fields */
261 tm = mktime(&tm_time);
262 if (tm < 0 ) {
263 fprintf(stderr, "date: invalid date `%s'\n", date_str);
264 exit(1);
265 }
266
267 /* if setting time, set it */
268 if(set_time) {
269 if( stime(&tm) < 0) {
270 fprintf(stderr, "date: can't set date.\n");
271 exit(1);
272 }
273 }
274 }
275
276 /* Display output */
277
278 /* Deal with format string */
279 if(date_fmt == NULL) {
280 date_fmt = (rfc822
281 ? (utc
282 ? "%a, %_d %b %Y %H:%M:%S GMT"
283 : "%a, %_d %b %Y %H:%M:%S %z")
284 : "%a %b %e %H:%M:%S %Z %Y");
285
286 } else if ( *date_fmt == '\0' ) {
287 /* Imitate what GNU 'date' does with NO format string! */
288 printf ("\n");
289 return(0);
290 }
291
292 /* Handle special conversions */
293
294 if( strncmp( date_fmt, "%f", 2) == 0 ) {
295 date_fmt = "%Y.%m.%d-%H:%M:%S";
296 }
297
298 /* Print OUTPUT (after ALL that!) */
299 t_buff = malloc(201);
300 strftime(t_buff, 200, date_fmt, &tm_time);
301 printf("%s\n", t_buff);
302
303 return(0);
304
305}
diff --git a/dd.c b/dd.c
new file mode 100644
index 000000000..8f1b9d409
--- /dev/null
+++ b/dd.c
@@ -0,0 +1,307 @@
1/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "dd" command, originally taken from sash.
7 *
8 * Permission to distribute this code under the GPL has been granted.
9 * Majorly modified, and bugs fixed for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
10 */
11
12#include "internal.h"
13#ifdef BB_DD
14
15const char dd_usage[] =
16"Copy a file, converting and formatting according to options\n\
17\n\
18usage: [if=name] [of=name] [bs=n] [count=n]\n\
19\tif=FILE\tread from FILE instead of stdin\n\
20\tof=FILE\twrite to FILE instead of stout\n\
21\tbs=n\tread and write N bytes at a time\n\
22\tcount=n\tcopy only n input blocks\n\
23\n\
24BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n";
25
26
27#include <stdio.h>
28#include <dirent.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <signal.h>
32#include <time.h>
33
34
35#define PAR_NONE 0
36#define PAR_IF 1
37#define PAR_OF 2
38#define PAR_BS 3
39#define PAR_COUNT 4
40
41
42typedef struct
43{
44 const char * name;
45 int value;
46} PARAM;
47
48
49static const PARAM params[] =
50{
51 {"if", PAR_IF},
52 {"of", PAR_OF},
53 {"bs", PAR_BS},
54 {"count", PAR_COUNT},
55 {NULL, PAR_NONE}
56};
57
58
59static long getNum(const char * cp);
60
61extern int
62dd_main (struct FileInfo *unused, int argc, char **argv)
63{
64 const char * str;
65 const PARAM * par;
66 const char * inFile;
67 const char * outFile;
68 char * cp;
69 int inFd;
70 int outFd;
71 int inCc=0;
72 int outCc;
73 int blockSize;
74 long count;
75 long intotal;
76 long outTotal;
77 unsigned char* buf;
78 unsigned char localBuf[BUF_SIZE];
79
80 inFile = NULL;
81 outFile = NULL;
82 blockSize = 512;
83 count = 1;
84
85
86 while (--argc > 0)
87 {
88 str = *++argv;
89 cp = strchr(str, '=');
90
91 if (cp == NULL)
92 {
93 fprintf(stderr, "Bad dd argument\n");
94 goto usage;
95 }
96
97 *cp++ = '\0';
98
99 for (par = params; par->name; par++)
100 {
101 if (strcmp(str, par->name) == 0)
102 break;
103 }
104
105 switch (par->value)
106 {
107 case PAR_IF:
108 if (inFile)
109 {
110 fprintf(stderr, "Multiple input files illegal\n");
111 goto usage;
112 }
113
114 //fprintf(stderr, "if=%s\n", cp);
115 inFile = cp;
116 break;
117
118 case PAR_OF:
119 if (outFile)
120 {
121 fprintf(stderr, "Multiple output files illegal\n");
122 goto usage;
123 }
124
125 //fprintf(stderr, "of=%s\n", cp);
126 outFile = cp;
127 break;
128
129 case PAR_BS:
130 blockSize = getNum(cp);
131 //fprintf(stderr, "bs=%d\n", blockSize);
132
133 if (blockSize <= 0)
134 {
135 fprintf(stderr, "Bad block size value\n");
136 goto usage;
137 }
138
139 break;
140
141 case PAR_COUNT:
142 count = getNum(cp);
143 //fprintf(stderr, "count=%ld\n", count);
144
145 if (count < 0)
146 {
147 fprintf(stderr, "Bad count value\n");
148 goto usage;
149 }
150
151 break;
152
153 default:
154 goto usage;
155 }
156 }
157
158 buf = localBuf;
159
160 if (blockSize > sizeof(localBuf))
161 {
162 buf = malloc(blockSize);
163
164 if (buf == NULL)
165 {
166 fprintf(stderr, "Cannot allocate buffer\n");
167 return 1;
168 }
169 }
170
171 intotal = 0;
172 outTotal = 0;
173
174 if (inFile == NULL)
175 inFd = STDIN;
176 else
177 inFd = open(inFile, 0);
178
179 if (inFd < 0)
180 {
181 perror(inFile);
182
183 if (buf != localBuf)
184 free(buf);
185
186 return 1;
187 }
188
189 if (outFile == NULL)
190 outFd = STDOUT;
191 else
192 outFd = creat(outFile, 0666);
193
194 if (outFd < 0)
195 {
196 perror(outFile);
197 close(inFd);
198
199 if (buf != localBuf)
200 free(buf);
201
202 return 1;
203 }
204
205 while ( outTotal < count*blockSize )
206 {
207 inCc = read(inFd, buf, blockSize);
208 if (inCc < 0) {
209 perror(inFile);
210 goto cleanup;
211 }
212 //fprintf(stderr, "read in =%d\n", inCc);
213 intotal += inCc;
214 cp = buf;
215
216
217 while ( intotal > outTotal )
218 {
219 if (outTotal+inCc > count*blockSize)
220 inCc=count*blockSize-outTotal;
221 outCc = write(outFd, cp, inCc);
222 if (outCc < 0)
223 {
224 perror(outFile);
225 goto cleanup;
226 }
227 //fprintf(stderr, "wrote out =%d\n", outCc);
228
229 inCc -= outCc;
230 cp += outCc;
231 outTotal += outCc;
232 //fprintf(stderr, "outTotal=%ld\n", outTotal);
233 }
234 }
235
236 if (inCc < 0)
237 perror(inFile);
238
239cleanup:
240 close(inFd);
241
242 if (close(outFd) < 0)
243 perror(outFile);
244
245 if (buf != localBuf)
246 free(buf);
247
248 printf("%ld+%d records in\n", intotal / blockSize,
249 (intotal % blockSize) != 0);
250
251 printf("%ld+%d records out\n", outTotal / blockSize,
252 (outTotal % blockSize) != 0);
253 return 0;
254usage:
255
256 fprintf(stderr, "%s", dd_usage);
257 return 1;
258}
259
260
261/*
262 * Read a number with a possible multiplier.
263 * Returns -1 if the number format is illegal.
264 */
265static long
266getNum(const char * cp)
267{
268 long value;
269
270 if (!isDecimal(*cp))
271 return -1;
272
273 value = 0;
274
275 while (isDecimal(*cp))
276 value = value * 10 + *cp++ - '0';
277
278 switch (*cp++)
279 {
280 case 'k':
281 value *= 1024;
282 break;
283
284 case 'b':
285 value *= 512;
286 break;
287
288 case 'w':
289 value *= 2;
290 break;
291
292 case '\0':
293 return value;
294
295 default:
296 return -1;
297 }
298
299 if (*cp)
300 return -1;
301
302 return value;
303}
304
305#endif
306/* END CODE */
307
diff --git a/descend.c b/descend.c
new file mode 100644
index 000000000..9ada7b4fc
--- /dev/null
+++ b/descend.c
@@ -0,0 +1,124 @@
1#include "internal.h"
2#include <stdio.h>
3#include <dirent.h>
4#include <string.h>
5#include <errno.h>
6
7
8static int
9noDots(const struct dirent * e)
10{
11 if ( e->d_name[0] == '.'
12 && (e->d_name[1] == '\0'
13 || (e->d_name[1] == '.' && e->d_name[2] == '\0')) )
14 return 0;
15 else
16 return 1;
17}
18
19extern int
20descend(
21 struct FileInfo *oldInfo
22,int (*function)(const struct FileInfo * i))
23{
24 char pathname[1024];
25 struct dirent * * names;
26 struct dirent * * n;
27 int length;
28 char * filename;
29 int status = 0;
30 int count;
31
32 if ( *oldInfo->source == '\0' ) {
33 errno = EINVAL;
34 return -1;
35 }
36
37 if ( oldInfo->stat.st_dev == 0
38 && oldInfo->stat.st_ino == 0
39 && oldInfo->stat.st_mode == 0 ) {
40 if ( lstat(oldInfo->source, &oldInfo->stat) != 0 )
41 return -1;
42 oldInfo->isSymbolicLink = ((oldInfo->stat.st_mode & S_IFMT) == S_IFLNK);
43
44 if ( oldInfo->isSymbolicLink )
45 if ( stat(oldInfo->source, &oldInfo->stat) != 0 )
46 memset((void *)&oldInfo->stat, 0, sizeof(oldInfo->stat));
47 }
48
49 if ( !oldInfo->processDirectoriesAfterTheirContents ) {
50 if ( function )
51 status = (*function)(oldInfo);
52 if ( status == 0 )
53 status = post_process(oldInfo);
54 }
55
56 if ( (count = scandir(oldInfo->source, &names, noDots, alphasort)) < 0 )
57 return -1;
58
59 length = strlen(oldInfo->source);
60 if ( oldInfo->source[length-1] == '/' )
61 length--;
62
63 memcpy(pathname, oldInfo->source, length+1);
64 pathname[length] = '/';
65 filename = &pathname[length+1];
66
67 n = names;
68 while ( count-- > 0 ) {
69 struct FileInfo i = *oldInfo;
70
71 strcpy(filename, (*n)->d_name);
72 free(*n++);
73
74 if ( lstat(pathname, &i.stat) != 0 && errno != ENOENT ) {
75 fprintf(stderr, "Can't stat %s: %s\n", pathname, strerror(errno));
76 return -1;
77 }
78 i.isSymbolicLink = ((i.stat.st_mode & S_IFMT) == S_IFLNK);
79
80 if ( i.isSymbolicLink )
81 if ( stat(pathname, &i.stat) != 0 )
82 memset((void *)&i.stat, 0, sizeof(i.stat));
83
84 i.source = pathname;
85
86 if ( i.dyadic ) {
87 char d[1024];
88
89 i.destination = join_paths(d, i.destination, &i.source[i.directoryLength]);
90 }
91 else
92 i.destination = i.source;
93
94 if ( !i.isSymbolicLink && (i.stat.st_mode & S_IFMT) == S_IFDIR )
95 status = descend(&i, function);
96 else {
97 if ( function )
98 status = (*function)(&i);
99 if ( status == 0 )
100 status = post_process(&i);
101 }
102
103 if ( !i.processDirectoriesAfterTheirContents
104 && status == 0
105 && (i.stat.st_mode & S_IFMT) == S_IFDIR )
106 descend(&i, function);
107
108 if ( status != 0 && !i.force ) {
109 while ( count-- > 0 )
110 free(*n++);
111 break;
112 }
113 }
114 free(names);
115
116 if ( oldInfo->processDirectoriesAfterTheirContents ) {
117 if ( function )
118 status = (*function)(oldInfo);
119 if ( status == 0 )
120 status = post_process(oldInfo);
121 }
122
123 return status;
124}
diff --git a/df.c b/df.c
new file mode 100644
index 000000000..a0692afc5
--- /dev/null
+++ b/df.c
@@ -0,0 +1,103 @@
1#include "internal.h"
2#include <stdio.h>
3#include <mntent.h>
4#include <sys/stat.h>
5#include <sys/vfs.h>
6
7const char df_usage[] = "df [filesystem ...]\n"
8"\n"
9"\tPrint the filesystem space used and space available.\n";
10
11
12static int
13df(const char * device, const char * mountPoint)
14{
15 struct statfs s;
16 long blocks_used;
17 long blocks_percent_used;
18
19 if ( statfs(mountPoint, &s) != 0 ) {
20 name_and_error(mountPoint);
21 return 1;
22 }
23
24 if ( s.f_blocks > 0 ) {
25 blocks_used = s.f_blocks - s.f_bfree;
26 blocks_percent_used = (long)
27 (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5);
28
29/*
30 printf(
31 "%-20s %7ld %7ld %7ld %5ld%% %s\n"
32 ,device
33 ,s.f_blocks
34 ,s.f_blocks - s.f_bfree
35 ,s.f_bavail
36 ,blocks_percent_used
37 ,mountPoint);
38*/
39
40 printf(
41 "%-20s %7.0f %7.0f %7.0f %5ld%% %s\n"
42 ,device
43 ,s.f_blocks * (s.f_bsize / 1024.0)
44 ,(s.f_blocks - s.f_bfree) * (s.f_bsize / 1024.0)
45 ,s.f_bavail * (s.f_bsize / 1024.0)
46 ,blocks_percent_used
47 ,mountPoint);
48
49 }
50
51 return 0;
52}
53
54extern int
55df_main(struct FileInfo * i, int argc, char * * argv)
56{
57 static const char header[] =
58 "Filesystem 1024-blocks Used Available Capacity Mounted on\n";
59 printf(header);
60
61 if ( argc > 1 ) {
62 struct mntent * mountEntry;
63 int status;
64
65 while ( argc > 1 ) {
66 if ( (mountEntry = findMountPoint(argv[1], "/etc/mtab")) == 0
67 && (mountEntry = findMountPoint(argv[1], "/proc/mounts")) == 0 )
68 {
69 fprintf(stderr, "%s: can't find mount point.\n"
70 ,argv[1]);
71 return 1;
72 }
73 status = df(mountEntry->mnt_fsname, mountEntry->mnt_dir);
74 if ( status != 0 )
75 return status;
76 argc--;
77 argv++;
78 }
79 return 0;
80 }
81 else {
82 FILE * mountTable;
83 struct mntent * mountEntry;
84
85 if ( (mountTable = setmntent("/etc/mtab", "r")) == 0
86 && (mountTable = setmntent("/proc/mounts", "r")) == 0
87 ) {
88 name_and_error("/etc/mtab");
89 return 1;
90 }
91
92 while ( (mountEntry = getmntent(mountTable)) != 0 ) {
93 int status = df(
94 mountEntry->mnt_fsname
95 ,mountEntry->mnt_dir);
96 if ( status != 0 )
97 return status;
98 }
99 endmntent(mountTable);
100 }
101
102 return 0;
103}
diff --git a/dmesg.c b/dmesg.c
new file mode 100644
index 000000000..a63fa3d39
--- /dev/null
+++ b/dmesg.c
@@ -0,0 +1,95 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <unistd.h>
4#include <time.h>
5
6/* dmesg.c -- Print out the contents of the kernel ring buffer
7 * Created: Sat Oct 9 16:19:47 1993
8 * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
9 * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
10 * This program comes with ABSOLUTELY NO WARRANTY.
11 * Modifications by Rick Sladkey (jrs@world.std.com)
12 * from util-linux; adapted for busybox
13 */
14
15#include <linux/unistd.h>
16#include <stdio.h>
17#include <getopt.h>
18
19#define __NR_klog __NR_syslog
20
21#if defined(__GLIBC__)
22#include <sys/klog.h>
23#define klog klogctl
24#else
25static inline _syscall3(int,klog,int,type,char *,b,int,len)
26#endif /* __GLIBC__ */
27
28const char dmesg_usage[] = "dmesg";
29
30int
31dmesg_main(struct FileInfo * info, int argc, char * * argv)
32{
33
34 char buf[4096];
35 int i;
36 int n;
37 int c;
38 int level = 0;
39 int lastc;
40 int cmd = 3;
41
42 while ((c = getopt( argc, argv, "cn:" )) != EOF) {
43 switch (c) {
44 case 'c':
45 cmd = 4;
46 break;
47 case 'n':
48 cmd = 8;
49 level = atoi(optarg);
50 break;
51 case '?':
52 default:
53 usage(dmesg_usage);
54 exit(1);
55 }
56 }
57 argc -= optind;
58 argv += optind;
59
60 if (argc > 1) {
61 usage(dmesg_usage);
62 exit(1);
63 }
64
65 if (cmd == 8) {
66 n = klog( cmd, NULL, level );
67 if (n < 0) {
68 perror( "klog" );
69 exit( 1 );
70 }
71 exit( 0 );
72 }
73
74 n = klog( cmd, buf, sizeof( buf ) );
75 if (n < 0) {
76 perror( "klog" );
77 exit( 1 );
78 }
79
80 lastc = '\n';
81 for (i = 0; i < n; i++) {
82 if ((i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
83 i++;
84 while (buf[i] >= '0' && buf[i] <= '9')
85 i++;
86 if (buf[i] == '>')
87 i++;
88 }
89 lastc = buf[i];
90 putchar( lastc );
91 }
92 if (lastc != '\n')
93 putchar( '\n' );
94 return 0;
95}
diff --git a/dutmp.c b/dutmp.c
new file mode 100644
index 000000000..e92b6700f
--- /dev/null
+++ b/dutmp.c
@@ -0,0 +1,47 @@
1/*
2 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
3 *
4 * dutmp
5 * Takes utmp formated file on stdin and dumps it's contents
6 * out in colon delimited fields. Easy to 'cut' for shell based
7 * versions of 'who', 'last', etc. IP Addr is output in hex,
8 * little endian on x86.
9 *
10 * made against libc6
11 */
12
13#include "internal.h"
14#include <stdio.h>
15#include <utmp.h>
16
17const char dutmp_usage[] = "dutmp\n"
18"\n"
19"\tDump file or stdin utmp file format to stdout, pipe delimited.\n"
20"\tdutmp /var/run/utmp\n";
21
22extern int
23dutmp_fn(const struct FileInfo * i)
24{
25
26FILE * f = stdin;
27struct utmp * ut = (struct utmp *) malloc(sizeof(struct utmp) );
28
29 if ( i )
30 if (! (f = fopen(i->source, "r"))) {
31 name_and_error(i->source);
32 return 1;
33 }
34
35 while (fread (ut, 1, sizeof(struct utmp), f)) {
36 //printf("%d:%d:%s:%s:%s:%s:%d:%d:%ld:%ld:%ld:%x\n",
37 printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n",
38 ut->ut_type, ut->ut_pid, ut->ut_line,
39 ut->ut_id, ut->ut_user, ut->ut_host,
40 ut->ut_exit.e_termination, ut->ut_exit.e_exit,
41 ut->ut_session,
42 ut->ut_tv.tv_sec, ut->ut_tv.tv_usec,
43 ut->ut_addr);
44 }
45
46return 0;
47}
diff --git a/dyadic.c b/dyadic.c
new file mode 100644
index 000000000..8136bb573
--- /dev/null
+++ b/dyadic.c
@@ -0,0 +1,28 @@
1#include "internal.h"
2#include <stdio.h>
3
4extern int
5dyadic_main(
6 struct FileInfo * i
7,int argc
8,char * * argv)
9{
10 int flags;
11
12 i->dyadic = 1;
13 i->destination = argv[argc - 1];
14
15 for ( flags = 0; flags < (argc - 1) && argv[flags + 1][0] == '-' ; flags++ )
16 ;
17 if ( argc - flags < 3 ) {
18 usage(i->applet->usage);
19 return 1;
20 }
21 else if ( argc - flags > 3 ) {
22 if ( !is_a_directory(i->destination) ) {
23 fprintf(stderr, "%s: not a directory.\n", i->destination);
24 return 1;
25 }
26 }
27 return monadic_main(i, argc - 1, argv);
28}
diff --git a/examples/busybox.spec b/examples/busybox.spec
new file mode 100644
index 000000000..46bd7f484
--- /dev/null
+++ b/examples/busybox.spec
@@ -0,0 +1,43 @@
1Name: busybox
2Version: 0.29alpha
3Release: 1
4Group: System/Utilities
5Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
6Copyright: GPL
7Packager : Erik Andersen <andersen@lineo.com>
8Conflicts: fileutils grep shellutils
9Buildroot: /tmp/%{Name}-%{Version}
10Source: busybox-0.29a1.tar.gz
11
12%Description
13BusyBox is a suite of "tiny" Unix utilities in a multi-call binary. It
14provides a pretty complete environment that fits on a floppy or in a
15ROM. Just add "ash" (Keith Almquists tiny Bourne shell clone) and "ae",
16and a kernel and you have a full system. This is used on the Debian
17install disk and in an internet router, and it makes a good environment
18for a "rescue" disk or any small or embedded system.
19
20%Prep
21%setup -q -n busybox
22
23%Build
24make
25
26%Install
27rm -rf $RPM_BUILD_ROOT
28mkdir -p $RPM_BUILD_ROOT/bin
29h=`cat busybox.links`
30
31for i in $h ; do
32 mkdir -p $RPM_BUILD_ROOT/`echo $i | sed -e 's/\(^.*\/\)\(.*\)/\1/g' `
33 (cd $RPM_BUILD_ROOT/bin ; ln -s ln `echo $i | sed -e 's/\(^.*\/\)\(.*\)/\2/g' ` );
34done
35rm -f $RPM_BUILD_ROOT/bin/ln
36install -m 755 busybox $RPM_BUILD_ROOT/bin/ln
37
38%Clean
39rm -rf $RPM_BUILD_ROOT
40
41%Files
42%defattr(-,root,root)
43/
diff --git a/fdflush.c b/fdflush.c
new file mode 100644
index 000000000..a15e9b3f7
--- /dev/null
+++ b/fdflush.c
@@ -0,0 +1,36 @@
1#include "internal.h"
2#include <sys/ioctl.h>
3#include <linux/fd.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7
8const char fdflush_usage[] = "fdflush device";
9
10int
11fdflush(const char *filename)
12{
13 int status;
14 int fd = open(filename, 0);
15
16 if ( fd < 0 ) {
17 name_and_error(filename);
18 return 1;
19 }
20
21 status = ioctl(fd, FDFLUSH, 0);
22 close(fd);
23
24 if ( status != 0 ) {
25 name_and_error(filename);
26 return 1;
27 }
28 return 0;
29}
30
31
32int
33fdflush_fn(const struct FileInfo * i)
34{
35 return fdflush(i->source);
36}
diff --git a/find.c b/find.c
new file mode 100644
index 000000000..b3ac1ff5a
--- /dev/null
+++ b/find.c
@@ -0,0 +1,23 @@
1#include "internal.h"
2#include <errno.h>
3#include <stdio.h>
4
5const char find_usage[] = "find dir [pattern]\n"
6"\n"
7"\tFind files.\n";
8
9extern int
10find_main(struct FileInfo * i, int argc, char * * argv)
11{
12 i->recursive=1;
13 i->processDirectoriesAfterTheirContents=1;
14 return monadic_main(i, argc, argv);
15}
16
17extern int
18find_fn(const struct FileInfo * i)
19{
20 printf("%s\n",i->source);
21
22 return(0);
23}
diff --git a/findmount.c b/findmount.c
new file mode 100644
index 000000000..26e28fcd3
--- /dev/null
+++ b/findmount.c
@@ -0,0 +1,46 @@
1#include "internal.h"
2#include <stdio.h>
3#include <mntent.h>
4#include <sys/stat.h>
5
6/*
7 * Given a block device, find the mount table entry if that block device
8 * is mounted.
9 *
10 * Given any other file (or directory), find the mount table entry for its
11 * filesystem.
12 */
13extern struct mntent *
14findMountPoint(const char * name, const char * table)
15{
16 struct stat s;
17 dev_t mountDevice;
18 FILE * mountTable;
19 struct mntent * mountEntry;
20
21 if ( stat(name, &s) != 0 )
22 return 0;
23
24 if ( (s.st_mode & S_IFMT) == S_IFBLK )
25 mountDevice = s.st_rdev;
26 else
27 mountDevice = s.st_dev;
28
29
30 if ( (mountTable = setmntent(table, "r")) == 0 )
31 return 0;
32
33 while ( (mountEntry = getmntent(mountTable)) != 0 ) {
34 if ( strcmp(name, mountEntry->mnt_dir) == 0
35 || strcmp(name, mountEntry->mnt_fsname) == 0 ) /* String match. */
36 break;
37 if ( stat(mountEntry->mnt_fsname, &s) == 0
38 && s.st_rdev == mountDevice ) /* Match the device. */
39 break;
40 if ( stat(mountEntry->mnt_dir, &s) == 0
41 && s.st_dev == mountDevice ) /* Match the directory's mount point. */
42 break;
43 }
44 endmntent(mountTable);
45 return mountEntry;
46}
diff --git a/findutils/find.c b/findutils/find.c
new file mode 100644
index 000000000..b3ac1ff5a
--- /dev/null
+++ b/findutils/find.c
@@ -0,0 +1,23 @@
1#include "internal.h"
2#include <errno.h>
3#include <stdio.h>
4
5const char find_usage[] = "find dir [pattern]\n"
6"\n"
7"\tFind files.\n";
8
9extern int
10find_main(struct FileInfo * i, int argc, char * * argv)
11{
12 i->recursive=1;
13 i->processDirectoriesAfterTheirContents=1;
14 return monadic_main(i, argc, argv);
15}
16
17extern int
18find_fn(const struct FileInfo * i)
19{
20 printf("%s\n",i->source);
21
22 return(0);
23}
diff --git a/findutils/grep.c b/findutils/grep.c
new file mode 100644
index 000000000..3779e5510
--- /dev/null
+++ b/findutils/grep.c
@@ -0,0 +1,210 @@
1/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "grep" command, taken from sash.
7 * This provides basic file searching.
8 *
9 * Permission to distribute this code under the GPL has been granted.
10 * Modified for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
11 */
12
13#include "internal.h"
14#ifdef BB_GREP
15
16#include <stdio.h>
17#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <signal.h>
21#include <time.h>
22#include <ctype.h>
23
24
25const char grep_usage[] =
26"Search the input file(s) for lines matching the given pattern.\n"
27"\tI search stdin if no files are given.\n"
28"\tI can't grok full regular expressions.\n"
29"usage: grep [in] PATTERN [FILES]...\n"
30"\ti=ignore case, n=list line numbers\n";
31
32
33
34static BOOL search
35 (const char * string, const char * word, BOOL ignoreCase);
36
37
38extern int
39grep_main(struct FileInfo * unused, int argc, char ** argv)
40{
41 FILE * fp;
42 const char * word;
43 const char * name;
44 const char * cp;
45 BOOL tellName;
46 BOOL ignoreCase;
47 BOOL tellLine;
48 long line;
49 char buf[BUF_SIZE];
50
51 ignoreCase = FALSE;
52 tellLine = FALSE;
53
54 argc--;
55 argv++;
56 if (argc < 1)
57 {
58 fprintf(stderr, "%s", grep_usage);
59 return 1;
60 }
61
62 if (**argv == '-')
63 {
64 argc--;
65 cp = *argv++;
66
67 while (*++cp) switch (*cp)
68 {
69 case 'i':
70 ignoreCase = TRUE;
71 break;
72
73 case 'n':
74 tellLine = TRUE;
75 break;
76
77 default:
78 fprintf(stderr, "Unknown option\n");
79 return 1;
80 }
81 }
82
83 word = *argv++;
84 argc--;
85
86 tellName = (argc > 1);
87
88 while (argc-- > 0)
89 {
90 name = *argv++;
91
92 fp = fopen(name, "r");
93
94 if (fp == NULL)
95 {
96 perror(name);
97
98 continue;
99 }
100
101 line = 0;
102
103 while (fgets(buf, sizeof(buf), fp))
104 {
105 line++;
106
107 cp = &buf[strlen(buf) - 1];
108
109 if (*cp != '\n')
110 fprintf(stderr, "%s: Line too long\n", name);
111
112 if (search(buf, word, ignoreCase))
113 {
114 if (tellName)
115 printf("%s: ", name);
116
117 if (tellLine)
118 printf("%ld: ", line);
119
120 fputs(buf, stdout);
121 }
122 }
123
124 if (ferror(fp))
125 perror(name);
126
127 fclose(fp);
128 }
129 return 0;
130}
131
132
133/*
134 * See if the specified word is found in the specified string.
135 */
136static BOOL
137search(const char * string, const char * word, BOOL ignoreCase)
138{
139 const char * cp1;
140 const char * cp2;
141 int len;
142 int lowFirst;
143 int ch1;
144 int ch2;
145
146 len = strlen(word);
147
148 if (!ignoreCase)
149 {
150 while (TRUE)
151 {
152 string = strchr(string, word[0]);
153
154 if (string == NULL)
155 return FALSE;
156
157 if (memcmp(string, word, len) == 0)
158 return TRUE;
159
160 string++;
161 }
162 }
163
164 /*
165 * Here if we need to check case independence.
166 * Do the search by lower casing both strings.
167 */
168 lowFirst = *word;
169
170 if (isupper(lowFirst))
171 lowFirst = tolower(lowFirst);
172
173 while (TRUE)
174 {
175 while (*string && (*string != lowFirst) &&
176 (!isupper(*string) || (tolower(*string) != lowFirst)))
177 {
178 string++;
179 }
180
181 if (*string == '\0')
182 return FALSE;
183
184 cp1 = string;
185 cp2 = word;
186
187 do
188 {
189 if (*cp2 == '\0')
190 return TRUE;
191
192 ch1 = *cp1++;
193
194 if (isupper(ch1))
195 ch1 = tolower(ch1);
196
197 ch2 = *cp2++;
198
199 if (isupper(ch2))
200 ch2 = tolower(ch2);
201
202 }
203 while (ch1 == ch2);
204
205 string++;
206 }
207}
208
209#endif
210/* END CODE */
diff --git a/grep.c b/grep.c
new file mode 100644
index 000000000..3779e5510
--- /dev/null
+++ b/grep.c
@@ -0,0 +1,210 @@
1/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "grep" command, taken from sash.
7 * This provides basic file searching.
8 *
9 * Permission to distribute this code under the GPL has been granted.
10 * Modified for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
11 */
12
13#include "internal.h"
14#ifdef BB_GREP
15
16#include <stdio.h>
17#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <signal.h>
21#include <time.h>
22#include <ctype.h>
23
24
25const char grep_usage[] =
26"Search the input file(s) for lines matching the given pattern.\n"
27"\tI search stdin if no files are given.\n"
28"\tI can't grok full regular expressions.\n"
29"usage: grep [in] PATTERN [FILES]...\n"
30"\ti=ignore case, n=list line numbers\n";
31
32
33
34static BOOL search
35 (const char * string, const char * word, BOOL ignoreCase);
36
37
38extern int
39grep_main(struct FileInfo * unused, int argc, char ** argv)
40{
41 FILE * fp;
42 const char * word;
43 const char * name;
44 const char * cp;
45 BOOL tellName;
46 BOOL ignoreCase;
47 BOOL tellLine;
48 long line;
49 char buf[BUF_SIZE];
50
51 ignoreCase = FALSE;
52 tellLine = FALSE;
53
54 argc--;
55 argv++;
56 if (argc < 1)
57 {
58 fprintf(stderr, "%s", grep_usage);
59 return 1;
60 }
61
62 if (**argv == '-')
63 {
64 argc--;
65 cp = *argv++;
66
67 while (*++cp) switch (*cp)
68 {
69 case 'i':
70 ignoreCase = TRUE;
71 break;
72
73 case 'n':
74 tellLine = TRUE;
75 break;
76
77 default:
78 fprintf(stderr, "Unknown option\n");
79 return 1;
80 }
81 }
82
83 word = *argv++;
84 argc--;
85
86 tellName = (argc > 1);
87
88 while (argc-- > 0)
89 {
90 name = *argv++;
91
92 fp = fopen(name, "r");
93
94 if (fp == NULL)
95 {
96 perror(name);
97
98 continue;
99 }
100
101 line = 0;
102
103 while (fgets(buf, sizeof(buf), fp))
104 {
105 line++;
106
107 cp = &buf[strlen(buf) - 1];
108
109 if (*cp != '\n')
110 fprintf(stderr, "%s: Line too long\n", name);
111
112 if (search(buf, word, ignoreCase))
113 {
114 if (tellName)
115 printf("%s: ", name);
116
117 if (tellLine)
118 printf("%ld: ", line);
119
120 fputs(buf, stdout);
121 }
122 }
123
124 if (ferror(fp))
125 perror(name);
126
127 fclose(fp);
128 }
129 return 0;
130}
131
132
133/*
134 * See if the specified word is found in the specified string.
135 */
136static BOOL
137search(const char * string, const char * word, BOOL ignoreCase)
138{
139 const char * cp1;
140 const char * cp2;
141 int len;
142 int lowFirst;
143 int ch1;
144 int ch2;
145
146 len = strlen(word);
147
148 if (!ignoreCase)
149 {
150 while (TRUE)
151 {
152 string = strchr(string, word[0]);
153
154 if (string == NULL)
155 return FALSE;
156
157 if (memcmp(string, word, len) == 0)
158 return TRUE;
159
160 string++;
161 }
162 }
163
164 /*
165 * Here if we need to check case independence.
166 * Do the search by lower casing both strings.
167 */
168 lowFirst = *word;
169
170 if (isupper(lowFirst))
171 lowFirst = tolower(lowFirst);
172
173 while (TRUE)
174 {
175 while (*string && (*string != lowFirst) &&
176 (!isupper(*string) || (tolower(*string) != lowFirst)))
177 {
178 string++;
179 }
180
181 if (*string == '\0')
182 return FALSE;
183
184 cp1 = string;
185 cp2 = word;
186
187 do
188 {
189 if (*cp2 == '\0')
190 return TRUE;
191
192 ch1 = *cp1++;
193
194 if (isupper(ch1))
195 ch1 = tolower(ch1);
196
197 ch2 = *cp2++;
198
199 if (isupper(ch2))
200 ch2 = tolower(ch2);
201
202 }
203 while (ch1 == ch2);
204
205 string++;
206 }
207}
208
209#endif
210/* END CODE */
diff --git a/gzip.c b/gzip.c
new file mode 100644
index 000000000..6fd2e3971
--- /dev/null
+++ b/gzip.c
@@ -0,0 +1,3231 @@
1/* gzip.c -- this is a stripped down version of gzip I put into busybox, it does
2 * only standard in to standard out with -9 compression. It also requires the
3 * zcat module for some important functions.
4 *
5 * Charles P. Wright <cpw@unix.asb.com>
6 */
7#include "internal.h"
8#ifdef BB_GZIP
9
10#ifndef BB_ZCAT
11error: you need zcat to have gzip support!
12#endif
13
14const char gzip_usage[] = "gzip\nignores all command line arguments\ncompress stdin to stdout with -9 compression\n";
15
16/* gzip.h -- common declarations for all gzip modules
17 * Copyright (C) 1992-1993 Jean-loup Gailly.
18 * This is free software; you can redistribute it and/or modify it under the
19 * terms of the GNU General Public License, see the file COPYING.
20 */
21
22#if defined(__STDC__) || defined(PROTO)
23# define OF(args) args
24#else
25# define OF(args) ()
26#endif
27
28#ifdef __STDC__
29 typedef void *voidp;
30#else
31 typedef char *voidp;
32#endif
33
34/* I don't like nested includes, but the string and io functions are used
35 * too often
36 */
37#include <stdio.h>
38#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
39# include <string.h>
40# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
41# include <memory.h>
42# endif
43# define memzero(s, n) memset ((voidp)(s), 0, (n))
44#else
45# include <strings.h>
46# define strchr index
47# define strrchr rindex
48# define memcpy(d, s, n) bcopy((s), (d), (n))
49# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
50# define memzero(s, n) bzero((s), (n))
51#endif
52
53#ifndef RETSIGTYPE
54# define RETSIGTYPE void
55#endif
56
57#define local static
58
59typedef unsigned char uch;
60typedef unsigned short ush;
61typedef unsigned long ulg;
62
63/* Return codes from gzip */
64#define OK 0
65#define ERROR 1
66#define WARNING 2
67
68/* Compression methods (see algorithm.doc) */
69#define STORED 0
70#define COMPRESSED 1
71#define PACKED 2
72#define LZHED 3
73/* methods 4 to 7 reserved */
74#define DEFLATED 8
75#define MAX_METHODS 9
76extern int method; /* compression method */
77
78/* To save memory for 16 bit systems, some arrays are overlaid between
79 * the various modules:
80 * deflate: prev+head window d_buf l_buf outbuf
81 * unlzw: tab_prefix tab_suffix stack inbuf outbuf
82 * inflate: window inbuf
83 * unpack: window inbuf prefix_len
84 * unlzh: left+right window c_table inbuf c_len
85 * For compression, input is done in window[]. For decompression, output
86 * is done in window except for unlzw.
87 */
88
89#ifndef INBUFSIZ
90# ifdef SMALL_MEM
91# define INBUFSIZ 0x2000 /* input buffer size */
92# else
93# define INBUFSIZ 0x8000 /* input buffer size */
94# endif
95#endif
96#define INBUF_EXTRA 64 /* required by unlzw() */
97
98#ifndef OUTBUFSIZ
99# ifdef SMALL_MEM
100# define OUTBUFSIZ 8192 /* output buffer size */
101# else
102# define OUTBUFSIZ 16384 /* output buffer size */
103# endif
104#endif
105#define OUTBUF_EXTRA 2048 /* required by unlzw() */
106
107#ifndef DIST_BUFSIZE
108# ifdef SMALL_MEM
109# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
110# else
111# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
112# endif
113#endif
114
115#ifdef DYN_ALLOC
116# define EXTERN(type, array) extern type * near array
117# define DECLARE(type, array, size) type * near array
118# define ALLOC(type, array, size) { \
119 array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
120 if (array == NULL) error("insufficient memory"); \
121 }
122# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
123#else
124# define EXTERN(type, array) extern type array[]
125# define DECLARE(type, array, size) type array[size]
126# define ALLOC(type, array, size)
127# define FREE(array)
128#endif
129
130EXTERN(uch, inbuf); /* input buffer */
131EXTERN(uch, outbuf); /* output buffer */
132EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
133EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
134#define tab_suffix window
135#ifndef MAXSEG_64K
136# define tab_prefix prev /* hash link (see deflate.c) */
137# define head (prev+WSIZE) /* hash head (see deflate.c) */
138 EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
139#else
140# define tab_prefix0 prev
141# define head tab_prefix1
142 EXTERN(ush, tab_prefix0); /* prefix for even codes */
143 EXTERN(ush, tab_prefix1); /* prefix for odd codes */
144#endif
145
146extern unsigned insize; /* valid bytes in inbuf */
147extern unsigned inptr; /* index of next byte to be processed in inbuf */
148extern unsigned outcnt; /* bytes in output buffer */
149
150extern long bytes_in; /* number of input bytes */
151extern long bytes_out; /* number of output bytes */
152extern long header_bytes;/* number of bytes in gzip header */
153
154#define isize bytes_in
155/* for compatibility with old zip sources (to be cleaned) */
156
157extern int ifd; /* input file descriptor */
158extern int ofd; /* output file descriptor */
159extern char ifname[]; /* input file name or "stdin" */
160extern char ofname[]; /* output file name or "stdout" */
161extern char *progname; /* program name */
162
163extern long time_stamp; /* original time stamp (modification time) */
164extern long ifile_size; /* input file size, -1 for devices (debug only) */
165
166typedef int file_t; /* Do not use stdio */
167#define NO_FILE (-1) /* in memory compression */
168
169
170#define PACK_MAGIC "\037\036" /* Magic header for packed files */
171#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
172#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
173#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/
174#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
175
176/* gzip flag byte */
177#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
178#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
179#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
180#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
181#define COMMENT 0x10 /* bit 4 set: file comment present */
182#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
183#define RESERVED 0xC0 /* bit 6,7: reserved */
184
185/* internal file attribute */
186#define UNKNOWN 0xffff
187#define BINARY 0
188#define ASCII 1
189
190#ifndef WSIZE
191# define WSIZE 0x8000 /* window size--must be a power of two, and */
192#endif /* at least 32K for zip's deflate method */
193
194#define MIN_MATCH 3
195#define MAX_MATCH 258
196/* The minimum and maximum match lengths */
197
198#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
199/* Minimum amount of lookahead, except at the end of the input file.
200 * See deflate.c for comments about the MIN_MATCH+1.
201 */
202
203#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
204/* In order to simplify the code, particularly on 16 bit machines, match
205 * distances are limited to MAX_DIST instead of WSIZE.
206 */
207
208extern int decrypt; /* flag to turn on decryption */
209extern int exit_code; /* program exit code */
210extern int verbose; /* be verbose (-v) */
211extern int quiet; /* be quiet (-q) */
212extern int test; /* check .z file integrity */
213extern int to_stdout; /* output to stdout (-c) */
214extern int save_orig_name; /* set if original name must be saved */
215
216#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
217#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
218
219/* put_byte is used for the compressed output, put_ubyte for the
220 * uncompressed output. However unlzw() uses window for its
221 * suffix table instead of its output buffer, so it does not use put_ubyte
222 * (to be cleaned up).
223 */
224#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
225 flush_outbuf();}
226#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
227 flush_window();}
228
229/* Output a 16 bit value, lsb first */
230#define put_short(w) \
231{ if (outcnt < OUTBUFSIZ-2) { \
232 outbuf[outcnt++] = (uch) ((w) & 0xff); \
233 outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
234 } else { \
235 put_byte((uch)((w) & 0xff)); \
236 put_byte((uch)((ush)(w) >> 8)); \
237 } \
238}
239
240/* Output a 32 bit value to the bit stream, lsb first */
241#define put_long(n) { \
242 put_short((n) & 0xffff); \
243 put_short(((ulg)(n)) >> 16); \
244}
245
246#define seekable() 0 /* force sequential output */
247#define translate_eol 0 /* no option -a yet */
248
249#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
250
251/* Macros for getting two-byte and four-byte header values */
252#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
253#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
254
255/* Diagnostic functions */
256#ifdef DEBUG
257# define Assert(cond,msg) {if(!(cond)) error(msg);}
258# define Trace(x) fprintf x
259# define Tracev(x) {if (verbose) fprintf x ;}
260# define Tracevv(x) {if (verbose>1) fprintf x ;}
261# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
262# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
263#else
264# define Assert(cond,msg)
265# define Trace(x)
266# define Tracev(x)
267# define Tracevv(x)
268# define Tracec(c,x)
269# define Tracecv(c,x)
270#endif
271
272#define WARN(msg) {if (!quiet) fprintf msg ; \
273 if (exit_code == OK) exit_code = WARNING;}
274
275local void do_exit(int exitcode);
276
277 /* in zip.c: */
278extern int zip OF((int in, int out));
279extern int file_read OF((char *buf, unsigned size));
280
281 /* in unzip.c */
282extern int unzip OF((int in, int out));
283extern int check_zipfile OF((int in));
284
285 /* in unpack.c */
286extern int unpack OF((int in, int out));
287
288 /* in unlzh.c */
289extern int unlzh OF((int in, int out));
290
291 /* in gzip.c */
292RETSIGTYPE abort_gzip OF((void));
293
294 /* in deflate.c */
295void lm_init OF((ush *flags));
296ulg deflate OF((void));
297
298 /* in trees.c */
299void ct_init OF((ush *attr, int *method));
300int ct_tally OF((int dist, int lc));
301ulg flush_block OF((char *buf, ulg stored_len, int eof));
302
303 /* in bits.c */
304void bi_init OF((file_t zipfile));
305void send_bits OF((int value, int length));
306unsigned bi_reverse OF((unsigned value, int length));
307void bi_windup OF((void));
308void copy_block OF((char *buf, unsigned len, int header));
309extern int (*read_buf) OF((char *buf, unsigned size));
310
311 /* in util.c: */
312extern int copy OF((int in, int out));
313extern ulg updcrc OF((uch *s, unsigned n));
314extern void clear_bufs OF((void));
315extern int fill_inbuf OF((int eof_ok));
316extern void flush_outbuf OF((void));
317extern void flush_window OF((void));
318extern void write_buf OF((int fd, voidp buf, unsigned cnt));
319extern char *strlwr OF((char *s));
320extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
321extern void error OF((char *m));
322extern void warn OF((char *a, char *b));
323extern void read_error OF((void));
324extern void write_error OF((void));
325extern void display_ratio OF((long num, long den, FILE *file));
326extern voidp xmalloc OF((unsigned int size));
327
328 /* in inflate.c */
329extern int inflate OF((void));
330/* lzw.h -- define the lzw functions.
331 * Copyright (C) 1992-1993 Jean-loup Gailly.
332 * This is free software; you can redistribute it and/or modify it under the
333 * terms of the GNU General Public License, see the file COPYING.
334 */
335
336#if !defined(OF) && defined(lint)
337# include "gzip.h"
338#endif
339
340#ifndef BITS
341# define BITS 16
342#endif
343#define INIT_BITS 9 /* Initial number of bits per code */
344
345#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
346/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
347 * It's a pity that old uncompress does not check bit 0x20. That makes
348 * extension of the format actually undesirable because old compress
349 * would just crash on the new format instead of giving a meaningful
350 * error message. It does check the number of bits, but it's more
351 * helpful to say "unsupported format, get a new version" than
352 * "can only handle 16 bits".
353 */
354
355#define BLOCK_MODE 0x80
356/* Block compression: if table is full and compression rate is dropping,
357 * clear the dictionary.
358 */
359
360#define LZW_RESERVED 0x60 /* reserved bits */
361
362#define CLEAR 256 /* flush the dictionary */
363#define FIRST (CLEAR+1) /* first free entry */
364
365extern int maxbits; /* max bits per code for LZW */
366extern int block_mode; /* block compress mode -C compatible with 2.0 */
367
368/* revision.h -- define the version number
369 * Copyright (C) 1992-1993 Jean-loup Gailly.
370 * This is free software; you can redistribute it and/or modify it under the
371 * terms of the GNU General Public License, see the file COPYING.
372 */
373
374#define VERSION "1.2.4"
375#define PATCHLEVEL 0
376#define REVDATE "18 Aug 93"
377
378/* This version does not support compression into old compress format: */
379#ifdef LZW
380# undef LZW
381#endif
382
383/* $Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $ */
384/* tailor.h -- target dependent definitions
385 * Copyright (C) 1992-1993 Jean-loup Gailly.
386 * This is free software; you can redistribute it and/or modify it under the
387 * terms of the GNU General Public License, see the file COPYING.
388 */
389
390/* The target dependent definitions should be defined here only.
391 * The target dependent functions should be defined in tailor.c.
392 */
393
394/* $Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $ */
395
396#if defined(__MSDOS__) && !defined(MSDOS)
397# define MSDOS
398#endif
399
400#if defined(__OS2__) && !defined(OS2)
401# define OS2
402#endif
403
404#if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */
405# undef MSDOS
406#endif
407
408#ifdef MSDOS
409# ifdef __GNUC__
410 /* DJGPP version 1.09+ on MS-DOS.
411 * The DJGPP 1.09 stat() function must be upgraded before gzip will
412 * fully work.
413 * No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
414 * implies DIRENT.
415 */
416# define near
417# else
418# define MAXSEG_64K
419# ifdef __TURBOC__
420# define NO_OFF_T
421# ifdef __BORLANDC__
422# define DIRENT
423# else
424# define NO_UTIME
425# endif
426# else /* MSC */
427# define HAVE_SYS_UTIME_H
428# define NO_UTIME_H
429# endif
430# endif
431# define PATH_SEP2 '\\'
432# define PATH_SEP3 ':'
433# define MAX_PATH_LEN 128
434# define NO_MULTIPLE_DOTS
435# define MAX_EXT_CHARS 3
436# define Z_SUFFIX "z"
437# define NO_CHOWN
438# define PROTO
439# define STDC_HEADERS
440# define NO_SIZE_CHECK
441# define casemap(c) tolow(c) /* Force file names to lower case */
442# include <io.h>
443# define OS_CODE 0x00
444# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
445# if !defined(NO_ASM) && !defined(ASMV)
446# define ASMV
447# endif
448#else
449# define near
450#endif
451
452#ifdef OS2
453# define PATH_SEP2 '\\'
454# define PATH_SEP3 ':'
455# define MAX_PATH_LEN 260
456# ifdef OS2FAT
457# define NO_MULTIPLE_DOTS
458# define MAX_EXT_CHARS 3
459# define Z_SUFFIX "z"
460# define casemap(c) tolow(c)
461# endif
462# define NO_CHOWN
463# define PROTO
464# define STDC_HEADERS
465# include <io.h>
466# define OS_CODE 0x06
467# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
468# ifdef _MSC_VER
469# define HAVE_SYS_UTIME_H
470# define NO_UTIME_H
471# define MAXSEG_64K
472# undef near
473# define near _near
474# endif
475# ifdef __EMX__
476# define HAVE_SYS_UTIME_H
477# define NO_UTIME_H
478# define DIRENT
479# define EXPAND(argc,argv) \
480 {_response(&argc, &argv); _wildcard(&argc, &argv);}
481# endif
482# ifdef __BORLANDC__
483# define DIRENT
484# endif
485# ifdef __ZTC__
486# define NO_DIR
487# define NO_UTIME_H
488# include <dos.h>
489# define EXPAND(argc,argv) \
490 {response_expand(&argc, &argv);}
491# endif
492#endif
493
494#ifdef WIN32 /* Windows NT */
495# define HAVE_SYS_UTIME_H
496# define NO_UTIME_H
497# define PATH_SEP2 '\\'
498# define PATH_SEP3 ':'
499# define MAX_PATH_LEN 260
500# define NO_CHOWN
501# define PROTO
502# define STDC_HEADERS
503# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
504# include <io.h>
505# include <malloc.h>
506# ifdef NTFAT
507# define NO_MULTIPLE_DOTS
508# define MAX_EXT_CHARS 3
509# define Z_SUFFIX "z"
510# define casemap(c) tolow(c) /* Force file names to lower case */
511# endif
512# define OS_CODE 0x0b
513#endif
514
515#ifdef MSDOS
516# ifdef __TURBOC__
517# include <alloc.h>
518# define DYN_ALLOC
519 /* Turbo C 2.0 does not accept static allocations of large arrays */
520 void * fcalloc (unsigned items, unsigned size);
521 void fcfree (void *ptr);
522# else /* MSC */
523# include <malloc.h>
524# define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
525# define fcfree(ptr) hfree(ptr)
526# endif
527#else
528# ifdef MAXSEG_64K
529# define fcalloc(items,size) calloc((items),(size))
530# else
531# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
532# endif
533# define fcfree(ptr) free(ptr)
534#endif
535
536#if defined(VAXC) || defined(VMS)
537# define PATH_SEP ']'
538# define PATH_SEP2 ':'
539# define SUFFIX_SEP ';'
540# define NO_MULTIPLE_DOTS
541# define Z_SUFFIX "-gz"
542# define RECORD_IO 1
543# define casemap(c) tolow(c)
544# define OS_CODE 0x02
545# define OPTIONS_VAR "GZIP_OPT"
546# define STDC_HEADERS
547# define NO_UTIME
548# define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
549# include <file.h>
550# define unlink delete
551# ifdef VAXC
552# define NO_FCNTL_H
553# include <unixio.h>
554# endif
555#endif
556
557#ifdef AMIGA
558# define PATH_SEP2 ':'
559# define STDC_HEADERS
560# define OS_CODE 0x01
561# define ASMV
562# ifdef __GNUC__
563# define DIRENT
564# define HAVE_UNISTD_H
565# else /* SASC */
566# define NO_STDIN_FSTAT
567# define SYSDIR
568# define NO_SYMLINK
569# define NO_CHOWN
570# define NO_FCNTL_H
571# include <fcntl.h> /* for read() and write() */
572# define direct dirent
573 extern void _expand_args(int *argc, char ***argv);
574# define EXPAND(argc,argv) _expand_args(&argc,&argv);
575# undef O_BINARY /* disable useless --ascii option */
576# endif
577#endif
578
579#if defined(ATARI) || defined(atarist)
580# ifndef STDC_HEADERS
581# define STDC_HEADERS
582# define HAVE_UNISTD_H
583# define DIRENT
584# endif
585# define ASMV
586# define OS_CODE 0x05
587# ifdef TOSFS
588# define PATH_SEP2 '\\'
589# define PATH_SEP3 ':'
590# define MAX_PATH_LEN 128
591# define NO_MULTIPLE_DOTS
592# define MAX_EXT_CHARS 3
593# define Z_SUFFIX "z"
594# define NO_CHOWN
595# define casemap(c) tolow(c) /* Force file names to lower case */
596# define NO_SYMLINK
597# endif
598#endif
599
600#ifdef MACOS
601# define PATH_SEP ':'
602# define DYN_ALLOC
603# define PROTO
604# define NO_STDIN_FSTAT
605# define NO_CHOWN
606# define NO_UTIME
607# define chmod(file, mode) (0)
608# define OPEN(name, flags, mode) open(name, flags)
609# define OS_CODE 0x07
610# ifdef MPW
611# define isatty(fd) ((fd) <= 2)
612# endif
613#endif
614
615#ifdef __50SERIES /* Prime/PRIMOS */
616# define PATH_SEP '>'
617# define STDC_HEADERS
618# define NO_MEMORY_H
619# define NO_UTIME_H
620# define NO_UTIME
621# define NO_CHOWN
622# define NO_STDIN_FSTAT
623# define NO_SIZE_CHECK
624# define NO_SYMLINK
625# define RECORD_IO 1
626# define casemap(c) tolow(c) /* Force file names to lower case */
627# define put_char(c) put_byte((c) & 0x7F)
628# define get_char(c) ascii2pascii(get_byte())
629# define OS_CODE 0x0F /* temporary, subject to change */
630# ifdef SIGTERM
631# undef SIGTERM /* We don't want a signal handler for SIGTERM */
632# endif
633#endif
634
635#if defined(pyr) && !defined(NOMEMCPY) /* Pyramid */
636# define NOMEMCPY /* problem with overlapping copies */
637#endif
638
639#ifdef TOPS20
640# define OS_CODE 0x0a
641#endif
642
643#ifndef unix
644# define NO_ST_INO /* don't rely on inode numbers */
645#endif
646
647
648 /* Common defaults */
649
650#ifndef OS_CODE
651# define OS_CODE 0x03 /* assume Unix */
652#endif
653
654#ifndef PATH_SEP
655# define PATH_SEP '/'
656#endif
657
658#ifndef casemap
659# define casemap(c) (c)
660#endif
661
662#ifndef OPTIONS_VAR
663# define OPTIONS_VAR "GZIP"
664#endif
665
666#ifndef Z_SUFFIX
667# define Z_SUFFIX ".gz"
668#endif
669
670#ifdef MAX_EXT_CHARS
671# define MAX_SUFFIX MAX_EXT_CHARS
672#else
673# define MAX_SUFFIX 30
674#endif
675
676#ifndef MAKE_LEGAL_NAME
677# ifdef NO_MULTIPLE_DOTS
678# define MAKE_LEGAL_NAME(name) make_simple_name(name)
679# else
680# define MAKE_LEGAL_NAME(name)
681# endif
682#endif
683
684#ifndef MIN_PART
685# define MIN_PART 3
686 /* keep at least MIN_PART chars between dots in a file name. */
687#endif
688
689#ifndef EXPAND
690# define EXPAND(argc,argv)
691#endif
692
693#ifndef RECORD_IO
694# define RECORD_IO 0
695#endif
696
697#ifndef SET_BINARY_MODE
698# define SET_BINARY_MODE(fd)
699#endif
700
701#ifndef OPEN
702# define OPEN(name, flags, mode) open(name, flags, mode)
703#endif
704
705#ifndef get_char
706# define get_char() get_byte()
707#endif
708
709#ifndef put_char
710# define put_char(c) put_byte(c)
711#endif
712/* bits.c -- output variable-length bit strings
713 * Copyright (C) 1992-1993 Jean-loup Gailly
714 * This is free software; you can redistribute it and/or modify it under the
715 * terms of the GNU General Public License, see the file COPYING.
716 */
717
718
719/*
720 * PURPOSE
721 *
722 * Output variable-length bit strings. Compression can be done
723 * to a file or to memory. (The latter is not supported in this version.)
724 *
725 * DISCUSSION
726 *
727 * The PKZIP "deflate" file format interprets compressed file data
728 * as a sequence of bits. Multi-bit strings in the file may cross
729 * byte boundaries without restriction.
730 *
731 * The first bit of each byte is the low-order bit.
732 *
733 * The routines in this file allow a variable-length bit value to
734 * be output right-to-left (useful for literal values). For
735 * left-to-right output (useful for code strings from the tree routines),
736 * the bits must have been reversed first with bi_reverse().
737 *
738 * For in-memory compression, the compressed bit stream goes directly
739 * into the requested output buffer. The input data is read in blocks
740 * by the mem_read() function. The buffer is limited to 64K on 16 bit
741 * machines.
742 *
743 * INTERFACE
744 *
745 * void bi_init (FILE *zipfile)
746 * Initialize the bit string routines.
747 *
748 * void send_bits (int value, int length)
749 * Write out a bit string, taking the source bits right to
750 * left.
751 *
752 * int bi_reverse (int value, int length)
753 * Reverse the bits of a bit string, taking the source bits left to
754 * right and emitting them right to left.
755 *
756 * void bi_windup (void)
757 * Write out any remaining bits in an incomplete byte.
758 *
759 * void copy_block(char *buf, unsigned len, int header)
760 * Copy a stored block to the zip file, storing first the length and
761 * its one's complement if requested.
762 *
763 */
764
765#ifdef DEBUG
766# include <stdio.h>
767#endif
768
769#ifdef RCSID
770static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
771#endif
772
773/* ===========================================================================
774 * Local data used by the "bit string" routines.
775 */
776
777local file_t zfile; /* output gzip file */
778
779local unsigned short bi_buf;
780/* Output buffer. bits are inserted starting at the bottom (least significant
781 * bits).
782 */
783
784#define Buf_size (8 * 2*sizeof(char))
785/* Number of bits used within bi_buf. (bi_buf might be implemented on
786 * more than 16 bits on some systems.)
787 */
788
789local int bi_valid;
790/* Number of valid bits in bi_buf. All bits above the last valid bit
791 * are always zero.
792 */
793
794int (*read_buf) OF((char *buf, unsigned size));
795/* Current input function. Set to mem_read for in-memory compression */
796
797#ifdef DEBUG
798 ulg bits_sent; /* bit length of the compressed data */
799#endif
800
801/* ===========================================================================
802 * Initialize the bit string routines.
803 */
804void bi_init (zipfile)
805 file_t zipfile; /* output zip file, NO_FILE for in-memory compression */
806{
807 zfile = zipfile;
808 bi_buf = 0;
809 bi_valid = 0;
810#ifdef DEBUG
811 bits_sent = 0L;
812#endif
813
814 /* Set the defaults for file compression. They are set by memcompress
815 * for in-memory compression.
816 */
817 if (zfile != NO_FILE) {
818 read_buf = file_read;
819 }
820}
821
822/* ===========================================================================
823 * Send a value on a given number of bits.
824 * IN assertion: length <= 16 and value fits in length bits.
825 */
826void send_bits(value, length)
827 int value; /* value to send */
828 int length; /* number of bits */
829{
830#ifdef DEBUG
831 Tracev((stderr," l %2d v %4x ", length, value));
832 Assert(length > 0 && length <= 15, "invalid length");
833 bits_sent += (ulg)length;
834#endif
835 /* If not enough room in bi_buf, use (valid) bits from bi_buf and
836 * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
837 * unused bits in value.
838 */
839 if (bi_valid > (int)Buf_size - length) {
840 bi_buf |= (value << bi_valid);
841 put_short(bi_buf);
842 bi_buf = (ush)value >> (Buf_size - bi_valid);
843 bi_valid += length - Buf_size;
844 } else {
845 bi_buf |= value << bi_valid;
846 bi_valid += length;
847 }
848}
849
850/* ===========================================================================
851 * Reverse the first len bits of a code, using straightforward code (a faster
852 * method would use a table)
853 * IN assertion: 1 <= len <= 15
854 */
855unsigned bi_reverse(code, len)
856 unsigned code; /* the value to invert */
857 int len; /* its bit length */
858{
859 register unsigned res = 0;
860 do {
861 res |= code & 1;
862 code >>= 1, res <<= 1;
863 } while (--len > 0);
864 return res >> 1;
865}
866
867/* ===========================================================================
868 * Write out any remaining bits in an incomplete byte.
869 */
870void bi_windup()
871{
872 if (bi_valid > 8) {
873 put_short(bi_buf);
874 } else if (bi_valid > 0) {
875 put_byte(bi_buf);
876 }
877 bi_buf = 0;
878 bi_valid = 0;
879#ifdef DEBUG
880 bits_sent = (bits_sent+7) & ~7;
881#endif
882}
883
884/* ===========================================================================
885 * Copy a stored block to the zip file, storing first the length and its
886 * one's complement if requested.
887 */
888void copy_block(buf, len, header)
889 char *buf; /* the input data */
890 unsigned len; /* its length */
891 int header; /* true if block header must be written */
892{
893 bi_windup(); /* align on byte boundary */
894
895 if (header) {
896 put_short((ush)len);
897 put_short((ush)~len);
898#ifdef DEBUG
899 bits_sent += 2*16;
900#endif
901 }
902#ifdef DEBUG
903 bits_sent += (ulg)len<<3;
904#endif
905 while (len--) {
906#ifdef CRYPT
907 int t;
908 if (key) zencode(*buf, t);
909#endif
910 put_byte(*buf++);
911 }
912}
913/* deflate.c -- compress data using the deflation algorithm
914 * Copyright (C) 1992-1993 Jean-loup Gailly
915 * This is free software; you can redistribute it and/or modify it under the
916 * terms of the GNU General Public License, see the file COPYING.
917 */
918
919/*
920 * PURPOSE
921 *
922 * Identify new text as repetitions of old text within a fixed-
923 * length sliding window trailing behind the new text.
924 *
925 * DISCUSSION
926 *
927 * The "deflation" process depends on being able to identify portions
928 * of the input text which are identical to earlier input (within a
929 * sliding window trailing behind the input currently being processed).
930 *
931 * The most straightforward technique turns out to be the fastest for
932 * most input files: try all possible matches and select the longest.
933 * The key feature of this algorithm is that insertions into the string
934 * dictionary are very simple and thus fast, and deletions are avoided
935 * completely. Insertions are performed at each input character, whereas
936 * string matches are performed only when the previous match ends. So it
937 * is preferable to spend more time in matches to allow very fast string
938 * insertions and avoid deletions. The matching algorithm for small
939 * strings is inspired from that of Rabin & Karp. A brute force approach
940 * is used to find longer strings when a small match has been found.
941 * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
942 * (by Leonid Broukhis).
943 * A previous version of this file used a more sophisticated algorithm
944 * (by Fiala and Greene) which is guaranteed to run in linear amortized
945 * time, but has a larger average cost, uses more memory and is patented.
946 * However the F&G algorithm may be faster for some highly redundant
947 * files if the parameter max_chain_length (described below) is too large.
948 *
949 * ACKNOWLEDGEMENTS
950 *
951 * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
952 * I found it in 'freeze' written by Leonid Broukhis.
953 * Thanks to many info-zippers for bug reports and testing.
954 *
955 * REFERENCES
956 *
957 * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
958 *
959 * A description of the Rabin and Karp algorithm is given in the book
960 * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
961 *
962 * Fiala,E.R., and Greene,D.H.
963 * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
964 *
965 * INTERFACE
966 *
967 * void lm_init (int pack_level, ush *flags)
968 * Initialize the "longest match" routines for a new file
969 *
970 * ulg deflate (void)
971 * Processes a new input file and return its compressed length. Sets
972 * the compressed length, crc, deflate flags and internal file
973 * attributes.
974 */
975
976#include <stdio.h>
977
978#ifdef RCSID
979static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
980#endif
981
982/* ===========================================================================
983 * Configuration parameters
984 */
985
986/* Compile with MEDIUM_MEM to reduce the memory requirements or
987 * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
988 * entire input file can be held in memory (not possible on 16 bit systems).
989 * Warning: defining these symbols affects HASH_BITS (see below) and thus
990 * affects the compression ratio. The compressed output
991 * is still correct, and might even be smaller in some cases.
992 */
993
994#ifdef SMALL_MEM
995# define HASH_BITS 13 /* Number of bits used to hash strings */
996#endif
997#ifdef MEDIUM_MEM
998# define HASH_BITS 14
999#endif
1000#ifndef HASH_BITS
1001# define HASH_BITS 15
1002 /* For portability to 16 bit machines, do not use values above 15. */
1003#endif
1004
1005/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
1006 * window with tab_suffix. Check that we can do this:
1007 */
1008#if (WSIZE<<1) > (1<<BITS)
1009 error: cannot overlay window with tab_suffix and prev with tab_prefix0
1010#endif
1011#if HASH_BITS > BITS-1
1012 error: cannot overlay head with tab_prefix1
1013#endif
1014
1015#define HASH_SIZE (unsigned)(1<<HASH_BITS)
1016#define HASH_MASK (HASH_SIZE-1)
1017#define WMASK (WSIZE-1)
1018/* HASH_SIZE and WSIZE must be powers of two */
1019
1020#define NIL 0
1021/* Tail of hash chains */
1022
1023#define FAST 4
1024#define SLOW 2
1025/* speed options for the general purpose bit flag */
1026
1027#ifndef TOO_FAR
1028# define TOO_FAR 4096
1029#endif
1030/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
1031
1032/* ===========================================================================
1033 * Local data used by the "longest match" routines.
1034 */
1035
1036typedef ush Pos;
1037typedef unsigned IPos;
1038/* A Pos is an index in the character window. We use short instead of int to
1039 * save space in the various tables. IPos is used only for parameter passing.
1040 */
1041
1042/* DECLARE(uch, window, 2L*WSIZE); */
1043/* Sliding window. Input bytes are read into the second half of the window,
1044 * and move to the first half later to keep a dictionary of at least WSIZE
1045 * bytes. With this organization, matches are limited to a distance of
1046 * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
1047 * performed with a length multiple of the block size. Also, it limits
1048 * the window size to 64K, which is quite useful on MSDOS.
1049 * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
1050 * be less efficient).
1051 */
1052
1053/* DECLARE(Pos, prev, WSIZE); */
1054/* Link to older string with same hash index. To limit the size of this
1055 * array to 64K, this link is maintained only for the last 32K strings.
1056 * An index in this array is thus a window index modulo 32K.
1057 */
1058
1059/* DECLARE(Pos, head, 1<<HASH_BITS); */
1060/* Heads of the hash chains or NIL. */
1061
1062ulg window_size = (ulg)2*WSIZE;
1063/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
1064 * input file length plus MIN_LOOKAHEAD.
1065 */
1066
1067long block_start;
1068/* window position at the beginning of the current output block. Gets
1069 * negative when the window is moved backwards.
1070 */
1071
1072local unsigned ins_h; /* hash index of string to be inserted */
1073
1074#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
1075/* Number of bits by which ins_h and del_h must be shifted at each
1076 * input step. It must be such that after MIN_MATCH steps, the oldest
1077 * byte no longer takes part in the hash key, that is:
1078 * H_SHIFT * MIN_MATCH >= HASH_BITS
1079 */
1080
1081unsigned int near prev_length;
1082/* Length of the best match at previous step. Matches not greater than this
1083 * are discarded. This is used in the lazy match evaluation.
1084 */
1085
1086 unsigned near strstart; /* start of string to insert */
1087 unsigned near match_start; /* start of matching string */
1088local int eofile; /* flag set at end of input file */
1089local unsigned lookahead; /* number of valid bytes ahead in window */
1090
1091unsigned near max_chain_length;
1092/* To speed up deflation, hash chains are never searched beyond this length.
1093 * A higher limit improves compression ratio but degrades the speed.
1094 */
1095
1096local unsigned int max_lazy_match;
1097/* Attempt to find a better match only when the current match is strictly
1098 * smaller than this value. This mechanism is used only for compression
1099 * levels >= 4.
1100 */
1101#define max_insert_length max_lazy_match
1102/* Insert new strings in the hash table only if the match length
1103 * is not greater than this length. This saves time but degrades compression.
1104 * max_insert_length is used only for compression levels <= 3.
1105 */
1106
1107unsigned near good_match;
1108/* Use a faster search when the previous match is longer than this */
1109
1110
1111/* Values for max_lazy_match, good_match and max_chain_length, depending on
1112 * the desired pack level (0..9). The values given below have been tuned to
1113 * exclude worst case performance for pathological files. Better values may be
1114 * found for specific files.
1115 */
1116
1117typedef struct config {
1118 ush good_length; /* reduce lazy search above this match length */
1119 ush max_lazy; /* do not perform lazy search above this match length */
1120 ush nice_length; /* quit search above this match length */
1121 ush max_chain;
1122} config;
1123
1124#ifdef FULL_SEARCH
1125# define nice_match MAX_MATCH
1126#else
1127 int near nice_match; /* Stop searching when current match exceeds this */
1128#endif
1129
1130local config configuration_table =
1131/* 9 */ {32, 258, 258, 4096}; /* maximum compression */
1132
1133/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
1134 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
1135 * meaning.
1136 */
1137
1138#define EQUAL 0
1139/* result of memcmp for equal strings */
1140
1141/* ===========================================================================
1142 * Prototypes for local functions.
1143 */
1144local void fill_window OF((void));
1145
1146 int longest_match OF((IPos cur_match));
1147#ifdef ASMV
1148 void match_init OF((void)); /* asm code initialization */
1149#endif
1150
1151#ifdef DEBUG
1152local void check_match OF((IPos start, IPos match, int length));
1153#endif
1154
1155/* ===========================================================================
1156 * Update a hash value with the given input byte
1157 * IN assertion: all calls to to UPDATE_HASH are made with consecutive
1158 * input characters, so that a running hash key can be computed from the
1159 * previous key instead of complete recalculation each time.
1160 */
1161#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
1162
1163/* ===========================================================================
1164 * Insert string s in the dictionary and set match_head to the previous head
1165 * of the hash chain (the most recent string with same hash key). Return
1166 * the previous length of the hash chain.
1167 * IN assertion: all calls to to INSERT_STRING are made with consecutive
1168 * input characters and the first MIN_MATCH bytes of s are valid
1169 * (except for the last MIN_MATCH-1 bytes of the input file).
1170 */
1171#define INSERT_STRING(s, match_head) \
1172 (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
1173 prev[(s) & WMASK] = match_head = head[ins_h], \
1174 head[ins_h] = (s))
1175
1176/* ===========================================================================
1177 * Initialize the "longest match" routines for a new file
1178 */
1179void lm_init (flags)
1180 ush *flags; /* general purpose bit flag */
1181{
1182 register unsigned j;
1183
1184 /* Initialize the hash table. */
1185#if defined(MAXSEG_64K) && HASH_BITS == 15
1186 for (j = 0; j < HASH_SIZE; j++) head[j] = NIL;
1187#else
1188 memzero((char*)head, HASH_SIZE*sizeof(*head));
1189#endif
1190 /* prev will be initialized on the fly */
1191
1192 /* Set the default configuration parameters:
1193 */
1194 max_lazy_match = configuration_table.max_lazy;
1195 good_match = configuration_table.good_length;
1196#ifndef FULL_SEARCH
1197 nice_match = configuration_table.nice_length;
1198#endif
1199 max_chain_length = configuration_table.max_chain;
1200 *flags |= SLOW;
1201 /* ??? reduce max_chain_length for binary files */
1202
1203 strstart = 0;
1204 block_start = 0L;
1205#ifdef ASMV
1206 match_init(); /* initialize the asm code */
1207#endif
1208
1209 lookahead = read_buf((char*)window,
1210 sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
1211
1212 if (lookahead == 0 || lookahead == (unsigned)EOF) {
1213 eofile = 1, lookahead = 0;
1214 return;
1215 }
1216 eofile = 0;
1217 /* Make sure that we always have enough lookahead. This is important
1218 * if input comes from a device such as a tty.
1219 */
1220 while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
1221
1222 ins_h = 0;
1223 for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
1224 /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
1225 * not important since only literal bytes will be emitted.
1226 */
1227}
1228
1229/* ===========================================================================
1230 * Set match_start to the longest match starting at the given string and
1231 * return its length. Matches shorter or equal to prev_length are discarded,
1232 * in which case the result is equal to prev_length and match_start is
1233 * garbage.
1234 * IN assertions: cur_match is the head of the hash chain for the current
1235 * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
1236 */
1237#ifndef ASMV
1238/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
1239 * match.s. The code is functionally equivalent, so you can use the C version
1240 * if desired.
1241 */
1242int longest_match(cur_match)
1243 IPos cur_match; /* current match */
1244{
1245 unsigned chain_length = max_chain_length; /* max hash chain length */
1246 register uch *scan = window + strstart; /* current string */
1247 register uch *match; /* matched string */
1248 register int len; /* length of current match */
1249 int best_len = prev_length; /* best match length so far */
1250 IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
1251 /* Stop when cur_match becomes <= limit. To simplify the code,
1252 * we prevent matches with the string of window index 0.
1253 */
1254
1255/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
1256 * It is easy to get rid of this optimization if necessary.
1257 */
1258#if HASH_BITS < 8 || MAX_MATCH != 258
1259 error: Code too clever
1260#endif
1261
1262#ifdef UNALIGNED_OK
1263 /* Compare two bytes at a time. Note: this is not always beneficial.
1264 * Try with and without -DUNALIGNED_OK to check.
1265 */
1266 register uch *strend = window + strstart + MAX_MATCH - 1;
1267 register ush scan_start = *(ush*)scan;
1268 register ush scan_end = *(ush*)(scan+best_len-1);
1269#else
1270 register uch *strend = window + strstart + MAX_MATCH;
1271 register uch scan_end1 = scan[best_len-1];
1272 register uch scan_end = scan[best_len];
1273#endif
1274
1275 /* Do not waste too much time if we already have a good match: */
1276 if (prev_length >= good_match) {
1277 chain_length >>= 2;
1278 }
1279 Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
1280
1281 do {
1282 Assert(cur_match < strstart, "no future");
1283 match = window + cur_match;
1284
1285 /* Skip to next match if the match length cannot increase
1286 * or if the match length is less than 2:
1287 */
1288#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
1289 /* This code assumes sizeof(unsigned short) == 2. Do not use
1290 * UNALIGNED_OK if your compiler uses a different size.
1291 */
1292 if (*(ush*)(match+best_len-1) != scan_end ||
1293 *(ush*)match != scan_start) continue;
1294
1295 /* It is not necessary to compare scan[2] and match[2] since they are
1296 * always equal when the other bytes match, given that the hash keys
1297 * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
1298 * strstart+3, +5, ... up to strstart+257. We check for insufficient
1299 * lookahead only every 4th comparison; the 128th check will be made
1300 * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
1301 * necessary to put more guard bytes at the end of the window, or
1302 * to check more often for insufficient lookahead.
1303 */
1304 scan++, match++;
1305 do {
1306 } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
1307 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
1308 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
1309 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
1310 scan < strend);
1311 /* The funny "do {}" generates better code on most compilers */
1312
1313 /* Here, scan <= window+strstart+257 */
1314 Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
1315 if (*scan == *match) scan++;
1316
1317 len = (MAX_MATCH - 1) - (int)(strend-scan);
1318 scan = strend - (MAX_MATCH-1);
1319
1320#else /* UNALIGNED_OK */
1321
1322 if (match[best_len] != scan_end ||
1323 match[best_len-1] != scan_end1 ||
1324 *match != *scan ||
1325 *++match != scan[1]) continue;
1326
1327 /* The check at best_len-1 can be removed because it will be made
1328 * again later. (This heuristic is not always a win.)
1329 * It is not necessary to compare scan[2] and match[2] since they
1330 * are always equal when the other bytes match, given that
1331 * the hash keys are equal and that HASH_BITS >= 8.
1332 */
1333 scan += 2, match++;
1334
1335 /* We check for insufficient lookahead only every 8th comparison;
1336 * the 256th check will be made at strstart+258.
1337 */
1338 do {
1339 } while (*++scan == *++match && *++scan == *++match &&
1340 *++scan == *++match && *++scan == *++match &&
1341 *++scan == *++match && *++scan == *++match &&
1342 *++scan == *++match && *++scan == *++match &&
1343 scan < strend);
1344
1345 len = MAX_MATCH - (int)(strend - scan);
1346 scan = strend - MAX_MATCH;
1347
1348#endif /* UNALIGNED_OK */
1349
1350 if (len > best_len) {
1351 match_start = cur_match;
1352 best_len = len;
1353 if (len >= nice_match) break;
1354#ifdef UNALIGNED_OK
1355 scan_end = *(ush*)(scan+best_len-1);
1356#else
1357 scan_end1 = scan[best_len-1];
1358 scan_end = scan[best_len];
1359#endif
1360 }
1361 } while ((cur_match = prev[cur_match & WMASK]) > limit
1362 && --chain_length != 0);
1363
1364 return best_len;
1365}
1366#endif /* ASMV */
1367
1368#ifdef DEBUG
1369/* ===========================================================================
1370 * Check that the match at match_start is indeed a match.
1371 */
1372local void check_match(start, match, length)
1373 IPos start, match;
1374 int length;
1375{
1376 /* check that the match is indeed a match */
1377 if (memcmp((char*)window + match,
1378 (char*)window + start, length) != EQUAL) {
1379 fprintf(stderr,
1380 " start %d, match %d, length %d\n",
1381 start, match, length);
1382 error("invalid match");
1383 }
1384 if (verbose > 1) {
1385 fprintf(stderr,"\\[%d,%d]", start-match, length);
1386 do { putc(window[start++], stderr); } while (--length != 0);
1387 }
1388}
1389#else
1390# define check_match(start, match, length)
1391#endif
1392
1393/* ===========================================================================
1394 * Fill the window when the lookahead becomes insufficient.
1395 * Updates strstart and lookahead, and sets eofile if end of input file.
1396 * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
1397 * OUT assertions: at least one byte has been read, or eofile is set;
1398 * file reads are performed for at least two bytes (required for the
1399 * translate_eol option).
1400 */
1401local void fill_window()
1402{
1403 register unsigned n, m;
1404 unsigned more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
1405 /* Amount of free space at the end of the window. */
1406
1407 /* If the window is almost full and there is insufficient lookahead,
1408 * move the upper half to the lower one to make room in the upper half.
1409 */
1410 if (more == (unsigned)EOF) {
1411 /* Very unlikely, but possible on 16 bit machine if strstart == 0
1412 * and lookahead == 1 (input done one byte at time)
1413 */
1414 more--;
1415 } else if (strstart >= WSIZE+MAX_DIST) {
1416 /* By the IN assertion, the window is not empty so we can't confuse
1417 * more == 0 with more == 64K on a 16 bit machine.
1418 */
1419 Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
1420
1421 memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
1422 match_start -= WSIZE;
1423 strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
1424
1425 block_start -= (long) WSIZE;
1426
1427 for (n = 0; n < HASH_SIZE; n++) {
1428 m = head[n];
1429 head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1430 }
1431 for (n = 0; n < WSIZE; n++) {
1432 m = prev[n];
1433 prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
1434 /* If n is not on any hash chain, prev[n] is garbage but
1435 * its value will never be used.
1436 */
1437 }
1438 more += WSIZE;
1439 }
1440 /* At this point, more >= 2 */
1441 if (!eofile) {
1442 n = read_buf((char*)window+strstart+lookahead, more);
1443 if (n == 0 || n == (unsigned)EOF) {
1444 eofile = 1;
1445 } else {
1446 lookahead += n;
1447 }
1448 }
1449}
1450
1451/* ===========================================================================
1452 * Flush the current block, with given end-of-file flag.
1453 * IN assertion: strstart is set to the end of the current match.
1454 */
1455#define FLUSH_BLOCK(eof) \
1456 flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
1457 (char*)NULL, (long)strstart - block_start, (eof))
1458
1459/* ===========================================================================
1460 * Same as above, but achieves better compression. We use a lazy
1461 * evaluation for matches: a match is finally adopted only if there is
1462 * no better match at the next window position.
1463 */
1464ulg deflate()
1465{
1466 IPos hash_head; /* head of hash chain */
1467 IPos prev_match; /* previous match */
1468 int flush; /* set if current block must be flushed */
1469 int match_available = 0; /* set if previous match exists */
1470 register unsigned match_length = MIN_MATCH-1; /* length of best match */
1471#ifdef DEBUG
1472 extern long isize; /* byte length of input file, for debug only */
1473#endif
1474
1475 /* Process the input block. */
1476 while (lookahead != 0) {
1477 /* Insert the string window[strstart .. strstart+2] in the
1478 * dictionary, and set hash_head to the head of the hash chain:
1479 */
1480 INSERT_STRING(strstart, hash_head);
1481
1482 /* Find the longest match, discarding those <= prev_length.
1483 */
1484 prev_length = match_length, prev_match = match_start;
1485 match_length = MIN_MATCH-1;
1486
1487 if (hash_head != NIL && prev_length < max_lazy_match &&
1488 strstart - hash_head <= MAX_DIST) {
1489 /* To simplify the code, we prevent matches with the string
1490 * of window index 0 (in particular we have to avoid a match
1491 * of the string with itself at the start of the input file).
1492 */
1493 match_length = longest_match (hash_head);
1494 /* longest_match() sets match_start */
1495 if (match_length > lookahead) match_length = lookahead;
1496
1497 /* Ignore a length 3 match if it is too distant: */
1498 if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
1499 /* If prev_match is also MIN_MATCH, match_start is garbage
1500 * but we will ignore the current match anyway.
1501 */
1502 match_length--;
1503 }
1504 }
1505 /* If there was a match at the previous step and the current
1506 * match is not better, output the previous match:
1507 */
1508 if (prev_length >= MIN_MATCH && match_length <= prev_length) {
1509
1510 check_match(strstart-1, prev_match, prev_length);
1511
1512 flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
1513
1514 /* Insert in hash table all strings up to the end of the match.
1515 * strstart-1 and strstart are already inserted.
1516 */
1517 lookahead -= prev_length-1;
1518 prev_length -= 2;
1519 do {
1520 strstart++;
1521 INSERT_STRING(strstart, hash_head);
1522 /* strstart never exceeds WSIZE-MAX_MATCH, so there are
1523 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
1524 * these bytes are garbage, but it does not matter since the
1525 * next lookahead bytes will always be emitted as literals.
1526 */
1527 } while (--prev_length != 0);
1528 match_available = 0;
1529 match_length = MIN_MATCH-1;
1530 strstart++;
1531 if (flush) FLUSH_BLOCK(0), block_start = strstart;
1532
1533 } else if (match_available) {
1534 /* If there was no match at the previous position, output a
1535 * single literal. If there was a match but the current match
1536 * is longer, truncate the previous match to a single literal.
1537 */
1538 Tracevv((stderr,"%c",window[strstart-1]));
1539 if (ct_tally (0, window[strstart-1])) {
1540 FLUSH_BLOCK(0), block_start = strstart;
1541 }
1542 strstart++;
1543 lookahead--;
1544 } else {
1545 /* There is no previous match to compare with, wait for
1546 * the next step to decide.
1547 */
1548 match_available = 1;
1549 strstart++;
1550 lookahead--;
1551 }
1552 Assert (strstart <= isize && lookahead <= isize, "a bit too far");
1553
1554 /* Make sure that we always have enough lookahead, except
1555 * at the end of the input file. We need MAX_MATCH bytes
1556 * for the next match, plus MIN_MATCH bytes to insert the
1557 * string following the next match.
1558 */
1559 while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
1560 }
1561 if (match_available) ct_tally (0, window[strstart-1]);
1562
1563 return FLUSH_BLOCK(1); /* eof */
1564}
1565/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
1566 * Copyright (C) 1992-1993 Jean-loup Gailly
1567 * The unzip code was written and put in the public domain by Mark Adler.
1568 * Portions of the lzw code are derived from the public domain 'compress'
1569 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
1570 * Ken Turkowski, Dave Mack and Peter Jannesen.
1571 *
1572 * See the license_msg below and the file COPYING for the software license.
1573 * See the file algorithm.doc for the compression algorithms and file formats.
1574 */
1575
1576/* Compress files with zip algorithm and 'compress' interface.
1577 * See usage() and help() functions below for all options.
1578 * Outputs:
1579 * file.gz: compressed file with same mode, owner, and utimes
1580 * or stdout with -c option or if stdin used as input.
1581 * If the output file name had to be truncated, the original name is kept
1582 * in the compressed file.
1583 * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
1584 *
1585 * Using gz on MSDOS would create too many file name conflicts. For
1586 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
1587 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
1588 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
1589 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
1590 *
1591 * For the meaning of all compilation flags, see comments in Makefile.in.
1592 */
1593
1594#ifdef RCSID
1595static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
1596#endif
1597
1598#include <ctype.h>
1599#include <sys/types.h>
1600#include <signal.h>
1601#include <sys/stat.h>
1602#include <errno.h>
1603
1604 /* configuration */
1605
1606#ifdef NO_TIME_H
1607# include <sys/time.h>
1608#else
1609# include <time.h>
1610#endif
1611
1612#ifndef NO_FCNTL_H
1613# include <fcntl.h>
1614#endif
1615
1616#ifdef HAVE_UNISTD_H
1617# include <unistd.h>
1618#endif
1619
1620#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
1621# include <stdlib.h>
1622#else
1623 extern int errno;
1624#endif
1625
1626#if defined(DIRENT)
1627# include <dirent.h>
1628 typedef struct dirent dir_type;
1629# define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
1630# define DIR_OPT "DIRENT"
1631#else
1632# define NLENGTH(dirent) ((dirent)->d_namlen)
1633# ifdef SYSDIR
1634# include <sys/dir.h>
1635 typedef struct direct dir_type;
1636# define DIR_OPT "SYSDIR"
1637# else
1638# ifdef SYSNDIR
1639# include <sys/ndir.h>
1640 typedef struct direct dir_type;
1641# define DIR_OPT "SYSNDIR"
1642# else
1643# ifdef NDIR
1644# include <ndir.h>
1645 typedef struct direct dir_type;
1646# define DIR_OPT "NDIR"
1647# else
1648# define NO_DIR
1649# define DIR_OPT "NO_DIR"
1650# endif
1651# endif
1652# endif
1653#endif
1654
1655#ifndef NO_UTIME
1656# ifndef NO_UTIME_H
1657# include <utime.h>
1658# define TIME_OPT "UTIME"
1659# else
1660# ifdef HAVE_SYS_UTIME_H
1661# include <sys/utime.h>
1662# define TIME_OPT "SYS_UTIME"
1663# else
1664 struct utimbuf {
1665 time_t actime;
1666 time_t modtime;
1667 };
1668# define TIME_OPT ""
1669# endif
1670# endif
1671#else
1672# define TIME_OPT "NO_UTIME"
1673#endif
1674
1675#if !defined(S_ISDIR) && defined(S_IFDIR)
1676# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1677#endif
1678#if !defined(S_ISREG) && defined(S_IFREG)
1679# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1680#endif
1681
1682typedef RETSIGTYPE (*sig_type) OF((int));
1683
1684#ifndef O_BINARY
1685# define O_BINARY 0 /* creation mode for open() */
1686#endif
1687
1688#ifndef O_CREAT
1689 /* Pure BSD system? */
1690# include <sys/file.h>
1691# ifndef O_CREAT
1692# define O_CREAT FCREAT
1693# endif
1694# ifndef O_EXCL
1695# define O_EXCL FEXCL
1696# endif
1697#endif
1698
1699#ifndef S_IRUSR
1700# define S_IRUSR 0400
1701#endif
1702#ifndef S_IWUSR
1703# define S_IWUSR 0200
1704#endif
1705#define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
1706
1707#ifndef MAX_PATH_LEN
1708# define MAX_PATH_LEN 1024 /* max pathname length */
1709#endif
1710
1711#ifndef SEEK_END
1712# define SEEK_END 2
1713#endif
1714
1715#ifdef NO_OFF_T
1716 typedef long off_t;
1717 off_t lseek OF((int fd, off_t offset, int whence));
1718#endif
1719
1720/* Separator for file name parts (see shorten_name()) */
1721#ifdef NO_MULTIPLE_DOTS
1722# define PART_SEP "-"
1723#else
1724# define PART_SEP "."
1725#endif
1726
1727 /* global buffers */
1728
1729DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
1730DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
1731DECLARE(ush, d_buf, DIST_BUFSIZE);
1732DECLARE(uch, window, 2L*WSIZE);
1733#ifndef MAXSEG_64K
1734 DECLARE(ush, tab_prefix, 1L<<BITS);
1735#else
1736 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
1737 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
1738#endif
1739
1740 /* local variables */
1741
1742int ascii = 0; /* convert end-of-lines to local OS conventions */
1743int to_stdout = 0; /* output to stdout (-c) */
1744int decompress = 0; /* decompress (-d) */
1745int no_name = -1; /* don't save or restore the original file name */
1746int no_time = -1; /* don't save or restore the original file time */
1747int foreground; /* set if program run in foreground */
1748char *progname; /* program name */
1749static int method = DEFLATED;/* compression method */
1750static int exit_code = OK; /* program exit code */
1751int save_orig_name; /* set if original name must be saved */
1752int last_member; /* set for .zip and .Z files */
1753int part_nb; /* number of parts in .gz file */
1754long time_stamp; /* original time stamp (modification time) */
1755long ifile_size; /* input file size, -1 for devices (debug only) */
1756char *env; /* contents of GZIP env variable */
1757char **args = NULL; /* argv pointer if GZIP env variable defined */
1758char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
1759int z_len; /* strlen(z_suffix) */
1760
1761long bytes_in; /* number of input bytes */
1762long bytes_out; /* number of output bytes */
1763char ifname[MAX_PATH_LEN]; /* input file name */
1764char ofname[MAX_PATH_LEN]; /* output file name */
1765int remove_ofname = 0; /* remove output file on error */
1766struct stat istat; /* status for input file */
1767int ifd; /* input file descriptor */
1768int ofd; /* output file descriptor */
1769unsigned insize; /* valid bytes in inbuf */
1770unsigned inptr; /* index of next byte to be processed in inbuf */
1771unsigned outcnt; /* bytes in output buffer */
1772
1773/* local functions */
1774
1775local void treat_stdin OF((void));
1776static int (*work) OF((int infile, int outfile)) = zip; /* function to call */
1777
1778#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
1779
1780/* ======================================================================== */
1781// int main (argc, argv)
1782// int argc;
1783// char **argv;
1784int gzip_main(struct FileInfo * i, int argc, char * * argv)
1785{
1786 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
1787 if (foreground) {
1788 (void) signal (SIGINT, (sig_type)abort_gzip);
1789 }
1790#ifdef SIGTERM
1791 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
1792 (void) signal(SIGTERM, (sig_type)abort_gzip);
1793 }
1794#endif
1795#ifdef SIGHUP
1796 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
1797 (void) signal(SIGHUP, (sig_type)abort_gzip);
1798 }
1799#endif
1800
1801 strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
1802 z_len = strlen(z_suffix);
1803
1804 to_stdout = 1;
1805
1806 /* Allocate all global buffers (for DYN_ALLOC option) */
1807 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
1808 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
1809 ALLOC(ush, d_buf, DIST_BUFSIZE);
1810 ALLOC(uch, window, 2L*WSIZE);
1811#ifndef MAXSEG_64K
1812 ALLOC(ush, tab_prefix, 1L<<BITS);
1813#else
1814 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
1815 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
1816#endif
1817
1818 /* And get to work */
1819 treat_stdin();
1820 do_exit(exit_code);
1821 return exit_code; /* just to avoid lint warning */
1822}
1823
1824/* ========================================================================
1825 * Compress or decompress stdin
1826 */
1827local void treat_stdin()
1828{
1829 SET_BINARY_MODE(fileno(stdout));
1830 strcpy(ifname, "stdin");
1831 strcpy(ofname, "stdout");
1832
1833 /* Get the time stamp on the input file. */
1834 time_stamp = 0; /* time unknown by default */
1835
1836 ifile_size = -1L; /* convention for unknown size */
1837
1838 clear_bufs(); /* clear input and output buffers */
1839 to_stdout = 1;
1840 part_nb = 0;
1841
1842 /* Actually do the compression/decompression. Loop over zipped members.
1843 */
1844 if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
1845}
1846
1847/* ========================================================================
1848 * Free all dynamically allocated variables and exit with the given code.
1849 */
1850local void do_exit(int exitcode)
1851{
1852 static int in_exit = 0;
1853
1854 if (in_exit) exit(exitcode);
1855 in_exit = 1;
1856 if (env != NULL) free(env), env = NULL;
1857 if (args != NULL) free((char*)args), args = NULL;
1858 FREE(inbuf);
1859 FREE(outbuf);
1860 FREE(d_buf);
1861 FREE(window);
1862#ifndef MAXSEG_64K
1863 FREE(tab_prefix);
1864#else
1865 FREE(tab_prefix0);
1866 FREE(tab_prefix1);
1867#endif
1868 exit(exitcode);
1869}
1870/* trees.c -- output deflated data using Huffman coding
1871 * Copyright (C) 1992-1993 Jean-loup Gailly
1872 * This is free software; you can redistribute it and/or modify it under the
1873 * terms of the GNU General Public License, see the file COPYING.
1874 */
1875
1876/*
1877 * PURPOSE
1878 *
1879 * Encode various sets of source values using variable-length
1880 * binary code trees.
1881 *
1882 * DISCUSSION
1883 *
1884 * The PKZIP "deflation" process uses several Huffman trees. The more
1885 * common source values are represented by shorter bit sequences.
1886 *
1887 * Each code tree is stored in the ZIP file in a compressed form
1888 * which is itself a Huffman encoding of the lengths of
1889 * all the code strings (in ascending order by source values).
1890 * The actual code strings are reconstructed from the lengths in
1891 * the UNZIP process, as described in the "application note"
1892 * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
1893 *
1894 * REFERENCES
1895 *
1896 * Lynch, Thomas J.
1897 * Data Compression: Techniques and Applications, pp. 53-55.
1898 * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
1899 *
1900 * Storer, James A.
1901 * Data Compression: Methods and Theory, pp. 49-50.
1902 * Computer Science Press, 1988. ISBN 0-7167-8156-5.
1903 *
1904 * Sedgewick, R.
1905 * Algorithms, p290.
1906 * Addison-Wesley, 1983. ISBN 0-201-06672-6.
1907 *
1908 * INTERFACE
1909 *
1910 * void ct_init (ush *attr, int *methodp)
1911 * Allocate the match buffer, initialize the various tables and save
1912 * the location of the internal file attribute (ascii/binary) and
1913 * method (DEFLATE/STORE)
1914 *
1915 * void ct_tally (int dist, int lc);
1916 * Save the match info and tally the frequency counts.
1917 *
1918 * long flush_block (char *buf, ulg stored_len, int eof)
1919 * Determine the best encoding for the current block: dynamic trees,
1920 * static trees or store, and output the encoded block to the zip
1921 * file. Returns the total compressed length for the file so far.
1922 *
1923 */
1924
1925#include <ctype.h>
1926
1927#ifdef RCSID
1928static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
1929#endif
1930
1931/* ===========================================================================
1932 * Constants
1933 */
1934
1935#define MAX_BITS 15
1936/* All codes must not exceed MAX_BITS bits */
1937
1938#define MAX_BL_BITS 7
1939/* Bit length codes must not exceed MAX_BL_BITS bits */
1940
1941#define LENGTH_CODES 29
1942/* number of length codes, not counting the special END_BLOCK code */
1943
1944#define LITERALS 256
1945/* number of literal bytes 0..255 */
1946
1947#define END_BLOCK 256
1948/* end of block literal code */
1949
1950#define L_CODES (LITERALS+1+LENGTH_CODES)
1951/* number of Literal or Length codes, including the END_BLOCK code */
1952
1953#define D_CODES 30
1954/* number of distance codes */
1955
1956#define BL_CODES 19
1957/* number of codes used to transfer the bit lengths */
1958
1959
1960local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
1961 = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
1962
1963local int near extra_dbits[D_CODES] /* extra bits for each distance code */
1964 = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
1965
1966local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
1967 = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
1968
1969#define STORED_BLOCK 0
1970#define STATIC_TREES 1
1971#define DYN_TREES 2
1972/* The three kinds of block type */
1973
1974#ifndef LIT_BUFSIZE
1975# ifdef SMALL_MEM
1976# define LIT_BUFSIZE 0x2000
1977# else
1978# ifdef MEDIUM_MEM
1979# define LIT_BUFSIZE 0x4000
1980# else
1981# define LIT_BUFSIZE 0x8000
1982# endif
1983# endif
1984#endif
1985#ifndef DIST_BUFSIZE
1986# define DIST_BUFSIZE LIT_BUFSIZE
1987#endif
1988/* Sizes of match buffers for literals/lengths and distances. There are
1989 * 4 reasons for limiting LIT_BUFSIZE to 64K:
1990 * - frequencies can be kept in 16 bit counters
1991 * - if compression is not successful for the first block, all input data is
1992 * still in the window so we can still emit a stored block even when input
1993 * comes from standard input. (This can also be done for all blocks if
1994 * LIT_BUFSIZE is not greater than 32K.)
1995 * - if compression is not successful for a file smaller than 64K, we can
1996 * even emit a stored file instead of a stored block (saving 5 bytes).
1997 * - creating new Huffman trees less frequently may not provide fast
1998 * adaptation to changes in the input data statistics. (Take for
1999 * example a binary file with poorly compressible code followed by
2000 * a highly compressible string table.) Smaller buffer sizes give
2001 * fast adaptation but have of course the overhead of transmitting trees
2002 * more frequently.
2003 * - I can't count above 4
2004 * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
2005 * memory at the expense of compression). Some optimizations would be possible
2006 * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
2007 */
2008#if LIT_BUFSIZE > INBUFSIZ
2009 error cannot overlay l_buf and inbuf
2010#endif
2011
2012#define REP_3_6 16
2013/* repeat previous bit length 3-6 times (2 bits of repeat count) */
2014
2015#define REPZ_3_10 17
2016/* repeat a zero length 3-10 times (3 bits of repeat count) */
2017
2018#define REPZ_11_138 18
2019/* repeat a zero length 11-138 times (7 bits of repeat count) */
2020
2021/* ===========================================================================
2022 * Local data
2023 */
2024
2025/* Data structure describing a single value and its code string. */
2026typedef struct ct_data {
2027 union {
2028 ush freq; /* frequency count */
2029 ush code; /* bit string */
2030 } fc;
2031 union {
2032 ush dad; /* father node in Huffman tree */
2033 ush len; /* length of bit string */
2034 } dl;
2035} ct_data;
2036
2037#define Freq fc.freq
2038#define Code fc.code
2039#define Dad dl.dad
2040#define Len dl.len
2041
2042#define HEAP_SIZE (2*L_CODES+1)
2043/* maximum heap size */
2044
2045local ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
2046local ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
2047
2048local ct_data near static_ltree[L_CODES+2];
2049/* The static literal tree. Since the bit lengths are imposed, there is no
2050 * need for the L_CODES extra codes used during heap construction. However
2051 * The codes 286 and 287 are needed to build a canonical tree (see ct_init
2052 * below).
2053 */
2054
2055local ct_data near static_dtree[D_CODES];
2056/* The static distance tree. (Actually a trivial tree since all codes use
2057 * 5 bits.)
2058 */
2059
2060local ct_data near bl_tree[2*BL_CODES+1];
2061/* Huffman tree for the bit lengths */
2062
2063typedef struct tree_desc {
2064 ct_data near *dyn_tree; /* the dynamic tree */
2065 ct_data near *static_tree; /* corresponding static tree or NULL */
2066 int near *extra_bits; /* extra bits for each code or NULL */
2067 int extra_base; /* base index for extra_bits */
2068 int elems; /* max number of elements in the tree */
2069 int max_length; /* max bit length for the codes */
2070 int max_code; /* largest code with non zero frequency */
2071} tree_desc;
2072
2073local tree_desc near l_desc =
2074{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
2075
2076local tree_desc near d_desc =
2077{dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0};
2078
2079local tree_desc near bl_desc =
2080{bl_tree, (ct_data near *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0};
2081
2082
2083local ush near bl_count[MAX_BITS+1];
2084/* number of codes at each bit length for an optimal tree */
2085
2086local uch near bl_order[BL_CODES]
2087 = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
2088/* The lengths of the bit length codes are sent in order of decreasing
2089 * probability, to avoid transmitting the lengths for unused bit length codes.
2090 */
2091
2092local int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
2093local int heap_len; /* number of elements in the heap */
2094local int heap_max; /* element of largest frequency */
2095/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
2096 * The same heap array is used to build all trees.
2097 */
2098
2099local uch near depth[2*L_CODES+1];
2100/* Depth of each subtree used as tie breaker for trees of equal frequency */
2101
2102local uch length_code[MAX_MATCH-MIN_MATCH+1];
2103/* length code for each normalized match length (0 == MIN_MATCH) */
2104
2105local uch dist_code[512];
2106/* distance codes. The first 256 values correspond to the distances
2107 * 3 .. 258, the last 256 values correspond to the top 8 bits of
2108 * the 15 bit distances.
2109 */
2110
2111local int near base_length[LENGTH_CODES];
2112/* First normalized length for each code (0 = MIN_MATCH) */
2113
2114local int near base_dist[D_CODES];
2115/* First normalized distance for each code (0 = distance of 1) */
2116
2117#define l_buf inbuf
2118/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */
2119
2120/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
2121
2122local uch near flag_buf[(LIT_BUFSIZE/8)];
2123/* flag_buf is a bit array distinguishing literals from lengths in
2124 * l_buf, thus indicating the presence or absence of a distance.
2125 */
2126
2127local unsigned last_lit; /* running index in l_buf */
2128local unsigned last_dist; /* running index in d_buf */
2129local unsigned last_flags; /* running index in flag_buf */
2130local uch flags; /* current flags not yet saved in flag_buf */
2131local uch flag_bit; /* current bit used in flags */
2132/* bits are filled in flags starting at bit 0 (least significant).
2133 * Note: these flags are overkill in the current code since we don't
2134 * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
2135 */
2136
2137local ulg opt_len; /* bit length of current block with optimal trees */
2138local ulg static_len; /* bit length of current block with static trees */
2139
2140local ulg compressed_len; /* total bit length of compressed file */
2141
2142local ulg input_len; /* total byte length of input file */
2143/* input_len is for debugging only since we can get it by other means. */
2144
2145ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
2146int *file_method; /* pointer to DEFLATE or STORE */
2147
2148#ifdef DEBUG
2149extern ulg bits_sent; /* bit length of the compressed data */
2150extern long isize; /* byte length of input file */
2151#endif
2152
2153extern long block_start; /* window offset of current block */
2154extern unsigned near strstart; /* window offset of current string */
2155
2156/* ===========================================================================
2157 * Local (static) routines in this file.
2158 */
2159
2160local void init_block OF((void));
2161local void pqdownheap OF((ct_data near *tree, int k));
2162local void gen_bitlen OF((tree_desc near *desc));
2163local void gen_codes OF((ct_data near *tree, int max_code));
2164local void build_tree OF((tree_desc near *desc));
2165local void scan_tree OF((ct_data near *tree, int max_code));
2166local void send_tree OF((ct_data near *tree, int max_code));
2167local int build_bl_tree OF((void));
2168local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
2169local void compress_block OF((ct_data near *ltree, ct_data near *dtree));
2170local void set_file_type OF((void));
2171
2172
2173#ifndef DEBUG
2174# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
2175 /* Send a code of the given tree. c and tree must not have side effects */
2176
2177#else /* DEBUG */
2178# define send_code(c, tree) \
2179 { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
2180 send_bits(tree[c].Code, tree[c].Len); }
2181#endif
2182
2183#define d_code(dist) \
2184 ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
2185/* Mapping from a distance to a distance code. dist is the distance - 1 and
2186 * must not have side effects. dist_code[256] and dist_code[257] are never
2187 * used.
2188 */
2189
2190#define MAX(a,b) (a >= b ? a : b)
2191/* the arguments must not have side effects */
2192
2193/* ===========================================================================
2194 * Allocate the match buffer, initialize the various tables and save the
2195 * location of the internal file attribute (ascii/binary) and method
2196 * (DEFLATE/STORE).
2197 */
2198void ct_init(attr, methodp)
2199 ush *attr; /* pointer to internal file attribute */
2200 int *methodp; /* pointer to compression method */
2201{
2202 int n; /* iterates over tree elements */
2203 int bits; /* bit counter */
2204 int length; /* length value */
2205 int code; /* code value */
2206 int dist; /* distance index */
2207
2208 file_type = attr;
2209 file_method = methodp;
2210 compressed_len = input_len = 0L;
2211
2212 if (static_dtree[0].Len != 0) return; /* ct_init already called */
2213
2214 /* Initialize the mapping length (0..255) -> length code (0..28) */
2215 length = 0;
2216 for (code = 0; code < LENGTH_CODES-1; code++) {
2217 base_length[code] = length;
2218 for (n = 0; n < (1<<extra_lbits[code]); n++) {
2219 length_code[length++] = (uch)code;
2220 }
2221 }
2222 Assert (length == 256, "ct_init: length != 256");
2223 /* Note that the length 255 (match length 258) can be represented
2224 * in two different ways: code 284 + 5 bits or code 285, so we
2225 * overwrite length_code[255] to use the best encoding:
2226 */
2227 length_code[length-1] = (uch)code;
2228
2229 /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
2230 dist = 0;
2231 for (code = 0 ; code < 16; code++) {
2232 base_dist[code] = dist;
2233 for (n = 0; n < (1<<extra_dbits[code]); n++) {
2234 dist_code[dist++] = (uch)code;
2235 }
2236 }
2237 Assert (dist == 256, "ct_init: dist != 256");
2238 dist >>= 7; /* from now on, all distances are divided by 128 */
2239 for ( ; code < D_CODES; code++) {
2240 base_dist[code] = dist << 7;
2241 for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
2242 dist_code[256 + dist++] = (uch)code;
2243 }
2244 }
2245 Assert (dist == 256, "ct_init: 256+dist != 512");
2246
2247 /* Construct the codes of the static literal tree */
2248 for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
2249 n = 0;
2250 while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
2251 while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
2252 while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
2253 while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
2254 /* Codes 286 and 287 do not exist, but we must include them in the
2255 * tree construction to get a canonical Huffman tree (longest code
2256 * all ones)
2257 */
2258 gen_codes((ct_data near *)static_ltree, L_CODES+1);
2259
2260 /* The static distance tree is trivial: */
2261 for (n = 0; n < D_CODES; n++) {
2262 static_dtree[n].Len = 5;
2263 static_dtree[n].Code = bi_reverse(n, 5);
2264 }
2265
2266 /* Initialize the first block of the first file: */
2267 init_block();
2268}
2269
2270/* ===========================================================================
2271 * Initialize a new block.
2272 */
2273local void init_block()
2274{
2275 int n; /* iterates over tree elements */
2276
2277 /* Initialize the trees. */
2278 for (n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0;
2279 for (n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0;
2280 for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
2281
2282 dyn_ltree[END_BLOCK].Freq = 1;
2283 opt_len = static_len = 0L;
2284 last_lit = last_dist = last_flags = 0;
2285 flags = 0; flag_bit = 1;
2286}
2287
2288#define SMALLEST 1
2289/* Index within the heap array of least frequent node in the Huffman tree */
2290
2291
2292/* ===========================================================================
2293 * Remove the smallest element from the heap and recreate the heap with
2294 * one less element. Updates heap and heap_len.
2295 */
2296#define pqremove(tree, top) \
2297{\
2298 top = heap[SMALLEST]; \
2299 heap[SMALLEST] = heap[heap_len--]; \
2300 pqdownheap(tree, SMALLEST); \
2301}
2302
2303/* ===========================================================================
2304 * Compares to subtrees, using the tree depth as tie breaker when
2305 * the subtrees have equal frequency. This minimizes the worst case length.
2306 */
2307#define smaller(tree, n, m) \
2308 (tree[n].Freq < tree[m].Freq || \
2309 (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
2310
2311/* ===========================================================================
2312 * Restore the heap property by moving down the tree starting at node k,
2313 * exchanging a node with the smallest of its two sons if necessary, stopping
2314 * when the heap property is re-established (each father smaller than its
2315 * two sons).
2316 */
2317local void pqdownheap(tree, k)
2318 ct_data near *tree; /* the tree to restore */
2319 int k; /* node to move down */
2320{
2321 int v = heap[k];
2322 int j = k << 1; /* left son of k */
2323 while (j <= heap_len) {
2324 /* Set j to the smallest of the two sons: */
2325 if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
2326
2327 /* Exit if v is smaller than both sons */
2328 if (smaller(tree, v, heap[j])) break;
2329
2330 /* Exchange v with the smallest son */
2331 heap[k] = heap[j]; k = j;
2332
2333 /* And continue down the tree, setting j to the left son of k */
2334 j <<= 1;
2335 }
2336 heap[k] = v;
2337}
2338
2339/* ===========================================================================
2340 * Compute the optimal bit lengths for a tree and update the total bit length
2341 * for the current block.
2342 * IN assertion: the fields freq and dad are set, heap[heap_max] and
2343 * above are the tree nodes sorted by increasing frequency.
2344 * OUT assertions: the field len is set to the optimal bit length, the
2345 * array bl_count contains the frequencies for each bit length.
2346 * The length opt_len is updated; static_len is also updated if stree is
2347 * not null.
2348 */
2349local void gen_bitlen(desc)
2350 tree_desc near *desc; /* the tree descriptor */
2351{
2352 ct_data near *tree = desc->dyn_tree;
2353 int near *extra = desc->extra_bits;
2354 int base = desc->extra_base;
2355 int max_code = desc->max_code;
2356 int max_length = desc->max_length;
2357 ct_data near *stree = desc->static_tree;
2358 int h; /* heap index */
2359 int n, m; /* iterate over the tree elements */
2360 int bits; /* bit length */
2361 int xbits; /* extra bits */
2362 ush f; /* frequency */
2363 int overflow = 0; /* number of elements with bit length too large */
2364
2365 for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
2366
2367 /* In a first pass, compute the optimal bit lengths (which may
2368 * overflow in the case of the bit length tree).
2369 */
2370 tree[heap[heap_max]].Len = 0; /* root of the heap */
2371
2372 for (h = heap_max+1; h < HEAP_SIZE; h++) {
2373 n = heap[h];
2374 bits = tree[tree[n].Dad].Len + 1;
2375 if (bits > max_length) bits = max_length, overflow++;
2376 tree[n].Len = (ush)bits;
2377 /* We overwrite tree[n].Dad which is no longer needed */
2378
2379 if (n > max_code) continue; /* not a leaf node */
2380
2381 bl_count[bits]++;
2382 xbits = 0;
2383 if (n >= base) xbits = extra[n-base];
2384 f = tree[n].Freq;
2385 opt_len += (ulg)f * (bits + xbits);
2386 if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
2387 }
2388 if (overflow == 0) return;
2389
2390 Trace((stderr,"\nbit length overflow\n"));
2391 /* This happens for example on obj2 and pic of the Calgary corpus */
2392
2393 /* Find the first bit length which could increase: */
2394 do {
2395 bits = max_length-1;
2396 while (bl_count[bits] == 0) bits--;
2397 bl_count[bits]--; /* move one leaf down the tree */
2398 bl_count[bits+1] += 2; /* move one overflow item as its brother */
2399 bl_count[max_length]--;
2400 /* The brother of the overflow item also moves one step up,
2401 * but this does not affect bl_count[max_length]
2402 */
2403 overflow -= 2;
2404 } while (overflow > 0);
2405
2406 /* Now recompute all bit lengths, scanning in increasing frequency.
2407 * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
2408 * lengths instead of fixing only the wrong ones. This idea is taken
2409 * from 'ar' written by Haruhiko Okumura.)
2410 */
2411 for (bits = max_length; bits != 0; bits--) {
2412 n = bl_count[bits];
2413 while (n != 0) {
2414 m = heap[--h];
2415 if (m > max_code) continue;
2416 if (tree[m].Len != (unsigned) bits) {
2417 Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
2418 opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
2419 tree[m].Len = (ush)bits;
2420 }
2421 n--;
2422 }
2423 }
2424}
2425
2426/* ===========================================================================
2427 * Generate the codes for a given tree and bit counts (which need not be
2428 * optimal).
2429 * IN assertion: the array bl_count contains the bit length statistics for
2430 * the given tree and the field len is set for all tree elements.
2431 * OUT assertion: the field code is set for all tree elements of non
2432 * zero code length.
2433 */
2434local void gen_codes (tree, max_code)
2435 ct_data near *tree; /* the tree to decorate */
2436 int max_code; /* largest code with non zero frequency */
2437{
2438 ush next_code[MAX_BITS+1]; /* next code value for each bit length */
2439 ush code = 0; /* running code value */
2440 int bits; /* bit index */
2441 int n; /* code index */
2442
2443 /* The distribution counts are first used to generate the code values
2444 * without bit reversal.
2445 */
2446 for (bits = 1; bits <= MAX_BITS; bits++) {
2447 next_code[bits] = code = (code + bl_count[bits-1]) << 1;
2448 }
2449 /* Check that the bit counts in bl_count are consistent. The last code
2450 * must be all ones.
2451 */
2452 Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
2453 "inconsistent bit counts");
2454 Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
2455
2456 for (n = 0; n <= max_code; n++) {
2457 int len = tree[n].Len;
2458 if (len == 0) continue;
2459 /* Now reverse the bits */
2460 tree[n].Code = bi_reverse(next_code[len]++, len);
2461
2462 Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
2463 n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
2464 }
2465}
2466
2467/* ===========================================================================
2468 * Construct one Huffman tree and assigns the code bit strings and lengths.
2469 * Update the total bit length for the current block.
2470 * IN assertion: the field freq is set for all tree elements.
2471 * OUT assertions: the fields len and code are set to the optimal bit length
2472 * and corresponding code. The length opt_len is updated; static_len is
2473 * also updated if stree is not null. The field max_code is set.
2474 */
2475local void build_tree(desc)
2476 tree_desc near *desc; /* the tree descriptor */
2477{
2478 ct_data near *tree = desc->dyn_tree;
2479 ct_data near *stree = desc->static_tree;
2480 int elems = desc->elems;
2481 int n, m; /* iterate over heap elements */
2482 int max_code = -1; /* largest code with non zero frequency */
2483 int node = elems; /* next internal node of the tree */
2484
2485 /* Construct the initial heap, with least frequent element in
2486 * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
2487 * heap[0] is not used.
2488 */
2489 heap_len = 0, heap_max = HEAP_SIZE;
2490
2491 for (n = 0; n < elems; n++) {
2492 if (tree[n].Freq != 0) {
2493 heap[++heap_len] = max_code = n;
2494 depth[n] = 0;
2495 } else {
2496 tree[n].Len = 0;
2497 }
2498 }
2499
2500 /* The pkzip format requires that at least one distance code exists,
2501 * and that at least one bit should be sent even if there is only one
2502 * possible code. So to avoid special checks later on we force at least
2503 * two codes of non zero frequency.
2504 */
2505 while (heap_len < 2) {
2506 int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
2507 tree[new].Freq = 1;
2508 depth[new] = 0;
2509 opt_len--; if (stree) static_len -= stree[new].Len;
2510 /* new is 0 or 1 so it does not have extra bits */
2511 }
2512 desc->max_code = max_code;
2513
2514 /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
2515 * establish sub-heaps of increasing lengths:
2516 */
2517 for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
2518
2519 /* Construct the Huffman tree by repeatedly combining the least two
2520 * frequent nodes.
2521 */
2522 do {
2523 pqremove(tree, n); /* n = node of least frequency */
2524 m = heap[SMALLEST]; /* m = node of next least frequency */
2525
2526 heap[--heap_max] = n; /* keep the nodes sorted by frequency */
2527 heap[--heap_max] = m;
2528
2529 /* Create a new node father of n and m */
2530 tree[node].Freq = tree[n].Freq + tree[m].Freq;
2531 depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
2532 tree[n].Dad = tree[m].Dad = (ush)node;
2533#ifdef DUMP_BL_TREE
2534 if (tree == bl_tree) {
2535 fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
2536 node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
2537 }
2538#endif
2539 /* and insert the new node in the heap */
2540 heap[SMALLEST] = node++;
2541 pqdownheap(tree, SMALLEST);
2542
2543 } while (heap_len >= 2);
2544
2545 heap[--heap_max] = heap[SMALLEST];
2546
2547 /* At this point, the fields freq and dad are set. We can now
2548 * generate the bit lengths.
2549 */
2550 gen_bitlen((tree_desc near *)desc);
2551
2552 /* The field len is now set, we can generate the bit codes */
2553 gen_codes ((ct_data near *)tree, max_code);
2554}
2555
2556/* ===========================================================================
2557 * Scan a literal or distance tree to determine the frequencies of the codes
2558 * in the bit length tree. Updates opt_len to take into account the repeat
2559 * counts. (The contribution of the bit length codes will be added later
2560 * during the construction of bl_tree.)
2561 */
2562local void scan_tree (tree, max_code)
2563 ct_data near *tree; /* the tree to be scanned */
2564 int max_code; /* and its largest code of non zero frequency */
2565{
2566 int n; /* iterates over all tree elements */
2567 int prevlen = -1; /* last emitted length */
2568 int curlen; /* length of current code */
2569 int nextlen = tree[0].Len; /* length of next code */
2570 int count = 0; /* repeat count of the current code */
2571 int max_count = 7; /* max repeat count */
2572 int min_count = 4; /* min repeat count */
2573
2574 if (nextlen == 0) max_count = 138, min_count = 3;
2575 tree[max_code+1].Len = (ush)0xffff; /* guard */
2576
2577 for (n = 0; n <= max_code; n++) {
2578 curlen = nextlen; nextlen = tree[n+1].Len;
2579 if (++count < max_count && curlen == nextlen) {
2580 continue;
2581 } else if (count < min_count) {
2582 bl_tree[curlen].Freq += count;
2583 } else if (curlen != 0) {
2584 if (curlen != prevlen) bl_tree[curlen].Freq++;
2585 bl_tree[REP_3_6].Freq++;
2586 } else if (count <= 10) {
2587 bl_tree[REPZ_3_10].Freq++;
2588 } else {
2589 bl_tree[REPZ_11_138].Freq++;
2590 }
2591 count = 0; prevlen = curlen;
2592 if (nextlen == 0) {
2593 max_count = 138, min_count = 3;
2594 } else if (curlen == nextlen) {
2595 max_count = 6, min_count = 3;
2596 } else {
2597 max_count = 7, min_count = 4;
2598 }
2599 }
2600}
2601
2602/* ===========================================================================
2603 * Send a literal or distance tree in compressed form, using the codes in
2604 * bl_tree.
2605 */
2606local void send_tree (tree, max_code)
2607 ct_data near *tree; /* the tree to be scanned */
2608 int max_code; /* and its largest code of non zero frequency */
2609{
2610 int n; /* iterates over all tree elements */
2611 int prevlen = -1; /* last emitted length */
2612 int curlen; /* length of current code */
2613 int nextlen = tree[0].Len; /* length of next code */
2614 int count = 0; /* repeat count of the current code */
2615 int max_count = 7; /* max repeat count */
2616 int min_count = 4; /* min repeat count */
2617
2618 /* tree[max_code+1].Len = -1; */ /* guard already set */
2619 if (nextlen == 0) max_count = 138, min_count = 3;
2620
2621 for (n = 0; n <= max_code; n++) {
2622 curlen = nextlen; nextlen = tree[n+1].Len;
2623 if (++count < max_count && curlen == nextlen) {
2624 continue;
2625 } else if (count < min_count) {
2626 do { send_code(curlen, bl_tree); } while (--count != 0);
2627
2628 } else if (curlen != 0) {
2629 if (curlen != prevlen) {
2630 send_code(curlen, bl_tree); count--;
2631 }
2632 Assert(count >= 3 && count <= 6, " 3_6?");
2633 send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
2634
2635 } else if (count <= 10) {
2636 send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
2637
2638 } else {
2639 send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
2640 }
2641 count = 0; prevlen = curlen;
2642 if (nextlen == 0) {
2643 max_count = 138, min_count = 3;
2644 } else if (curlen == nextlen) {
2645 max_count = 6, min_count = 3;
2646 } else {
2647 max_count = 7, min_count = 4;
2648 }
2649 }
2650}
2651
2652/* ===========================================================================
2653 * Construct the Huffman tree for the bit lengths and return the index in
2654 * bl_order of the last bit length code to send.
2655 */
2656local int build_bl_tree()
2657{
2658 int max_blindex; /* index of last bit length code of non zero freq */
2659
2660 /* Determine the bit length frequencies for literal and distance trees */
2661 scan_tree((ct_data near *)dyn_ltree, l_desc.max_code);
2662 scan_tree((ct_data near *)dyn_dtree, d_desc.max_code);
2663
2664 /* Build the bit length tree: */
2665 build_tree((tree_desc near *)(&bl_desc));
2666 /* opt_len now includes the length of the tree representations, except
2667 * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
2668 */
2669
2670 /* Determine the number of bit length codes to send. The pkzip format
2671 * requires that at least 4 bit length codes be sent. (appnote.txt says
2672 * 3 but the actual value used is 4.)
2673 */
2674 for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
2675 if (bl_tree[bl_order[max_blindex]].Len != 0) break;
2676 }
2677 /* Update opt_len to include the bit length tree and counts */
2678 opt_len += 3*(max_blindex+1) + 5+5+4;
2679 Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
2680
2681 return max_blindex;
2682}
2683
2684/* ===========================================================================
2685 * Send the header for a block using dynamic Huffman trees: the counts, the
2686 * lengths of the bit length codes, the literal tree and the distance tree.
2687 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
2688 */
2689local void send_all_trees(lcodes, dcodes, blcodes)
2690 int lcodes, dcodes, blcodes; /* number of codes for each tree */
2691{
2692 int rank; /* index in bl_order */
2693
2694 Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
2695 Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
2696 "too many codes");
2697 Tracev((stderr, "\nbl counts: "));
2698 send_bits(lcodes-257, 5); /* not +255 as stated in appnote.txt */
2699 send_bits(dcodes-1, 5);
2700 send_bits(blcodes-4, 4); /* not -3 as stated in appnote.txt */
2701 for (rank = 0; rank < blcodes; rank++) {
2702 Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
2703 send_bits(bl_tree[bl_order[rank]].Len, 3);
2704 }
2705 Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
2706
2707 send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */
2708 Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
2709
2710 send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */
2711 Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
2712}
2713
2714/* ===========================================================================
2715 * Determine the best encoding for the current block: dynamic trees, static
2716 * trees or store, and output the encoded block to the zip file. This function
2717 * returns the total compressed length for the file so far.
2718 */
2719ulg flush_block(buf, stored_len, eof)
2720 char *buf; /* input block, or NULL if too old */
2721 ulg stored_len; /* length of input block */
2722 int eof; /* true if this is the last block for a file */
2723{
2724 ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
2725 int max_blindex; /* index of last bit length code of non zero freq */
2726
2727 flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
2728
2729 /* Check if the file is ascii or binary */
2730 if (*file_type == (ush)UNKNOWN) set_file_type();
2731
2732 /* Construct the literal and distance trees */
2733 build_tree((tree_desc near *)(&l_desc));
2734 Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
2735
2736 build_tree((tree_desc near *)(&d_desc));
2737 Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
2738 /* At this point, opt_len and static_len are the total bit lengths of
2739 * the compressed block data, excluding the tree representations.
2740 */
2741
2742 /* Build the bit length tree for the above two trees, and get the index
2743 * in bl_order of the last bit length code to send.
2744 */
2745 max_blindex = build_bl_tree();
2746
2747 /* Determine the best encoding. Compute first the block length in bytes */
2748 opt_lenb = (opt_len+3+7)>>3;
2749 static_lenb = (static_len+3+7)>>3;
2750 input_len += stored_len; /* for debugging only */
2751
2752 Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
2753 opt_lenb, opt_len, static_lenb, static_len, stored_len,
2754 last_lit, last_dist));
2755
2756 if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
2757
2758 /* If compression failed and this is the first and last block,
2759 * and if the zip file can be seeked (to rewrite the local header),
2760 * the whole file is transformed into a stored file:
2761 */
2762#ifdef FORCE_METHOD
2763#else
2764 if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
2765#endif
2766 /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
2767 if (buf == (char*)0) error ("block vanished");
2768
2769 copy_block(buf, (unsigned)stored_len, 0); /* without header */
2770 compressed_len = stored_len << 3;
2771 *file_method = STORED;
2772
2773#ifdef FORCE_METHOD
2774#else
2775 } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
2776 /* 4: two words for the lengths */
2777#endif
2778 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
2779 * Otherwise we can't have processed more than WSIZE input bytes since
2780 * the last block flush, because compression would have been
2781 * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
2782 * transform a block into a stored block.
2783 */
2784 send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
2785 compressed_len = (compressed_len + 3 + 7) & ~7L;
2786 compressed_len += (stored_len + 4) << 3;
2787
2788 copy_block(buf, (unsigned)stored_len, 1); /* with header */
2789
2790#ifdef FORCE_METHOD
2791#else
2792 } else if (static_lenb == opt_lenb) {
2793#endif
2794 send_bits((STATIC_TREES<<1)+eof, 3);
2795 compress_block((ct_data near *)static_ltree, (ct_data near *)static_dtree);
2796 compressed_len += 3 + static_len;
2797 } else {
2798 send_bits((DYN_TREES<<1)+eof, 3);
2799 send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
2800 compress_block((ct_data near *)dyn_ltree, (ct_data near *)dyn_dtree);
2801 compressed_len += 3 + opt_len;
2802 }
2803 Assert (compressed_len == bits_sent, "bad compressed size");
2804 init_block();
2805
2806 if (eof) {
2807 Assert (input_len == isize, "bad input size");
2808 bi_windup();
2809 compressed_len += 7; /* align on byte boundary */
2810 }
2811 Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
2812 compressed_len-7*eof));
2813
2814 return compressed_len >> 3;
2815}
2816
2817/* ===========================================================================
2818 * Save the match info and tally the frequency counts. Return true if
2819 * the current block must be flushed.
2820 */
2821int ct_tally (dist, lc)
2822 int dist; /* distance of matched string */
2823 int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
2824{
2825 l_buf[last_lit++] = (uch)lc;
2826 if (dist == 0) {
2827 /* lc is the unmatched char */
2828 dyn_ltree[lc].Freq++;
2829 } else {
2830 /* Here, lc is the match length - MIN_MATCH */
2831 dist--; /* dist = match distance - 1 */
2832 Assert((ush)dist < (ush)MAX_DIST &&
2833 (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
2834 (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
2835
2836 dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
2837 dyn_dtree[d_code(dist)].Freq++;
2838
2839 d_buf[last_dist++] = (ush)dist;
2840 flags |= flag_bit;
2841 }
2842 flag_bit <<= 1;
2843
2844 /* Output the flags if they fill a byte: */
2845 if ((last_lit & 7) == 0) {
2846 flag_buf[last_flags++] = flags;
2847 flags = 0, flag_bit = 1;
2848 }
2849 /* Try to guess if it is profitable to stop the current block here */
2850 if ((last_lit & 0xfff) == 0) {
2851 /* Compute an upper bound for the compressed length */
2852 ulg out_length = (ulg)last_lit*8L;
2853 ulg in_length = (ulg)strstart-block_start;
2854 int dcode;
2855 for (dcode = 0; dcode < D_CODES; dcode++) {
2856 out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
2857 }
2858 out_length >>= 3;
2859 Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
2860 last_lit, last_dist, in_length, out_length,
2861 100L - out_length*100L/in_length));
2862 if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
2863 }
2864 return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
2865 /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
2866 * on 16 bit machines and because stored blocks are restricted to
2867 * 64K-1 bytes.
2868 */
2869}
2870
2871/* ===========================================================================
2872 * Send the block data compressed using the given Huffman trees
2873 */
2874local void compress_block(ltree, dtree)
2875 ct_data near *ltree; /* literal tree */
2876 ct_data near *dtree; /* distance tree */
2877{
2878 unsigned dist; /* distance of matched string */
2879 int lc; /* match length or unmatched char (if dist == 0) */
2880 unsigned lx = 0; /* running index in l_buf */
2881 unsigned dx = 0; /* running index in d_buf */
2882 unsigned fx = 0; /* running index in flag_buf */
2883 uch flag = 0; /* current flags */
2884 unsigned code; /* the code to send */
2885 int extra; /* number of extra bits to send */
2886
2887 if (last_lit != 0) do {
2888 if ((lx & 7) == 0) flag = flag_buf[fx++];
2889 lc = l_buf[lx++];
2890 if ((flag & 1) == 0) {
2891 send_code(lc, ltree); /* send a literal byte */
2892 Tracecv(isgraph(lc), (stderr," '%c' ", lc));
2893 } else {
2894 /* Here, lc is the match length - MIN_MATCH */
2895 code = length_code[lc];
2896 send_code(code+LITERALS+1, ltree); /* send the length code */
2897 extra = extra_lbits[code];
2898 if (extra != 0) {
2899 lc -= base_length[code];
2900 send_bits(lc, extra); /* send the extra length bits */
2901 }
2902 dist = d_buf[dx++];
2903 /* Here, dist is the match distance - 1 */
2904 code = d_code(dist);
2905 Assert (code < D_CODES, "bad d_code");
2906
2907 send_code(code, dtree); /* send the distance code */
2908 extra = extra_dbits[code];
2909 if (extra != 0) {
2910 dist -= base_dist[code];
2911 send_bits(dist, extra); /* send the extra distance bits */
2912 }
2913 } /* literal or match pair ? */
2914 flag >>= 1;
2915 } while (lx < last_lit);
2916
2917 send_code(END_BLOCK, ltree);
2918}
2919
2920/* ===========================================================================
2921 * Set the file type to ASCII or BINARY, using a crude approximation:
2922 * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
2923 * IN assertion: the fields freq of dyn_ltree are set and the total of all
2924 * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
2925 */
2926local void set_file_type()
2927{
2928 int n = 0;
2929 unsigned ascii_freq = 0;
2930 unsigned bin_freq = 0;
2931 while (n < 7) bin_freq += dyn_ltree[n++].Freq;
2932 while (n < 128) ascii_freq += dyn_ltree[n++].Freq;
2933 while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
2934 *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
2935 if (*file_type == BINARY && translate_eol) {
2936 warn("-l used on binary file", "");
2937 }
2938}
2939/* util.c -- utility functions for gzip support
2940 * Copyright (C) 1992-1993 Jean-loup Gailly
2941 * This is free software; you can redistribute it and/or modify it under the
2942 * terms of the GNU General Public License, see the file COPYING.
2943 */
2944
2945#ifdef RCSID
2946static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
2947#endif
2948
2949#include <ctype.h>
2950#include <errno.h>
2951#include <sys/types.h>
2952
2953#ifdef HAVE_UNISTD_H
2954# include <unistd.h>
2955#endif
2956#ifndef NO_FCNTL_H
2957# include <fcntl.h>
2958#endif
2959
2960#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
2961# include <stdlib.h>
2962#else
2963 extern int errno;
2964#endif
2965
2966extern ulg crc_32_tab[]; /* crc table, defined below */
2967
2968/* ===========================================================================
2969 * Copy input to output unchanged: zcat == cat with --force.
2970 * IN assertion: insize bytes have already been read in inbuf.
2971 */
2972int copy(in, out)
2973 int in, out; /* input and output file descriptors */
2974{
2975 errno = 0;
2976 while (insize != 0 && (int)insize != EOF) {
2977 write_buf(out, (char*)inbuf, insize);
2978 bytes_out += insize;
2979 insize = read(in, (char*)inbuf, INBUFSIZ);
2980 }
2981 if ((int)insize == EOF && errno != 0) {
2982 read_error();
2983 }
2984 bytes_in = bytes_out;
2985 return OK;
2986}
2987
2988/* ========================================================================
2989 * Put string s in lower case, return s.
2990 */
2991char *strlwr(s)
2992 char *s;
2993{
2994 char *t;
2995 for (t = s; *t; t++) *t = tolow(*t);
2996 return s;
2997}
2998
2999#if defined(NO_STRING_H) && !defined(STDC_HEADERS)
3000
3001/* Provide missing strspn and strcspn functions. */
3002
3003# ifndef __STDC__
3004# define const
3005# endif
3006
3007int strspn OF((const char *s, const char *accept));
3008int strcspn OF((const char *s, const char *reject));
3009
3010/* ========================================================================
3011 * Return the length of the maximum initial segment
3012 * of s which contains only characters in accept.
3013 */
3014int strspn(s, accept)
3015 const char *s;
3016 const char *accept;
3017{
3018 register const char *p;
3019 register const char *a;
3020 register int count = 0;
3021
3022 for (p = s; *p != '\0'; ++p) {
3023 for (a = accept; *a != '\0'; ++a) {
3024 if (*p == *a) break;
3025 }
3026 if (*a == '\0') return count;
3027 ++count;
3028 }
3029 return count;
3030}
3031
3032/* ========================================================================
3033 * Return the length of the maximum inital segment of s
3034 * which contains no characters from reject.
3035 */
3036int strcspn(s, reject)
3037 const char *s;
3038 const char *reject;
3039{
3040 register int count = 0;
3041
3042 while (*s != '\0') {
3043 if (strchr(reject, *s++) != NULL) return count;
3044 ++count;
3045 }
3046 return count;
3047}
3048
3049#endif /* NO_STRING_H */
3050
3051/* ========================================================================
3052 * Add an environment variable (if any) before argv, and update argc.
3053 * Return the expanded environment variable to be freed later, or NULL
3054 * if no options were added to argv.
3055 */
3056#define SEPARATOR " \t" /* separators in env variable */
3057
3058char *add_envopt(argcp, argvp, env)
3059 int *argcp; /* pointer to argc */
3060 char ***argvp; /* pointer to argv */
3061 char *env; /* name of environment variable */
3062{
3063 char *p; /* running pointer through env variable */
3064 char **oargv; /* runs through old argv array */
3065 char **nargv; /* runs through new argv array */
3066 int oargc = *argcp; /* old argc */
3067 int nargc = 0; /* number of arguments in env variable */
3068
3069 env = (char*)getenv(env);
3070 if (env == NULL) return NULL;
3071
3072 p = (char*)xmalloc(strlen(env)+1);
3073 env = strcpy(p, env); /* keep env variable intact */
3074
3075 for (p = env; *p; nargc++ ) { /* move through env */
3076 p += strspn(p, SEPARATOR); /* skip leading separators */
3077 if (*p == '\0') break;
3078
3079 p += strcspn(p, SEPARATOR); /* find end of word */
3080 if (*p) *p++ = '\0'; /* mark it */
3081 }
3082 if (nargc == 0) {
3083 free(env);
3084 return NULL;
3085 }
3086 *argcp += nargc;
3087 /* Allocate the new argv array, with an extra element just in case
3088 * the original arg list did not end with a NULL.
3089 */
3090 nargv = (char**)calloc(*argcp+1, sizeof(char *));
3091 if (nargv == NULL) error("out of memory");
3092 oargv = *argvp;
3093 *argvp = nargv;
3094
3095 /* Copy the program name first */
3096 if (oargc-- < 0) error("argc<=0");
3097 *(nargv++) = *(oargv++);
3098
3099 /* Then copy the environment args */
3100 for (p = env; nargc > 0; nargc--) {
3101 p += strspn(p, SEPARATOR); /* skip separators */
3102 *(nargv++) = p; /* store start */
3103 while (*p++) ; /* skip over word */
3104 }
3105
3106 /* Finally copy the old args and add a NULL (usual convention) */
3107 while (oargc--) *(nargv++) = *(oargv++);
3108 *nargv = NULL;
3109 return env;
3110}
3111/* ========================================================================
3112 * Display compression ratio on the given stream on 6 characters.
3113 */
3114void display_ratio(num, den, file)
3115 long num;
3116 long den;
3117 FILE *file;
3118{
3119 long ratio; /* 1000 times the compression ratio */
3120
3121 if (den == 0) {
3122 ratio = 0; /* no compression */
3123 } else if (den < 2147483L) { /* (2**31 -1)/1000 */
3124 ratio = 1000L*num/den;
3125 } else {
3126 ratio = num/(den/1000L);
3127 }
3128 if (ratio < 0) {
3129 putc('-', file);
3130 ratio = -ratio;
3131 } else {
3132 putc(' ', file);
3133 }
3134 fprintf(file, "%2ld.%1ld%%", ratio / 10L, ratio % 10L);
3135}
3136
3137
3138/* zip.c -- compress files to the gzip or pkzip format
3139 * Copyright (C) 1992-1993 Jean-loup Gailly
3140 * This is free software; you can redistribute it and/or modify it under the
3141 * terms of the GNU General Public License, see the file COPYING.
3142 */
3143
3144#ifdef RCSID
3145static char rcsid[] = "$Id: gzip.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
3146#endif
3147
3148#include <ctype.h>
3149#include <sys/types.h>
3150
3151#ifdef HAVE_UNISTD_H
3152# include <unistd.h>
3153#endif
3154#ifndef NO_FCNTL_H
3155# include <fcntl.h>
3156#endif
3157
3158local ulg crc; /* crc on uncompressed file data */
3159long header_bytes; /* number of bytes in gzip header */
3160
3161/* ===========================================================================
3162 * Deflate in to out.
3163 * IN assertions: the input and output buffers are cleared.
3164 * The variables time_stamp and save_orig_name are initialized.
3165 */
3166int zip(in, out)
3167 int in, out; /* input and output file descriptors */
3168{
3169 uch flags = 0; /* general purpose bit flags */
3170 ush attr = 0; /* ascii/binary flag */
3171 ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
3172
3173 ifd = in;
3174 ofd = out;
3175 outcnt = 0;
3176
3177 /* Write the header to the gzip file. See algorithm.doc for the format */
3178
3179 method = DEFLATED;
3180 put_byte(GZIP_MAGIC[0]); /* magic header */
3181 put_byte(GZIP_MAGIC[1]);
3182 put_byte(DEFLATED); /* compression method */
3183
3184 put_byte(flags); /* general flags */
3185 put_long(time_stamp);
3186
3187 /* Write deflated file to zip file */
3188 crc = updcrc(0, 0);
3189
3190 bi_init(out);
3191 ct_init(&attr, &method);
3192 lm_init(&deflate_flags);
3193
3194 put_byte((uch)deflate_flags); /* extra flags */
3195 put_byte(OS_CODE); /* OS identifier */
3196
3197 header_bytes = (long)outcnt;
3198
3199 (void)deflate();
3200
3201 /* Write the crc and uncompressed size */
3202 put_long(crc);
3203 put_long(isize);
3204 header_bytes += 2*sizeof(long);
3205
3206 flush_outbuf();
3207 return OK;
3208}
3209
3210
3211/* ===========================================================================
3212 * Read a new buffer from the current input file, perform end-of-line
3213 * translation, and update the crc and input file size.
3214 * IN assertion: size >= 2 (for end-of-line translation)
3215 */
3216int file_read(buf, size)
3217 char *buf;
3218 unsigned size;
3219{
3220 unsigned len;
3221
3222 Assert(insize == 0, "inbuf not empty");
3223
3224 len = read(ifd, buf, size);
3225 if (len == (unsigned)(-1) || len == 0) return (int)len;
3226
3227 crc = updcrc((uch*)buf, len);
3228 isize += (ulg)len;
3229 return (int)len;
3230}
3231#endif
diff --git a/halt.c b/halt.c
new file mode 100644
index 000000000..7f3ccf966
--- /dev/null
+++ b/halt.c
@@ -0,0 +1,12 @@
1#include "internal.h"
2#include <signal.h>
3
4const char halt_usage[] = "halt\n"
5"\n\t"
6"\thalt the system.\n";
7
8extern int
9halt_main(struct FileInfo * i, int argc, char * * argv)
10{
11 return kill(1, SIGUSR1);
12}
diff --git a/init.c b/init.c
new file mode 100644
index 000000000..4771722b9
--- /dev/null
+++ b/init.c
@@ -0,0 +1,438 @@
1#include "internal.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <stdarg.h>
5#include <unistd.h>
6#include <errno.h>
7#include <signal.h>
8#include <termios.h>
9#include <sys/types.h>
10#include <sys/fcntl.h>
11#include <sys/wait.h>
12#include <string.h>
13#include <sys/mount.h>
14#include <sys/reboot.h>
15#include <sys/kdaemon.h>
16#include <sys/swap.h>
17#include <sys/sysmacros.h>
18
19const char init_usage[] = "Used internally by the system.";
20char console[16] = "";
21const char * default_console = "/dev/tty1";
22char * first_terminal = NULL;
23const char * second_terminal = "/dev/tty2";
24const char log[] = "/dev/tty3";
25char * term_ptr = NULL;
26
27static void
28message(const char * terminal, const char * pattern, ...)
29{
30 int fd;
31 FILE * con = 0;
32 va_list arguments;
33
34 /*
35 * Open the console device each time a message is printed. If the user
36 * has switched consoles, the open will get the new console. If we kept
37 * the console open, we'd always print to the same one.
38 */
39 if ( ((fd = open(terminal, O_WRONLY|O_NOCTTY)) < 0)
40 || ((con = fdopen(fd, "w")) == NULL) )
41 return;
42
43 va_start(arguments, pattern);
44 vfprintf(con, pattern, arguments);
45 va_end(arguments);
46 fclose(con);
47}
48
49static int
50waitfor(int pid)
51{
52 int status;
53 int wpid;
54
55 message(log, "Waiting for process %d.\n", pid);
56 while ( (wpid = wait(&status)) != pid ) {
57 if ( wpid > 0 ) {
58 message(
59 log
60 ,"pid %d exited, status=%x.\n"
61 ,wpid
62 ,status);
63 }
64 }
65 return wpid;
66}
67
68static int
69run(
70 const char * program
71,const char * const * arguments
72,const char * terminal
73,int get_enter)
74{
75 static const char control_characters[] = {
76 '\003',
77 '\034',
78 '\177',
79 '\025',
80 '\004',
81 '\0',
82 '\1',
83 '\0',
84 '\021',
85 '\023',
86 '\032',
87 '\0',
88 '\022',
89 '\017',
90 '\027',
91 '\026',
92 '\0'
93 };
94
95 static char * environment[] = {
96 "HOME=/",
97 "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
98 "SHELL=/bin/sh",
99 0,
100 "USER=root",
101 0
102 };
103
104 static const char press_enter[] =
105 "Please press Enter to activate this console. ";
106
107 int pid;
108
109 environment[3]=term_ptr;
110
111 pid = fork();
112 if ( pid == 0 ) {
113 struct termios t;
114 const char * const * arg;
115
116 close(0);
117 close(1);
118 close(2);
119 setsid();
120
121 open(terminal, O_RDWR);
122 dup(0);
123 dup(0);
124 tcsetpgrp(0, getpgrp());
125
126 tcgetattr(0, &t);
127 memcpy(t.c_cc, control_characters, sizeof(control_characters));
128 t.c_line = 0;
129 t.c_iflag = ICRNL|IXON|IXOFF;
130 t.c_oflag = OPOST|ONLCR;
131 t.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
132 tcsetattr(0, TCSANOW, &t);
133
134 if ( get_enter ) {
135 /*
136 * Save memory by not exec-ing anything large (like a shell)
137 * before the user wants it. This is critical if swap is not
138 * enabled and the system has low memory. Generally this will
139 * be run on the second virtual console, and the first will
140 * be allowed to start a shell or the installation system.
141 */
142 char c;
143 write(1, press_enter, sizeof(press_enter) - 1);
144 read(0, &c, 1);
145 }
146
147 message(log, "Executing ");
148 arg = arguments;
149 while ( *arg != 0 )
150 message(log, "%s ", *arg++);
151 message(log, "\n");
152
153 execve(program, (char * *)arguments, (char * *)environment);
154 message(log, "%s: could not execute: %s.\r\n", program, strerror(errno));
155 exit(-1);
156 }
157 return pid;
158}
159
160static int
161mem_total()
162{
163 char s[80];
164 char *p;
165 FILE *f;
166 const char pattern[]="MemTotal:";
167
168 f=fopen("/proc/meminfo","r");
169 while (NULL != fgets(s,79,f)) {
170 p=strstr(s, pattern);
171 if (NULL != p) {
172 fclose(f);
173 return(atoi(p+strlen(pattern)));
174 }
175 }
176 return -1;
177}
178
179static void
180set_free_pages()
181{
182 char s[80];
183 FILE *f;
184
185 f=fopen("/proc/sys/vm/freepages","r");
186 fgets(s,79,f);
187 if (atoi(s) < 32) {
188 fclose(f);
189 f=fopen("/proc/sys/vm/freepages","w");
190 fprintf(f,"30\t40\t50\n");
191 printf("\nIncreased /proc/sys/vm/freepages values to 30/40/50\n");
192 }
193 fclose(f);
194}
195
196static void
197shutdown_system(int do_reboot)
198{
199 static const char * const umount_args[] = {"/bin/umount", "-a", "-n", 0};
200
201 sync();
202 /* Allow Ctrl-Alt-Del to reboot system. */
203 reboot(RB_ENABLE_CAD);
204
205 /* Send signals to every process _except_ pid 1 */
206 message(console, "Sending SIGHUP to all processes.\r\n");
207 kill(-1, SIGHUP);
208 sleep(2);
209 sync();
210 message(console, "Sending SIGKILL to all processes.\r\n");
211 kill(-1, SIGKILL);
212 sleep(1);
213 waitfor(run("/bin/umount", umount_args, console, 0));
214 sync();
215 bdflush(1, 0);
216 sync();
217 reboot(do_reboot ?RB_AUTOBOOT : RB_HALT_SYSTEM);
218 exit(0);
219}
220
221static void
222halt_signal(int sig)
223{
224 shutdown_system(0);
225}
226
227static void
228reboot_signal(int sig)
229{
230 shutdown_system(1);
231}
232
233static void
234exit_signal(int sig)
235{
236
237 /* initrd doesn't work anyway */
238
239 shutdown_system(1);
240
241 /* This is used on the initial ramdisk */
242
243 /* message(log, "Init exiting.");
244 exit(0);
245 */
246}
247
248void
249configure_terminals( int serial_cons );
250
251extern int
252init_main(struct FileInfo * i, int argc, char * * argv)
253{
254 static const char * const rc = "etc/rc";
255 const char * arguments[100];
256 int run_rc = 1;
257 int j;
258 int pid1 = 0;
259 int pid2 = 0;
260 int create_swap= -1;
261 struct stat statbuf;
262#ifndef INCLUDE_DINSTALL
263 const char * tty_commands[2] = { "bin/sh", "bin/sh"};
264#else
265 const char * tty_commands[2] = { "sbin/dinstall", "bin/sh"};
266#endif
267 char swap[20];
268 int serial_console = 0;
269
270 /*
271 * If I am started as /linuxrc instead of /sbin/init, I don't have the
272 * environment that init expects. I can't fix the signal behavior. Try
273 * to divorce from the controlling terminal with setsid(). This won't work
274 * if I am the process group leader.
275 */
276 setsid();
277
278 signal(SIGUSR1, halt_signal);
279 signal(SIGUSR2, reboot_signal);
280 signal(SIGINT, reboot_signal);
281 signal(SIGTERM, exit_signal);
282
283 reboot(RB_DISABLE_CAD);
284
285 message(log, "%s: started. ", argv[0]);
286
287 for ( j = 1; j < argc; j++ ) {
288 if ( strcmp(argv[j], "single") == 0 ) {
289 run_rc = 0;
290 tty_commands[0] = "bin/sh";
291 tty_commands[1] = 0;
292 }
293 }
294 for ( j = 0; __environ[j] != 0; j++ ) {
295 if ( strncmp(__environ[j], "tty", 3) == 0
296 && __environ[j][3] >= '1'
297 && __environ[j][3] <= '2'
298 && __environ[j][4] == '=' ) {
299 const char * s = &__environ[j][5];
300
301 if ( *s == 0 || strcmp(s, "off") == 0 )
302 s = 0;
303
304 tty_commands[__environ[j][3] - '1'] = s;
305 }
306 /* Should catch the syntax of Sparc kernel console setting. */
307 /* The kernel does not recognize a serial console when getting*/
308 /* console=/dev/ttySX !! */
309 else if ( strcmp(__environ[j], "console=ttya") == 0 ) {
310 serial_console=1;
311 }
312 else if ( strcmp(__environ[j], "console=ttyb") == 0 ) {
313 serial_console=2;
314 }
315 /* standard console settings */
316 else if ( strncmp(__environ[j], "console=", 8) == 0 ) {
317 first_terminal=&(__environ[j][8]);
318 }
319 else if ( strncmp(__environ[j], "TERM=", 5) == 0) {
320 term_ptr=__environ[j];
321 }
322 }
323 configure_terminals( serial_console );
324
325 printf("mounting /proc ...\n");
326 if (mount("/proc","/proc","proc",0,0)) {
327 perror("mounting /proc failed\n");
328 }
329 printf("\tdone.\n");
330
331 set_free_pages();
332
333 if (mem_total() < 3500) { /* not enough memory for standard install */
334 int retval;
335 retval= stat("/etc/swappartition",&statbuf);
336 if (retval) {
337 printf("
338You do not have enough RAM, hence you must boot using the Boot Disk
339for Low Memory systems.
340
341Read the instructions in the install.html file.
342");
343 while (1) {;}
344 } else { /* everything OK */
345 FILE *f;
346
347 f=fopen("/etc/swappartition","r");
348 fgets(swap,19,f);
349 fclose(f);
350 *(strstr(swap,"\n"))='\0';
351
352 if (swapon(swap,0)) {
353 perror("swapon failed\n");
354 } else {
355 f=fopen("/etc/swaps","w");
356 fprintf(f,"%s none swap rw 0 0",swap);
357 fclose(f);
358 create_swap = 0;
359 }
360 }
361 }
362
363 /*
364 * Don't modify **argv directly, it would show up in the "ps" display.
365 * I don't want "init" to look like "rc".
366 */
367 arguments[0] = rc;
368 for ( j = 1; j < argc; j++ ) {
369 arguments[j] = argv[j];
370 }
371 arguments[j] = 0;
372
373 if ( run_rc )
374 waitfor(run(rc, arguments, console, 0));
375
376 if ( 0 == create_swap) {
377 if (unlink("/etc/swappartition")) {
378 perror("unlinking /etc/swappartition");
379 }
380 }
381
382 arguments[0] = "-sh";
383 arguments[1] = 0;
384 for ( ; ; ) {
385 int wpid;
386 int status;
387
388 if ( pid1 == 0 && tty_commands[0] ) {
389 /* Ask before starting a shell */
390 /*
391 arguments[0] = tty_commands[0];
392 */
393 pid1 = run(tty_commands[0], arguments, first_terminal, 0);
394 }
395 if ( pid2 == 0 && tty_commands[1] )
396 pid2 = run(tty_commands[1], arguments, second_terminal, 1);
397 wpid = wait(&status);
398 if ( wpid > 0 ) {
399 /* DEBUGGING */
400 message(log, "pid %d exited, status=%x.\n", wpid, status);
401 }
402 if ( wpid == pid1 ) {
403 pid1 = 0;
404 }
405 if ( wpid == pid2 )
406 pid2 = 0;
407 }
408}
409
410void
411configure_terminals( int serial_cons )
412{
413 //struct stat statbuf;
414 char *tty;
415
416 switch (serial_cons) {
417 case 1:
418 strcpy( console, "/dev/ttyS0" );
419 break;
420 case 2:
421 strcpy( console, "/dev/ttyS1" );
422 break;
423 default:
424 tty = ttyname(0);
425 if (tty) {
426 strcpy( console, tty );
427 if (!strncmp( tty, "/dev/ttyS", 9 ))
428 serial_cons=1;
429 }
430 else
431 /* falls back to /dev/tty1 if an error occurs */
432 strcpy( console, default_console );
433 }
434 if (!first_terminal)
435 first_terminal = console;
436 if (serial_cons && !strncmp(term_ptr,"TERM=linux",10))
437 term_ptr = "TERM=vt100";
438}
diff --git a/init/halt.c b/init/halt.c
new file mode 100644
index 000000000..7f3ccf966
--- /dev/null
+++ b/init/halt.c
@@ -0,0 +1,12 @@
1#include "internal.h"
2#include <signal.h>
3
4const char halt_usage[] = "halt\n"
5"\n\t"
6"\thalt the system.\n";
7
8extern int
9halt_main(struct FileInfo * i, int argc, char * * argv)
10{
11 return kill(1, SIGUSR1);
12}
diff --git a/init/init.c b/init/init.c
new file mode 100644
index 000000000..4771722b9
--- /dev/null
+++ b/init/init.c
@@ -0,0 +1,438 @@
1#include "internal.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <stdarg.h>
5#include <unistd.h>
6#include <errno.h>
7#include <signal.h>
8#include <termios.h>
9#include <sys/types.h>
10#include <sys/fcntl.h>
11#include <sys/wait.h>
12#include <string.h>
13#include <sys/mount.h>
14#include <sys/reboot.h>
15#include <sys/kdaemon.h>
16#include <sys/swap.h>
17#include <sys/sysmacros.h>
18
19const char init_usage[] = "Used internally by the system.";
20char console[16] = "";
21const char * default_console = "/dev/tty1";
22char * first_terminal = NULL;
23const char * second_terminal = "/dev/tty2";
24const char log[] = "/dev/tty3";
25char * term_ptr = NULL;
26
27static void
28message(const char * terminal, const char * pattern, ...)
29{
30 int fd;
31 FILE * con = 0;
32 va_list arguments;
33
34 /*
35 * Open the console device each time a message is printed. If the user
36 * has switched consoles, the open will get the new console. If we kept
37 * the console open, we'd always print to the same one.
38 */
39 if ( ((fd = open(terminal, O_WRONLY|O_NOCTTY)) < 0)
40 || ((con = fdopen(fd, "w")) == NULL) )
41 return;
42
43 va_start(arguments, pattern);
44 vfprintf(con, pattern, arguments);
45 va_end(arguments);
46 fclose(con);
47}
48
49static int
50waitfor(int pid)
51{
52 int status;
53 int wpid;
54
55 message(log, "Waiting for process %d.\n", pid);
56 while ( (wpid = wait(&status)) != pid ) {
57 if ( wpid > 0 ) {
58 message(
59 log
60 ,"pid %d exited, status=%x.\n"
61 ,wpid
62 ,status);
63 }
64 }
65 return wpid;
66}
67
68static int
69run(
70 const char * program
71,const char * const * arguments
72,const char * terminal
73,int get_enter)
74{
75 static const char control_characters[] = {
76 '\003',
77 '\034',
78 '\177',
79 '\025',
80 '\004',
81 '\0',
82 '\1',
83 '\0',
84 '\021',
85 '\023',
86 '\032',
87 '\0',
88 '\022',
89 '\017',
90 '\027',
91 '\026',
92 '\0'
93 };
94
95 static char * environment[] = {
96 "HOME=/",
97 "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
98 "SHELL=/bin/sh",
99 0,
100 "USER=root",
101 0
102 };
103
104 static const char press_enter[] =
105 "Please press Enter to activate this console. ";
106
107 int pid;
108
109 environment[3]=term_ptr;
110
111 pid = fork();
112 if ( pid == 0 ) {
113 struct termios t;
114 const char * const * arg;
115
116 close(0);
117 close(1);
118 close(2);
119 setsid();
120
121 open(terminal, O_RDWR);
122 dup(0);
123 dup(0);
124 tcsetpgrp(0, getpgrp());
125
126 tcgetattr(0, &t);
127 memcpy(t.c_cc, control_characters, sizeof(control_characters));
128 t.c_line = 0;
129 t.c_iflag = ICRNL|IXON|IXOFF;
130 t.c_oflag = OPOST|ONLCR;
131 t.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
132 tcsetattr(0, TCSANOW, &t);
133
134 if ( get_enter ) {
135 /*
136 * Save memory by not exec-ing anything large (like a shell)
137 * before the user wants it. This is critical if swap is not
138 * enabled and the system has low memory. Generally this will
139 * be run on the second virtual console, and the first will
140 * be allowed to start a shell or the installation system.
141 */
142 char c;
143 write(1, press_enter, sizeof(press_enter) - 1);
144 read(0, &c, 1);
145 }
146
147 message(log, "Executing ");
148 arg = arguments;
149 while ( *arg != 0 )
150 message(log, "%s ", *arg++);
151 message(log, "\n");
152
153 execve(program, (char * *)arguments, (char * *)environment);
154 message(log, "%s: could not execute: %s.\r\n", program, strerror(errno));
155 exit(-1);
156 }
157 return pid;
158}
159
160static int
161mem_total()
162{
163 char s[80];
164 char *p;
165 FILE *f;
166 const char pattern[]="MemTotal:";
167
168 f=fopen("/proc/meminfo","r");
169 while (NULL != fgets(s,79,f)) {
170 p=strstr(s, pattern);
171 if (NULL != p) {
172 fclose(f);
173 return(atoi(p+strlen(pattern)));
174 }
175 }
176 return -1;
177}
178
179static void
180set_free_pages()
181{
182 char s[80];
183 FILE *f;
184
185 f=fopen("/proc/sys/vm/freepages","r");
186 fgets(s,79,f);
187 if (atoi(s) < 32) {
188 fclose(f);
189 f=fopen("/proc/sys/vm/freepages","w");
190 fprintf(f,"30\t40\t50\n");
191 printf("\nIncreased /proc/sys/vm/freepages values to 30/40/50\n");
192 }
193 fclose(f);
194}
195
196static void
197shutdown_system(int do_reboot)
198{
199 static const char * const umount_args[] = {"/bin/umount", "-a", "-n", 0};
200
201 sync();
202 /* Allow Ctrl-Alt-Del to reboot system. */
203 reboot(RB_ENABLE_CAD);
204
205 /* Send signals to every process _except_ pid 1 */
206 message(console, "Sending SIGHUP to all processes.\r\n");
207 kill(-1, SIGHUP);
208 sleep(2);
209 sync();
210 message(console, "Sending SIGKILL to all processes.\r\n");
211 kill(-1, SIGKILL);
212 sleep(1);
213 waitfor(run("/bin/umount", umount_args, console, 0));
214 sync();
215 bdflush(1, 0);
216 sync();
217 reboot(do_reboot ?RB_AUTOBOOT : RB_HALT_SYSTEM);
218 exit(0);
219}
220
221static void
222halt_signal(int sig)
223{
224 shutdown_system(0);
225}
226
227static void
228reboot_signal(int sig)
229{
230 shutdown_system(1);
231}
232
233static void
234exit_signal(int sig)
235{
236
237 /* initrd doesn't work anyway */
238
239 shutdown_system(1);
240
241 /* This is used on the initial ramdisk */
242
243 /* message(log, "Init exiting.");
244 exit(0);
245 */
246}
247
248void
249configure_terminals( int serial_cons );
250
251extern int
252init_main(struct FileInfo * i, int argc, char * * argv)
253{
254 static const char * const rc = "etc/rc";
255 const char * arguments[100];
256 int run_rc = 1;
257 int j;
258 int pid1 = 0;
259 int pid2 = 0;
260 int create_swap= -1;
261 struct stat statbuf;
262#ifndef INCLUDE_DINSTALL
263 const char * tty_commands[2] = { "bin/sh", "bin/sh"};
264#else
265 const char * tty_commands[2] = { "sbin/dinstall", "bin/sh"};
266#endif
267 char swap[20];
268 int serial_console = 0;
269
270 /*
271 * If I am started as /linuxrc instead of /sbin/init, I don't have the
272 * environment that init expects. I can't fix the signal behavior. Try
273 * to divorce from the controlling terminal with setsid(). This won't work
274 * if I am the process group leader.
275 */
276 setsid();
277
278 signal(SIGUSR1, halt_signal);
279 signal(SIGUSR2, reboot_signal);
280 signal(SIGINT, reboot_signal);
281 signal(SIGTERM, exit_signal);
282
283 reboot(RB_DISABLE_CAD);
284
285 message(log, "%s: started. ", argv[0]);
286
287 for ( j = 1; j < argc; j++ ) {
288 if ( strcmp(argv[j], "single") == 0 ) {
289 run_rc = 0;
290 tty_commands[0] = "bin/sh";
291 tty_commands[1] = 0;
292 }
293 }
294 for ( j = 0; __environ[j] != 0; j++ ) {
295 if ( strncmp(__environ[j], "tty", 3) == 0
296 && __environ[j][3] >= '1'
297 && __environ[j][3] <= '2'
298 && __environ[j][4] == '=' ) {
299 const char * s = &__environ[j][5];
300
301 if ( *s == 0 || strcmp(s, "off") == 0 )
302 s = 0;
303
304 tty_commands[__environ[j][3] - '1'] = s;
305 }
306 /* Should catch the syntax of Sparc kernel console setting. */
307 /* The kernel does not recognize a serial console when getting*/
308 /* console=/dev/ttySX !! */
309 else if ( strcmp(__environ[j], "console=ttya") == 0 ) {
310 serial_console=1;
311 }
312 else if ( strcmp(__environ[j], "console=ttyb") == 0 ) {
313 serial_console=2;
314 }
315 /* standard console settings */
316 else if ( strncmp(__environ[j], "console=", 8) == 0 ) {
317 first_terminal=&(__environ[j][8]);
318 }
319 else if ( strncmp(__environ[j], "TERM=", 5) == 0) {
320 term_ptr=__environ[j];
321 }
322 }
323 configure_terminals( serial_console );
324
325 printf("mounting /proc ...\n");
326 if (mount("/proc","/proc","proc",0,0)) {
327 perror("mounting /proc failed\n");
328 }
329 printf("\tdone.\n");
330
331 set_free_pages();
332
333 if (mem_total() < 3500) { /* not enough memory for standard install */
334 int retval;
335 retval= stat("/etc/swappartition",&statbuf);
336 if (retval) {
337 printf("
338You do not have enough RAM, hence you must boot using the Boot Disk
339for Low Memory systems.
340
341Read the instructions in the install.html file.
342");
343 while (1) {;}
344 } else { /* everything OK */
345 FILE *f;
346
347 f=fopen("/etc/swappartition","r");
348 fgets(swap,19,f);
349 fclose(f);
350 *(strstr(swap,"\n"))='\0';
351
352 if (swapon(swap,0)) {
353 perror("swapon failed\n");
354 } else {
355 f=fopen("/etc/swaps","w");
356 fprintf(f,"%s none swap rw 0 0",swap);
357 fclose(f);
358 create_swap = 0;
359 }
360 }
361 }
362
363 /*
364 * Don't modify **argv directly, it would show up in the "ps" display.
365 * I don't want "init" to look like "rc".
366 */
367 arguments[0] = rc;
368 for ( j = 1; j < argc; j++ ) {
369 arguments[j] = argv[j];
370 }
371 arguments[j] = 0;
372
373 if ( run_rc )
374 waitfor(run(rc, arguments, console, 0));
375
376 if ( 0 == create_swap) {
377 if (unlink("/etc/swappartition")) {
378 perror("unlinking /etc/swappartition");
379 }
380 }
381
382 arguments[0] = "-sh";
383 arguments[1] = 0;
384 for ( ; ; ) {
385 int wpid;
386 int status;
387
388 if ( pid1 == 0 && tty_commands[0] ) {
389 /* Ask before starting a shell */
390 /*
391 arguments[0] = tty_commands[0];
392 */
393 pid1 = run(tty_commands[0], arguments, first_terminal, 0);
394 }
395 if ( pid2 == 0 && tty_commands[1] )
396 pid2 = run(tty_commands[1], arguments, second_terminal, 1);
397 wpid = wait(&status);
398 if ( wpid > 0 ) {
399 /* DEBUGGING */
400 message(log, "pid %d exited, status=%x.\n", wpid, status);
401 }
402 if ( wpid == pid1 ) {
403 pid1 = 0;
404 }
405 if ( wpid == pid2 )
406 pid2 = 0;
407 }
408}
409
410void
411configure_terminals( int serial_cons )
412{
413 //struct stat statbuf;
414 char *tty;
415
416 switch (serial_cons) {
417 case 1:
418 strcpy( console, "/dev/ttyS0" );
419 break;
420 case 2:
421 strcpy( console, "/dev/ttyS1" );
422 break;
423 default:
424 tty = ttyname(0);
425 if (tty) {
426 strcpy( console, tty );
427 if (!strncmp( tty, "/dev/ttyS", 9 ))
428 serial_cons=1;
429 }
430 else
431 /* falls back to /dev/tty1 if an error occurs */
432 strcpy( console, default_console );
433 }
434 if (!first_terminal)
435 first_terminal = console;
436 if (serial_cons && !strncmp(term_ptr,"TERM=linux",10))
437 term_ptr = "TERM=vt100";
438}
diff --git a/init/reboot.c b/init/reboot.c
new file mode 100644
index 000000000..0388fbce7
--- /dev/null
+++ b/init/reboot.c
@@ -0,0 +1,12 @@
1#include "internal.h"
2#include <signal.h>
3
4const char reboot_usage[] = "reboot\n"
5"\n\t"
6"\treboot the system.\n";
7
8extern int
9reboot_main(struct FileInfo * i, int argc, char * * argv)
10{
11 return kill(1, SIGUSR2);
12}
diff --git a/internal.h b/internal.h
new file mode 100644
index 000000000..e658d3b7d
--- /dev/null
+++ b/internal.h
@@ -0,0 +1,189 @@
1#ifndef _INTERNAL_H_
2#define _INTERNAL_H_
3
4#include "busybox.def.h"
5
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9#include <sys/stat.h>
10
11
12/* Some useful definitions */
13typedef int BOOL;
14#define STDIN 0
15#define STDOUT 1
16#define FALSE ((BOOL) 0)
17#define TRUE ((BOOL) 1)
18
19#define PATH_LEN 1024
20#define BUF_SIZE 8192
21#define EXPAND_ALLOC 1024
22
23#define isBlank(ch) (((ch) == ' ') || ((ch) == '\t'))
24#define isDecimal(ch) (((ch) >= '0') && ((ch) <= '9'))
25#define isOctal(ch) (((ch) >= '0') && ((ch) <= '7'))
26#define isWildCard(ch) (((ch) == '*') || ((ch) == '?') || ((ch) == '['))
27
28
29
30struct FileInfo {
31 unsigned int complainInPostProcess:1;
32 unsigned int changeUserID:1;
33 unsigned int changeGroupID:1;
34 unsigned int changeMode:1;
35 unsigned int create:1;
36 unsigned int force:1;
37 unsigned int recursive:1;
38 unsigned int processDirectoriesAfterTheirContents;
39 unsigned int makeParentDirectories:1;
40 unsigned int didOperation:1;
41 unsigned int isSymbolicLink:1;
42 unsigned int makeSymbolicLink:1;
43 unsigned int dyadic:1;
44 const char* source;
45 const char* destination;
46 int directoryLength;
47 uid_t userID;
48 gid_t groupID;
49 mode_t andWithMode;
50 mode_t orWithMode;
51 struct stat stat;
52 const struct Applet *
53 applet;
54};
55
56struct Applet {
57 const char* name;
58 int (*main)(int argc, char** argv);
59};
60
61extern void name_and_error(const char*);
62extern int is_a_directory(const char*);
63extern char* join_paths(char *, const char *, const char *);
64
65extern int descend(
66 struct FileInfo *o
67 ,int (*function)(const struct FileInfo * i));
68
69extern struct mntent *
70 findMountPoint(const char*, const char *);
71
72extern void usage(const char*);
73extern int busybox_main(int argc, char** argv);
74extern int block_device_main(int argc, char** argv);
75extern int cat_more_main(int argc, char** argv);
76extern int chgrp_main(int argc, char** argv);
77extern int chmod_main(int argc, char** argv);
78extern int chown_main(int argc, char** argv);
79extern int chroot_main(int argc, char** argv);
80extern int clear_main(int argc, char** argv);
81extern int date_main(int argc, char** argv);
82extern int dd_main(int argc, char** argv);
83extern int df_main(int argc, char** argv);
84extern int dmesg_main(int argc, char** argv);
85extern int dyadic_main(int argc, char** argv);
86extern int false_main(int argc, char** argv);
87extern int fdisk_main(int argc, char** argv);
88extern int find_main(int argc, char** argv);
89extern int grep_main(int argc, char** argv);
90extern int halt_main(int argc, char** argv);
91extern int init_main(int argc, char** argv);
92extern int kill_main(int argc, char** argv);
93extern int length_main(int argc, char** argv);
94extern int ln_main(int argc, char** argv);
95extern int loadkmap_main(int argc, char** argv);
96extern int losetup_main(int argc, char** argv);
97extern int ls_main(int argc, char** argv);
98extern int makedevs_main(int argc, char** argv);
99extern int math_main(int argc, char** argv);
100extern int mknod_main(int argc, char** argv);
101extern int mkswap_main(int argc, char** argv);
102extern int mnc_main(int argc, char** argv);
103extern int monadic_main(int argc, char** argv);
104extern int mount_main(int argc, char** argv);
105extern int mt_main(int argc, char** argv);
106extern int printf_main(int argc, char** argv);
107extern int pwd_main(int argc, char** argv);
108extern int reboot_main(int argc, char** argv);
109extern int rm_main(int argc, char** argv);
110extern int scan_partitions_main(int argc, char** argv);
111extern int sh_main(int argc, char** argv);
112extern int sleep_main(int argc, char** argv);
113extern int tar_main(int argc, char** argv);
114extern int sync_main(int argc, char** argv);
115extern int tput_main(int argc, char** argv);
116extern int true_main(int argc, char** argv);
117extern int tryopen_main(int argc, char** argv);
118extern int umount_main(int argc, char** argv);
119extern int update_main(int argc, char** argv);
120extern int zcat_main(int argc, char** argv);
121extern int gzip_main(int argc, char** argv);
122
123extern int
124parse_mode(
125 const char* s
126,mode_t * or
127,mode_t * and
128,int * group_execute);
129
130extern int parse_user_name(const char* string, struct FileInfo * i);
131
132extern const char block_device_usage[];
133extern const char chgrp_usage[];
134extern const char chmod_usage[];
135extern const char chown_usage[];
136extern const char chroot_usage[];
137extern const char clear_usage[];
138extern const char cp_usage[];
139extern const char date_usage[];
140extern const char dd_usage[];
141extern const char df_usage[];
142extern const char dmesg_usage[];
143extern const char dutmp_usage[];
144extern const char false_usage[];
145extern const char fdflush_usage[];
146extern const char find_usage[];
147extern const char grep_usage[];
148extern const char halt_usage[];
149extern const char init_usage[];
150extern const char kill_usage[];
151extern const char length_usage[];
152extern const char ln_usage[];
153extern const char loadkmap_usage[];
154extern const char losetup_usage[];
155extern const char ls_usage[];
156extern const char math_usage[];
157extern const char makedevs_usage[];
158extern const char mkdir_usage[];
159extern const char mknod_usage[];
160extern const char mkswap_usage[];
161extern const char mnc_usage[];
162extern const char more_usage[];
163extern const char mount_usage[];
164extern const char mt_usage[];
165extern const char mv_usage[];
166extern const char printf_usage[];
167extern const char pwd_usage[];
168extern const char reboot_usage[];
169extern const char rm_usage[];
170extern const char rmdir_usage[];
171extern const char scan_partitions_usage[];
172extern const char sleep_usage[];
173extern const char tar_usage[];
174extern const char swapoff_usage[];
175extern const char swapon_usage[];
176extern const char sync_usage[];
177extern const char touch_usage[];
178extern const char tput_usage[];
179extern const char true_usage[];
180extern const char tryopen_usage[];
181extern const char umount_usage[];
182extern const char update_usage[];
183extern const char zcat_usage[];
184extern const char gzip_usage[];
185
186
187
188#endif
189
diff --git a/kill.c b/kill.c
new file mode 100644
index 000000000..da025fafc
--- /dev/null
+++ b/kill.c
@@ -0,0 +1,140 @@
1#include "internal.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <signal.h>
6
7const char kill_usage[] = "kill [-signal] process-id [process-id ...]\n";
8
9struct signal_name {
10 const char * name;
11 int number;
12};
13
14const struct signal_name signames[] = {
15 { "HUP", SIGHUP },
16 { "INT", SIGINT },
17 { "QUIT", SIGQUIT },
18 { "ILL", SIGILL },
19 { "TRAP", SIGTRAP },
20 { "ABRT", SIGABRT },
21#ifndef __alpha__
22 { "IOT", SIGIOT },
23#endif
24#if defined(sparc) || defined(__alpha__)
25 { "EMT", SIGEMT },
26#else
27 { "BUS", SIGBUS },
28#endif
29 { "FPE", SIGFPE },
30 { "KILL", SIGKILL },
31#if defined(sparc) || defined(__alpha__)
32 { "BUS", SIGBUS },
33#else
34 { "USR1", SIGUSR1 },
35#endif
36 { "SEGV", SIGSEGV },
37#if defined(sparc) || defined(__alpha__)
38 { "SYS", SIGSYS },
39#else
40 { "USR2", SIGUSR2 },
41#endif
42 { "PIPE", SIGPIPE },
43 { "ALRM", SIGALRM },
44 { "TERM", SIGTERM },
45#if defined(sparc) || defined(__alpha__)
46 { "URG", SIGURG },
47 { "STOP", SIGSTOP },
48 { "TSTP", SIGTSTP },
49 { "CONT", SIGCONT },
50 { "CHLD", SIGCHLD },
51 { "TTIN", SIGTTIN },
52 { "TTOU", SIGTTOU },
53 { "IO", SIGIO },
54# ifndef __alpha__
55 { "POLL", SIGIO },
56# endif
57 { "XCPU", SIGXCPU },
58 { "XFSZ", SIGXFSZ },
59 { "VTALRM", SIGVTALRM },
60 { "PROF", SIGPROF },
61 { "WINCH", SIGWINCH },
62# ifdef __alpha__
63 { "INFO", SIGINFO },
64# else
65 { "LOST", SIGLOST },
66# endif
67 { "USR1", SIGUSR1 },
68 { "USR2", SIGUSR2 },
69#else
70 { "STKFLT", SIGSTKFLT },
71 { "CHLD", SIGCHLD },
72 { "CONT", SIGCONT },
73 { "STOP", SIGSTOP },
74 { "TSTP", SIGTSTP },
75 { "TTIN", SIGTTIN },
76 { "TTOU", SIGTTOU },
77 { "URG", SIGURG },
78 { "XCPU", SIGXCPU },
79 { "XFSZ", SIGXFSZ },
80 { "VTALRM", SIGVTALRM },
81 { "PROF", SIGPROF },
82 { "WINCH", SIGWINCH },
83 { "IO", SIGIO },
84 { "POLL", SIGPOLL },
85 { "PWR", SIGPWR },
86 { "UNUSED", SIGUNUSED },
87#endif
88 { 0, 0 }
89};
90
91extern int
92kill_main(struct FileInfo * i, int argc, char * * argv)
93{
94 int had_error = 0;
95 int sig = SIGTERM;
96 if ( argv[1][0] == '-' ) {
97 if ( argv[1][1] >= '0' && argv[1][1] <= '9' ) {
98 sig = atoi(&argv[1][1]);
99 if ( sig < 0 || sig >= NSIG ) {
100 usage(kill_usage);
101 exit(-1);
102 }
103 }
104 else {
105 const struct signal_name * s = signames;
106 for ( ; ; ) {
107 if ( strcmp(s->name, &argv[1][1]) == 0 ) {
108 sig = s->number;
109 break;
110 }
111 s++;
112 if ( s->name == 0 ) {
113 usage(kill_usage);
114 exit(-1);
115 }
116 }
117 }
118 argv++;
119 argc--;
120
121 }
122 while ( argc > 1 ) {
123 int pid;
124 if ( argv[1][0] < '0' || argv[1][0] > '9' ) {
125 usage(kill_usage);
126 exit(-1);
127 }
128 pid = atoi(argv[1]);
129 if ( kill(pid, sig) != 0 ) {
130 had_error = 1;
131 perror(argv[1]);
132 }
133 argv++;
134 argc--;
135 }
136 if ( had_error )
137 return -1;
138 else
139 return 0;
140}
diff --git a/length.c b/length.c
new file mode 100644
index 000000000..284bbfdf9
--- /dev/null
+++ b/length.c
@@ -0,0 +1,13 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5
6const char length_usage[] = "length string";
7
8int
9length_main(struct FileInfo * i, int argc, char * * argv)
10{
11 printf("%d\n", strlen(argv[1]));
12 return 0;
13}
diff --git a/ln.c b/ln.c
new file mode 100644
index 000000000..3e87b579e
--- /dev/null
+++ b/ln.c
@@ -0,0 +1,52 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/stat.h>
4#include <sys/param.h>
5#include <errno.h>
6
7const char ln_usage[] = "ln [-s] [-f] original-name additional-name\n"
8"\n"
9"\tAdd a new name that refers to the same file as \"original-name\"\n"
10"\n"
11"\t-s:\tUse a \"symbolic\" link, instead of a \"hard\" link.\n"
12"\t-f:\tRemove existing destination files.\n";
13
14int
15ln_fn(const struct FileInfo * i)
16{
17 int status = 0;
18 char d[PATH_MAX];
19 const char * destination = i->destination;
20
21 if ( !i->makeSymbolicLink && (i->stat.st_mode & S_IFMT) == S_IFDIR ) {
22 fprintf(stderr, "Please use \"ln -s\" to link directories.\n");
23 return 1;
24 }
25
26 /*
27 * If the destination is a directory, create a file within it.
28 */
29 if ( is_a_directory(i->destination) ) {
30 destination = join_paths(
31 d
32 ,i->destination
33 ,&i->source[i->directoryLength]);
34 }
35
36 if ( i->force )
37 status = ( unlink(destination) && errno != ENOENT );
38
39 if ( status == 0 ) {
40 if ( i->makeSymbolicLink )
41 status = symlink(i->source, destination);
42 else
43 status = link(i->source, destination);
44 }
45
46 if ( status != 0 ) {
47 name_and_error(destination);
48 return 1;
49 }
50 else
51 return 0;
52}
diff --git a/loadkmap.c b/loadkmap.c
new file mode 100644
index 000000000..0f092d193
--- /dev/null
+++ b/loadkmap.c
@@ -0,0 +1,68 @@
1#include "internal.h"
2#include <errno.h>
3#include <fcntl.h>
4#include <stdio.h>
5#include <linux/kd.h>
6#include <linux/keyboard.h>
7#include <sys/ioctl.h>
8
9
10const char loadkmap_usage[] = "loadkmap\n"
11"\n"
12"\tLoad a binary keyboard translation table from standard input.\n"
13"\n";
14
15
16int
17loadkmap_main(struct FileInfo * info, int argc, char * * argv)
18{
19 struct kbentry ke;
20 u_short *ibuff;
21 int i,j,fd,readsz,pos,ibuffsz=NR_KEYS * sizeof(u_short);
22 char flags[MAX_NR_KEYMAPS],magic[]="bkeymap",buff[7];
23
24 fd = open("/dev/tty0", O_RDWR);
25 if (fd < 0) {
26 fprintf(stderr, "Error opening /dev/tty0: %s\n", strerror(errno));
27 return 1;
28 }
29
30 read(0,buff,7);
31 if (0 != strncmp(buff,magic,7)) {
32 fprintf(stderr, "This is not a valid binary keymap.\n");
33 return 1;
34 }
35
36 if ( MAX_NR_KEYMAPS != read(0,flags,MAX_NR_KEYMAPS) ) {
37 fprintf(stderr, "Error reading keymap flags: %s\n", strerror(errno));
38 return 1;
39 }
40
41 ibuff=(u_short *) malloc(ibuffsz);
42 if (!ibuff) {
43 fprintf(stderr, "Out of memory.\n");
44 return 1;
45 }
46
47 for(i=0; i<MAX_NR_KEYMAPS; i++) {
48 if (flags[i]==1){
49 pos=0;
50 while (pos < ibuffsz) {
51 if ( (readsz = read(0,ibuff+pos,ibuffsz-pos)) < 0 ) {
52 fprintf(stderr, "Error reading keymap: %s\n",
53 strerror(errno));
54 return 1;
55 }
56 pos += readsz;
57 }
58 for(j=0; j<NR_KEYS; j++) {
59 ke.kb_index = j;
60 ke.kb_table = i;
61 ke.kb_value = ibuff[j];
62 ioctl(fd, KDSKBENT, &ke);
63 }
64 }
65 }
66 close (fd);
67 return 0;
68}
diff --git a/losetup.c b/losetup.c
new file mode 100644
index 000000000..2908dbc88
--- /dev/null
+++ b/losetup.c
@@ -0,0 +1,190 @@
1/*
2 * losetup.c - setup and control loop devices
3 */
4
5
6#include "internal.h"
7
8const char losetup_usage[] = "losetup\n"
9"\n"
10"\tlosetup loop_device give info\n"
11"\tlosetup -d loop_device delete\n"
12"\tlosetup [ -o offset ] loop_device file setup\n";
13
14/* from mount-2.6d */
15
16/*
17 * losetup.c - setup and control loop devices
18 */
19
20#include <stdio.h>
21#include <string.h>
22#include <ctype.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <getopt.h>
26#include <errno.h>
27#include <sys/ioctl.h>
28#include <linux/fs.h>
29/* #include "loop.h" */
30
31/*
32 * include/linux/loop.h
33 *
34 * Written by Theodore Ts'o, 3/29/93.
35 *
36 * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
37 * permitted under the GNU Public License.
38 */
39
40#define LO_NAME_SIZE 64
41#define LO_KEY_SIZE 32
42
43struct loop_info {
44 int lo_number; /* ioctl r/o */
45 dev_t lo_device; /* ioctl r/o */
46 unsigned long lo_inode; /* ioctl r/o */
47 dev_t lo_rdevice; /* ioctl r/o */
48 int lo_offset;
49 int lo_encrypt_type;
50 int lo_encrypt_key_size; /* ioctl w/o */
51 int lo_flags; /* ioctl r/o */
52 char lo_name[LO_NAME_SIZE];
53 unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
54 unsigned long lo_init[2];
55 char reserved[4];
56};
57
58/*
59 * IOCTL commands --- we will commandeer 0x4C ('L')
60 */
61
62#define LOOP_SET_FD 0x4C00
63#define LOOP_CLR_FD 0x4C01
64#define LOOP_SET_STATUS 0x4C02
65#define LOOP_GET_STATUS 0x4C03
66
67/* #include "lomount.h" */
68
69extern int set_loop (const char *, const char *, int, int *);
70extern int del_loop (const char *);
71
72static void show_loop(const char *device)
73{
74 struct loop_info loopinfo;
75 int fd;
76
77 if ((fd = open(device, O_RDWR)) < 0) {
78 perror(device);
79 return;
80 }
81 if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
82 perror("Cannot get loop info");
83 close(fd);
84 return;
85 }
86 printf("%s: [%04x]:%ld (%s) offset %d\n",
87 device, (unsigned int)loopinfo.lo_device, loopinfo.lo_inode,
88 loopinfo.lo_name, loopinfo.lo_offset);
89 close(fd);
90}
91
92
93int set_loop(const char *device, const char *file, int offset, int *loopro)
94{
95 struct loop_info loopinfo;
96 int fd, ffd, mode;
97
98 mode = *loopro ? O_RDONLY : O_RDWR;
99 if ((ffd = open (file, mode)) < 0 && !*loopro
100 && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) {
101 perror (file);
102 return 1;
103 }
104 if ((fd = open (device, mode)) < 0) {
105 close(ffd);
106 perror (device);
107 return 1;
108 }
109 *loopro = (mode == O_RDONLY);
110
111 memset(&loopinfo, 0, sizeof(loopinfo));
112 strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
113 loopinfo.lo_name[LO_NAME_SIZE-1] = 0;
114
115 loopinfo.lo_offset = offset;
116
117 loopinfo.lo_encrypt_key_size = 0;
118 if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
119 perror("ioctl: LOOP_SET_FD");
120 exit(1);
121 }
122 if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
123 (void) ioctl(fd, LOOP_CLR_FD, 0);
124 perror("ioctl: LOOP_SET_STATUS");
125 exit(1);
126 }
127 close(fd);
128 close(ffd);
129 return 0;
130}
131
132int del_loop(const char *device)
133{
134 int fd;
135
136 if ((fd = open(device, O_RDONLY)) < 0) {
137 perror(device);
138 exit(1);
139 }
140 if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
141 perror("ioctl: LOOP_CLR_FD");
142 exit(1);
143 }
144 close(fd);
145 return(0);
146}
147
148
149static int losetup_usage_fn(void)
150{
151 fprintf(stderr, losetup_usage);
152 exit(1);
153}
154
155int losetup_main(struct FileInfo * i, int argc, char * * argv)
156{
157 char *offset;
158 int delete,off,c;
159 int ro = 0;
160
161 delete = off = 0;
162 offset = NULL;
163 while ((c = getopt(argc,argv,"do:")) != EOF) {
164 switch (c) {
165 case 'd':
166 delete = 1;
167 break;
168 case 'o':
169 offset = optarg;
170 break;
171 default:
172 losetup_usage_fn();
173 }
174 }
175 if (argc == 1) losetup_usage_fn();
176 if ((delete && (argc != optind+1 || offset)) ||
177 (!delete && (argc < optind+1 || argc > optind+2)))
178 losetup_usage_fn();
179 if (argc == optind+1)
180 if (delete)
181 del_loop(argv[optind]);
182 else
183 show_loop(argv[optind]);
184 else {
185 if (offset && sscanf(offset,"%d",&off) != 1)
186 losetup_usage_fn();
187 set_loop(argv[optind],argv[optind+1],off,&ro);
188 }
189 return 0;
190}
diff --git a/ls.c b/ls.c
new file mode 100644
index 000000000..2566beea0
--- /dev/null
+++ b/ls.c
@@ -0,0 +1,542 @@
1#include "internal.h"
2/*
3 * tiny-ls.c version 0.1.0: A minimalist 'ls'
4 * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/*
22 * To achieve a small memory footprint, this version of 'ls' doesn't do any
23 * file sorting, and only has the most essential command line switches
24 * (i.e. the ones I couldn't live without :-) All features which involve
25 * linking in substantial chunks of libc can be disabled.
26 *
27 * Although I don't really want to add new features to this program to
28 * keep it small, I *am* interested to receive bug fixes and ways to make
29 * it more portable.
30 *
31 * KNOWN BUGS:
32 * 1. messy output if you mix files and directories on the command line
33 * 2. ls -l of a directory doesn't give "total <blocks>" header
34 * 3. ls of a symlink to a directory doesn't list directory contents
35 * 4. hidden files can make column width too large
36 * NON-OPTIMAL BEHAVIOUR:
37 * 1. autowidth reads directories twice
38 * 2. if you do a short directory listing without filetype characters
39 * appended, there's no need to stat each one
40 * PORTABILITY:
41 * 1. requires lstat (BSD) - how do you do it without?
42 */
43
44#define FEATURE_USERNAME /* show username/groupnames (libc6 uses NSS) */
45#define FEATURE_TIMESTAMPS /* show file timestamps */
46#define FEATURE_AUTOWIDTH /* calculate terminal & column widths */
47#define FEATURE_FILETYPECHAR /* enable -p and -F */
48
49#undef OP_BUF_SIZE 1024 /* leave undefined for unbuffered output */
50
51#define TERMINAL_WIDTH 80 /* use 79 if your terminal has linefold bug */
52#define COLUMN_WIDTH 14 /* default if AUTOWIDTH not defined */
53#define COLUMN_GAP 2 /* includes the file type char, if present */
54
55/************************************************************************/
56
57#define HAS_REWINDDIR
58
59#if 1 /* FIXME libc 6 */
60# include <linux/types.h>
61#else
62# include <sys/types.h>
63#endif
64#include <sys/stat.h>
65#include <stdio.h>
66#include <unistd.h>
67#include <dirent.h>
68#include <errno.h>
69#include <stdio.h>
70#ifdef FEATURE_USERNAME
71#include <pwd.h>
72#include <grp.h>
73#endif
74#ifdef FEATURE_TIMESTAMPS
75#include <time.h>
76#endif
77
78#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
79#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
80#ifdef FEATURE_FILETYPECHAR
81#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
82#endif
83
84#ifndef MAJOR
85#define MAJOR(dev) (((dev)>>8)&0xff)
86#define MINOR(dev) ((dev)&0xff)
87#endif
88
89#define MODE1 "rwxrwxrwx"
90#define MODE0 "---------"
91#define SMODE1 "..s..s..t"
92#define SMODE0 "..S..S..T"
93
94/* The 9 mode bits to test */
95
96static const umode_t MBIT[] = {
97 S_IRUSR, S_IWUSR, S_IXUSR,
98 S_IRGRP, S_IWGRP, S_IXGRP,
99 S_IROTH, S_IWOTH, S_IXOTH
100};
101
102/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
103
104static const umode_t SBIT[] = {
105 0, 0, S_ISUID,
106 0, 0, S_ISGID,
107 0, 0, S_ISVTX
108};
109
110#define FMT_AUTO 0
111#define FMT_LONG 1 /* one record per line, extended info */
112#define FMT_SINGLE 2 /* one record per line */
113#define FMT_ROWS 3 /* print across rows */
114#define FMT_COLUMNS 3 /* fill columns (same, since we don't sort) */
115
116#define TIME_MOD 0
117#define TIME_CHANGE 1
118#define TIME_ACCESS 2
119
120#define DISP_FTYPE 1 /* show character for file type */
121#define DISP_EXEC 2 /* show '*' if regular executable file */
122#define DISP_HIDDEN 4 /* show files starting . (except . and ..) */
123#define DISP_DOT 8 /* show . and .. */
124#define DISP_NUMERIC 16 /* numeric uid and gid */
125#define DISP_FULLTIME 32 /* show extended time display */
126#define DIR_NOLIST 64 /* show directory as itself, not contents */
127#define DISP_DIRNAME 128 /* show directory name (for internal use) */
128#define DIR_RECURSE 256 /* -R (not yet implemented) */
129
130static unsigned char display_fmt = FMT_AUTO;
131static unsigned short opts = 0;
132static unsigned short column = 0;
133
134#ifdef FEATURE_AUTOWIDTH
135static unsigned short terminal_width = 0, column_width = 0;
136#else
137#define terminal_width TERMINAL_WIDTH
138#define column_width COLUMN_WIDTH
139#endif
140
141#ifdef FEATURE_TIMESTAMPS
142static unsigned char time_fmt = TIME_MOD;
143#endif
144
145#define wr(data,len) fwrite(data, 1, len, stdout)
146
147static void writenum(long val, short minwidth)
148{
149 char scratch[20];
150
151 char *p = scratch + sizeof(scratch);
152 short len = 0;
153 short neg = (val < 0);
154
155 if (neg) val = -val;
156 do
157 *--p = (val % 10) + '0', len++, val /= 10;
158 while (val);
159 if (neg)
160 *--p = '-', len++;
161 while (len < minwidth)
162 *--p = ' ', len++;
163 wr(p, len);
164 column += len;
165}
166
167static void newline(void)
168{
169 if (column > 0) {
170 wr("\n", 1);
171 column = 0;
172 }
173}
174
175static void tab(short col)
176{
177 static const char spaces[] = " ";
178 #define nspaces ((sizeof spaces)-1) /* null terminator! */
179
180 short n = col - column;
181
182 if (n > 0) {
183 column = col;
184 while (n > nspaces) {
185 wr(spaces, nspaces);
186 n -= nspaces;
187 }
188 /* must be 1...(sizeof spaces) left */
189 wr(spaces, n);
190 }
191 #undef nspaces
192}
193
194#ifdef FEATURE_FILETYPECHAR
195static char append_char(umode_t mode)
196{
197 if (!(opts & DISP_FTYPE))
198 return '\0';
199 if ((opts & DISP_EXEC) && S_ISREG(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
200 return '*';
201 return APPCHAR(mode);
202}
203#endif
204
205/**
206 **
207 ** Display a file or directory as a single item
208 ** (in either long or short format)
209 **
210 **/
211
212static void list_single(const char *name, struct stat *info)
213{
214 char scratch[20];
215 short len = strlen(name);
216#ifdef FEATURE_FILETYPECHAR
217 char append = append_char(info->st_mode);
218#endif
219
220 if (display_fmt == FMT_LONG) {
221 umode_t mode = info->st_mode;
222 int i;
223
224 scratch[0] = TYPECHAR(mode);
225 for (i=0; i<9; i++)
226 if (mode & SBIT[i])
227 scratch[i+1] = (mode & MBIT[i])
228 ? SMODE1[i]
229 : SMODE0[i];
230 else
231 scratch[i+1] = (mode & MBIT[i])
232 ? MODE1[i]
233 : MODE0[i];
234 newline();
235 wr(scratch, 10);
236 column=10;
237 writenum((long)info->st_nlink,(short)4);
238 fputs(" ", stdout);
239#ifdef FEATURE_USERNAME
240 if (!(opts & DISP_NUMERIC)) {
241 struct passwd *pw = getpwuid(info->st_uid);
242 if (pw)
243 fputs(pw->pw_name, stdout);
244 else
245 writenum((long)info->st_uid,(short)0);
246 } else
247#endif
248 writenum((long)info->st_uid,(short)0);
249 tab(24);
250#ifdef FEATURE_USERNAME
251 if (!(opts & DISP_NUMERIC)) {
252 struct group *gr = getgrgid(info->st_gid);
253 if (gr)
254 fputs(gr->gr_name, stdout);
255 else
256 writenum((long)info->st_gid,(short)0);
257 } else
258#endif
259 writenum((long)info->st_gid,(short)0);
260 tab(33);
261 if (S_ISBLK(mode) || S_ISCHR(mode)) {
262 writenum((long)MAJOR(info->st_rdev),(short)3);
263 fputs(", ", stdout);
264 writenum((long)MINOR(info->st_rdev),(short)3);
265 }
266 else
267 writenum((long)info->st_size,(short)8);
268 fputs(" ", stdout);
269#ifdef FEATURE_TIMESTAMPS
270 {
271 time_t cal;
272 char *string;
273
274 switch(time_fmt) {
275 case TIME_CHANGE:
276 cal=info->st_ctime; break;
277 case TIME_ACCESS:
278 cal=info->st_atime; break;
279 default:
280 cal=info->st_mtime; break;
281 }
282 string=ctime(&cal);
283 if (opts & DISP_FULLTIME)
284 wr(string,24);
285 else {
286 time_t age = time(NULL) - cal;
287 wr(string+4,7); /* mmm_dd_ */
288 if(age < 3600L*24*365/2 && age > -15*60)
289 /* hh:mm if less than 6 months old */
290 wr(string+11,5);
291 else
292 /* _yyyy otherwise */
293 wr(string+19,5);
294 }
295 wr(" ", 1);
296 }
297#else
298 fputs("--- -- ----- ", stdout);
299#endif
300 wr(name, len);
301 if (S_ISLNK(mode)) {
302 wr(" -> ", 4);
303 len = readlink(name, scratch, sizeof scratch);
304 if (len > 0) fwrite(scratch, 1, len, stdout);
305#ifdef FEATURE_FILETYPECHAR
306 /* show type of destination */
307 if (opts & DISP_FTYPE) {
308 if (!stat(name, info)) {
309 append = append_char(info->st_mode);
310 if (append)
311 fputc(append, stdout);
312 }
313 }
314#endif
315 }
316#ifdef FEATURE_FILETYPECHAR
317 else if (append)
318 wr(&append, 1);
319#endif
320 } else {
321 static short nexttab = 0;
322
323 /* sort out column alignment */
324 if (column == 0)
325 ; /* nothing to do */
326 else if (display_fmt == FMT_SINGLE)
327 newline();
328 else {
329 if (nexttab + column_width > terminal_width
330#ifndef FEATURE_AUTOWIDTH
331 || nexttab + len >= terminal_width
332#endif
333 )
334 newline();
335 else
336 tab(nexttab);
337 }
338 /* work out where next column starts */
339#ifdef FEATURE_AUTOWIDTH
340 /* we know the calculated width is big enough */
341 nexttab = column + column_width + COLUMN_GAP;
342#else
343 /* might cover more than one fixed-width column */
344 nexttab = column;
345 do
346 nexttab += column_width + COLUMN_GAP;
347 while (nexttab < (column + len + COLUMN_GAP));
348#endif
349 /* now write the data */
350 wr(name, len);
351 column = column + len;
352#ifdef FEATURE_FILETYPECHAR
353 if (append)
354 wr(&append, 1), column++;
355#endif
356 }
357}
358
359/**
360 **
361 ** List the given file or directory, expanding a directory
362 ** to show its contents if required
363 **
364 **/
365
366static int list_item(const char *name)
367{
368 struct stat info;
369 DIR *dir;
370 struct dirent *entry;
371 char fullname[MAXNAMLEN+1], *fnend;
372
373 if (lstat(name, &info))
374 goto listerr;
375
376 if (!S_ISDIR(info.st_mode) ||
377 (opts & DIR_NOLIST)) {
378 list_single(name, &info);
379 return 0;
380 }
381
382 /* Otherwise, it's a directory we want to list the contents of */
383
384 if (opts & DISP_DIRNAME) { /* identify the directory */
385 if (column)
386 wr("\n\n", 2), column = 0;
387 wr(name, strlen(name));
388 wr(":\n", 2);
389 }
390
391 dir = opendir(name);
392 if (!dir) goto listerr;
393#ifdef FEATURE_AUTOWIDTH
394 column_width = 0;
395 while ((entry = readdir(dir)) != NULL) {
396 short w = strlen(entry->d_name);
397 if (column_width < w)
398 column_width = w;
399 }
400#ifdef HAS_REWINDDIR
401 rewinddir(dir);
402#else
403 closedir(dir);
404 dir = opendir(name);
405 if (!dir) goto listerr;
406#endif
407#endif
408
409 /* List the contents */
410
411 strcpy(fullname,name); /* *** ignore '.' by itself */
412 fnend=fullname+strlen(fullname);
413 if (fnend[-1] != '/')
414 *fnend++ = '/';
415
416 while ((entry = readdir(dir)) != NULL) {
417 const char *en=entry->d_name;
418 if (en[0] == '.') {
419 if (!en[1] || (en[1] == '.' && !en[2])) { /* . or .. */
420 if (!(opts & DISP_DOT))
421 continue;
422 }
423 else if (!(opts & DISP_HIDDEN))
424 continue;
425 }
426 /* FIXME: avoid stat if not required */
427 strcpy(fnend, entry->d_name);
428 if (lstat(fullname, &info))
429 goto direrr; /* (shouldn't fail) */
430 list_single(entry->d_name, &info);
431 }
432 closedir(dir);
433 return 0;
434
435direrr:
436 closedir(dir);
437listerr:
438 newline();
439 name_and_error(name);
440 return 1;
441}
442
443const char ls_usage[] = "Usage: ls [-1a"
444#ifdef FEATURE_TIMESTAMPS
445 "c"
446#endif
447 "d"
448#ifdef FEATURE_TIMESTAMPS
449 "e"
450#endif
451 "ln"
452#ifdef FEATURE_FILETYPECHAR
453 "p"
454#endif
455#ifdef FEATURE_TIMESTAMPS
456 "u"
457#endif
458 "xAC"
459#ifdef FEATURE_FILETYPECHAR
460 "F"
461#endif
462#ifdef FEATURE_RECURSIVE
463 "R"
464#endif
465 "] [filenames...]\n";
466
467extern int
468ls_main(struct FileInfo * not_used, int argc, char * * argv)
469{
470 int argi=1, i;
471
472 /* process options */
473 while (argi < argc && argv[argi][0] == '-') {
474 const char *p = &argv[argi][1];
475
476 if (!*p) goto print_usage_message; /* "-" by itself not allowed */
477 if (*p == '-') {
478 if (!p[1]) { /* "--" forces end of options */
479 argi++;
480 break;
481 }
482 /* it's a long option name - we don't support them */
483 goto print_usage_message;
484 }
485
486 while (*p)
487 switch (*p++) {
488 case 'l': display_fmt = FMT_LONG; break;
489 case '1': display_fmt = FMT_SINGLE; break;
490 case 'x': display_fmt = FMT_ROWS; break;
491 case 'C': display_fmt = FMT_COLUMNS; break;
492#ifdef FEATURE_FILETYPECHAR
493 case 'p': opts |= DISP_FTYPE; break;
494 case 'F': opts |= DISP_FTYPE|DISP_EXEC; break;
495#endif
496 case 'A': opts |= DISP_HIDDEN; break;
497 case 'a': opts |= DISP_HIDDEN|DISP_DOT; break;
498 case 'n': opts |= DISP_NUMERIC; break;
499 case 'd': opts |= DIR_NOLIST; break;
500#ifdef FEATURE_RECURSIVE
501 case 'R': opts |= DIR_RECURSE; break;
502#endif
503#ifdef FEATURE_TIMESTAMPS
504 case 'u': time_fmt = TIME_ACCESS; break;
505 case 'c': time_fmt = TIME_CHANGE; break;
506 case 'e': opts |= DISP_FULLTIME; break;
507#endif
508 default: goto print_usage_message;
509 }
510
511 argi++;
512 }
513
514 /* choose a display format */
515 if (display_fmt == FMT_AUTO)
516 display_fmt = isatty(STDOUT_FILENO) ? FMT_COLUMNS : FMT_SINGLE;
517 if (argi < argc - 1)
518 opts |= DISP_DIRNAME; /* 2 or more items? label directories */
519#ifdef FEATURE_AUTOWIDTH
520 /* could add a -w option and/or TIOCGWINSZ call */
521 if (terminal_width < 1) terminal_width = TERMINAL_WIDTH;
522
523 for (i = argi; i < argc; i++) {
524 int len = strlen(argv[i]);
525 if (column_width < len)
526 column_width = len;
527 }
528#endif
529
530 /* process files specified, or current directory if none */
531 i=0;
532 if (argi == argc)
533 i = list_item(".");
534 while (argi < argc)
535 i |= list_item(argv[argi++]);
536 newline();
537 return i;
538
539print_usage_message:
540 usage(ls_usage);
541 return 1;
542}
diff --git a/makedevs.c b/makedevs.c
new file mode 100644
index 000000000..691236e29
--- /dev/null
+++ b/makedevs.c
@@ -0,0 +1,95 @@
1/*
2 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
3 *
4 * makedevs
5 * Make ranges of device files quickly.
6 * known bugs: can't deal with alpha ranges
7 */
8
9#include "internal.h"
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <fcntl.h>
14#include <unistd.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17
18const char makedevs_usage[] =
19"makedevs 0.01 -- Create an entire range of device files\n\n"
20"\tmakedevs /dev/ttyS c 4 64 0 63 (ttyS0-ttyS63)\n"
21"\tmakedevs /dev/hda b 3 0 0 8 s (hda,hda1-hda8)\n";
22
23int
24makedevs_main(struct FileInfo * i, int argc, char * * argv)
25{
26
27const char *basedev = argv[1];
28const char *type = argv[2];
29int major = atoi(argv[3]);
30int Sminor = atoi(argv[4]);
31int S = atoi(argv[5]);
32int E = atoi(argv[6]);
33int sbase = argc == 8 ? 1 : 0;
34
35mode_t mode = 0;
36dev_t dev = 0;
37char devname[255];
38char buf[255];
39
40 switch (type[0]) {
41 case 'c':
42 mode = S_IFCHR; break;
43 case 'b':
44 mode = S_IFBLK; break;
45 case 'f':
46 mode = S_IFIFO; break;
47 default:
48 usage(makedevs_usage);
49 return 2;
50 }
51 mode |= 0660;
52
53 while ( S <= E ) {
54
55 if (type[0] != 'f')
56 dev = (major << 8) | Sminor;
57 strcpy(devname, basedev);
58
59 if (sbase == 0) {
60 sprintf(buf, "%d", S);
61 strcat(devname, buf);
62 } else {
63 sbase = 0;
64 }
65
66 if (mknod (devname, mode, dev))
67 printf("Failed to create: %s\n", devname);
68
69 S++; Sminor++;
70 }
71
72return 0;
73}
74
75/*
76And this is what this program replaces. The shell is too slow!
77
78makedev () {
79local basedev=$1; local S=$2; local E=$3
80local major=$4; local Sminor=$5; local type=$6
81local sbase=$7
82
83 if [ ! "$sbase" = "" ]; then
84 mknod "$basedev" $type $major $Sminor
85 S=`expr $S + 1`
86 Sminor=`expr $Sminor + 1`
87 fi
88
89 while [ $S -le $E ]; do
90 mknod "$basedev$S" $type $major $Sminor
91 S=`expr $S + 1`
92 Sminor=`expr $Sminor + 1`
93 done
94}
95*/
diff --git a/math.c b/math.c
new file mode 100644
index 000000000..5c1560a4e
--- /dev/null
+++ b/math.c
@@ -0,0 +1,149 @@
1#include "internal.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <math.h>
6
7/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
8
9const char math_usage[] = "math expression ...";
10
11static double stack[100];
12static unsigned int pointer;
13
14static void
15push(double a)
16{
17 if ( pointer >= (sizeof(stack) / sizeof(*stack)) ) {
18 fprintf(stderr, "math: stack overflow\n");
19 exit(-1);
20 }
21 else
22 stack[pointer++] = a;
23}
24
25static double
26pop()
27{
28 if ( pointer == 0 ) {
29 fprintf(stderr, "math: stack underflow\n");
30 exit(-1);
31 }
32 return stack[--pointer];
33}
34
35static void
36add()
37{
38 push(pop() + pop());
39}
40
41static void
42sub()
43{
44 double subtrahend = pop();
45
46 push(pop() - subtrahend);
47}
48
49static void
50mul()
51{
52 push(pop() * pop());
53}
54
55static void
56divide()
57{
58 double divisor = pop();
59 push(pop() / divisor);
60}
61
62static void
63and()
64{
65 push((unsigned int)pop() & (unsigned int)pop());
66}
67
68static void
69or()
70{
71 push((unsigned int)pop() | (unsigned int)pop());
72}
73
74static void
75eor()
76{
77 push((unsigned int)pop() ^ (unsigned int)pop());
78}
79
80static void
81not()
82{
83 push(~(unsigned int)pop());
84}
85
86static void
87print()
88{
89 printf("%g\n", pop());
90}
91
92struct op {
93 const char * name;
94 void (*function)();
95};
96
97static const struct op operators[] = {
98 { "add", add },
99 { "and", and },
100 { "div", divide },
101 { "eor", eor },
102 { "mul", mul },
103 { "not", not },
104 { "or", or },
105 { "sub", sub },
106 { 0, 0 }
107};
108
109static void
110stack_machine(const char * argument)
111{
112 char * endPointer = 0;
113 double d;
114 const struct op * o = operators;
115
116 if ( argument == 0 ) {
117 print();
118 return;
119 }
120
121 d = strtod(argument, &endPointer);
122
123 if ( endPointer != argument ) {
124 push(d);
125 return;
126 }
127
128 while ( o->name != 0 ) {
129 if ( strcmp(o->name, argument) == 0 ) {
130 (*(o->function))();
131 return;
132 }
133 o++;
134 }
135 fprintf(stderr, "math: %s: syntax error.\n", argument);
136 exit(-1);
137}
138
139int
140math_main(struct FileInfo * i, int argc, char * * argv)
141{
142 while ( argc >= 2 ) {
143 stack_machine(argv[1]);
144 argv++;
145 argc--;
146 }
147 stack_machine(0);
148 return 0;
149}
diff --git a/miscutils/dutmp.c b/miscutils/dutmp.c
new file mode 100644
index 000000000..e92b6700f
--- /dev/null
+++ b/miscutils/dutmp.c
@@ -0,0 +1,47 @@
1/*
2 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
3 *
4 * dutmp
5 * Takes utmp formated file on stdin and dumps it's contents
6 * out in colon delimited fields. Easy to 'cut' for shell based
7 * versions of 'who', 'last', etc. IP Addr is output in hex,
8 * little endian on x86.
9 *
10 * made against libc6
11 */
12
13#include "internal.h"
14#include <stdio.h>
15#include <utmp.h>
16
17const char dutmp_usage[] = "dutmp\n"
18"\n"
19"\tDump file or stdin utmp file format to stdout, pipe delimited.\n"
20"\tdutmp /var/run/utmp\n";
21
22extern int
23dutmp_fn(const struct FileInfo * i)
24{
25
26FILE * f = stdin;
27struct utmp * ut = (struct utmp *) malloc(sizeof(struct utmp) );
28
29 if ( i )
30 if (! (f = fopen(i->source, "r"))) {
31 name_and_error(i->source);
32 return 1;
33 }
34
35 while (fread (ut, 1, sizeof(struct utmp), f)) {
36 //printf("%d:%d:%s:%s:%s:%s:%d:%d:%ld:%ld:%ld:%x\n",
37 printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n",
38 ut->ut_type, ut->ut_pid, ut->ut_line,
39 ut->ut_id, ut->ut_user, ut->ut_host,
40 ut->ut_exit.e_termination, ut->ut_exit.e_exit,
41 ut->ut_session,
42 ut->ut_tv.tv_sec, ut->ut_tv.tv_usec,
43 ut->ut_addr);
44 }
45
46return 0;
47}
diff --git a/miscutils/makedevs.c b/miscutils/makedevs.c
new file mode 100644
index 000000000..691236e29
--- /dev/null
+++ b/miscutils/makedevs.c
@@ -0,0 +1,95 @@
1/*
2 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
3 *
4 * makedevs
5 * Make ranges of device files quickly.
6 * known bugs: can't deal with alpha ranges
7 */
8
9#include "internal.h"
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <fcntl.h>
14#include <unistd.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17
18const char makedevs_usage[] =
19"makedevs 0.01 -- Create an entire range of device files\n\n"
20"\tmakedevs /dev/ttyS c 4 64 0 63 (ttyS0-ttyS63)\n"
21"\tmakedevs /dev/hda b 3 0 0 8 s (hda,hda1-hda8)\n";
22
23int
24makedevs_main(struct FileInfo * i, int argc, char * * argv)
25{
26
27const char *basedev = argv[1];
28const char *type = argv[2];
29int major = atoi(argv[3]);
30int Sminor = atoi(argv[4]);
31int S = atoi(argv[5]);
32int E = atoi(argv[6]);
33int sbase = argc == 8 ? 1 : 0;
34
35mode_t mode = 0;
36dev_t dev = 0;
37char devname[255];
38char buf[255];
39
40 switch (type[0]) {
41 case 'c':
42 mode = S_IFCHR; break;
43 case 'b':
44 mode = S_IFBLK; break;
45 case 'f':
46 mode = S_IFIFO; break;
47 default:
48 usage(makedevs_usage);
49 return 2;
50 }
51 mode |= 0660;
52
53 while ( S <= E ) {
54
55 if (type[0] != 'f')
56 dev = (major << 8) | Sminor;
57 strcpy(devname, basedev);
58
59 if (sbase == 0) {
60 sprintf(buf, "%d", S);
61 strcat(devname, buf);
62 } else {
63 sbase = 0;
64 }
65
66 if (mknod (devname, mode, dev))
67 printf("Failed to create: %s\n", devname);
68
69 S++; Sminor++;
70 }
71
72return 0;
73}
74
75/*
76And this is what this program replaces. The shell is too slow!
77
78makedev () {
79local basedev=$1; local S=$2; local E=$3
80local major=$4; local Sminor=$5; local type=$6
81local sbase=$7
82
83 if [ ! "$sbase" = "" ]; then
84 mknod "$basedev" $type $major $Sminor
85 S=`expr $S + 1`
86 Sminor=`expr $Sminor + 1`
87 fi
88
89 while [ $S -le $E ]; do
90 mknod "$basedev$S" $type $major $Sminor
91 S=`expr $S + 1`
92 Sminor=`expr $Sminor + 1`
93 done
94}
95*/
diff --git a/miscutils/mt.c b/miscutils/mt.c
new file mode 100644
index 000000000..7d75fbd3d
--- /dev/null
+++ b/miscutils/mt.c
@@ -0,0 +1,98 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/mtio.h>
4#include <sys/fcntl.h>
5
6const char mt_usage[] = "mt [-f device] opcode value\n";
7
8struct mt_opcodes {
9 char * name;
10 short value;
11};
12
13/* missing: eod/seod, stoptions, stwrthreshold, densities */
14static const struct mt_opcodes opcodes[] = {
15 { "bsf", MTBSF },
16 { "bsfm", MTBSFM },
17 { "bsr", MTBSR },
18 { "bss", MTBSS },
19 { "datacompression", MTCOMPRESSION },
20 { "eom", MTEOM },
21 { "erase", MTERASE },
22 { "fsf", MTFSF },
23 { "fsfm", MTFSFM },
24 { "fsr", MTFSR },
25 { "fss", MTFSS },
26 { "load", MTLOAD },
27 { "lock", MTLOCK },
28 { "mkpart", MTMKPART },
29 { "nop", MTNOP },
30 { "offline",MTOFFL },
31 { "rewoffline",MTOFFL },
32 { "ras1", MTRAS1 },
33 { "ras2", MTRAS2 },
34 { "ras3", MTRAS3 },
35 { "reset", MTRESET },
36 { "retension", MTRETEN },
37 { "rew", MTREW },
38 { "seek", MTSEEK },
39 { "setblk", MTSETBLK },
40 { "setdensity", MTSETDENSITY },
41 { "drvbuffer", MTSETDRVBUFFER },
42 { "setpart", MTSETPART },
43 { "tell", MTTELL },
44 { "wset", MTWSM },
45 { "unload", MTUNLOAD },
46 { "unlock", MTUNLOCK },
47 { "eof", MTWEOF },
48 { "weof", MTWEOF },
49 { 0, 0 }
50};
51
52extern int
53mt_main(struct FileInfo * i, int argc, char * * argv)
54{
55 const char * file = "/dev/tape";
56 const struct mt_opcodes * code = opcodes;
57 struct mtop op;
58 int fd;
59
60 if ( strcmp(argv[1], "-f") == 0 ) {
61 if ( argc < 4 ) {
62 usage(mt_usage);
63 return 1;
64 }
65 file = argv[2];
66 argv += 2;
67 argc -= 2;
68 }
69
70 while ( code->name != 0 ) {
71 if ( strcmp(code->name, argv[1]) == 0 )
72 break;
73 code++;
74 }
75
76 if ( code->name == 0 ) {
77 fprintf(stderr, "mt: unrecognized opcode %s.\n", argv[1]);
78 return 1;
79 }
80
81 op.mt_op = code->value;
82 if ( argc >= 3 )
83 op.mt_count = atoi(argv[2]);
84 else
85 op.mt_count = 1; /* One, not zero, right? */
86
87 if ( (fd = open(file, O_RDONLY, 0)) < 0 ) {
88 name_and_error(file);
89 return 1;
90 }
91
92 if ( ioctl(fd, MTIOCTOP, &op) != 0 ) {
93 name_and_error(file);
94 return 1;
95 }
96
97 return 0;
98}
diff --git a/miscutils/update.c b/miscutils/update.c
new file mode 100644
index 000000000..f3b7fc0c8
--- /dev/null
+++ b/miscutils/update.c
@@ -0,0 +1,48 @@
1#include "internal.h"
2#include <linux/unistd.h>
3
4const char update_usage[] = "update\n"
5"\n"
6"\tFlush buffered data to the disk devices every 30 seconds.\n";
7
8#if defined(__GLIBC__)
9#include <sys/kdaemon.h>
10#else
11_syscall2(int, bdflush, int, func, int, data);
12#endif /* __GLIBC__ */
13
14extern int
15update_main(struct FileInfo * i, int argc, char * * argv)
16{
17 /*
18 * Update is actually two daemons, bdflush and update.
19 */
20 int pid;
21
22 pid = fork();
23 if ( pid < 0 )
24 return pid;
25 else if ( pid == 0 ) {
26 /*
27 * This is no longer necessary since 1.3.5x, but it will harmlessly
28 * exit if that is the case.
29 */
30 strcpy(argv[0], "bdflush (update)");
31 argv[1] = 0;
32 argv[2] = 0;
33 bdflush(1, 0);
34 _exit(0);
35 }
36 pid = fork();
37 if ( pid < 0 )
38 return pid;
39 else if ( pid == 0 ) {
40 argv[0] = "update";
41 for ( ; ; ) {
42 sync();
43 sleep(30);
44 }
45 }
46
47 return 0;
48}
diff --git a/mkdir.c b/mkdir.c
new file mode 100644
index 000000000..8f1fa04db
--- /dev/null
+++ b/mkdir.c
@@ -0,0 +1,58 @@
1#include "internal.h"
2#include <errno.h>
3#include <sys/param.h>
4
5const char mkdir_usage[] = "mkdir [-m mode] directory [directory ...]\n"
6"\tCreate directories.\n"
7"\n"
8"\t-m mode:\tSpecifiy the mode for the new directory\n"
9"\t\tunder the argument directory.";
10
11/*make directories skipping the last part of the path. Used here and by untar*/
12int mkdir_until(const char *fpath, const struct FileInfo * fi)
13{
14 char path[PATH_MAX];
15 char * s = path;
16
17 strcpy(path, fpath);
18 if ( s[0] == '\0' && s[1] == '\0' ) {
19 usage(mkdir_usage);
20 return 1;
21 }
22 s++;
23 while ( *s != '\0' ) {
24 if ( *s == '/' ) {
25 int status;
26
27 *s = '\0';
28 status = mkdir(path, (fi?fi->orWithMode:0700) );
29 *s = '/';
30
31 if ( status != 0 ) {
32 if ( errno != EEXIST ) {
33 name_and_error(fpath);
34 return 1;
35 }
36 }
37
38 }
39 s++;
40 }
41 return 0;
42}
43
44int
45mkdir_fn(const struct FileInfo * i)
46{
47 if ( i->makeParentDirectories ) {
48 if(mkdir_until(i->source, i)) return 1;
49 }
50
51 if ( mkdir(i->source, i->orWithMode) != 0 && errno != EEXIST ) {
52 name_and_error(i->source);
53 return 1;
54 }
55 else
56 return 0;
57}
58
diff --git a/mknod.c b/mknod.c
new file mode 100644
index 000000000..b18394bec
--- /dev/null
+++ b/mknod.c
@@ -0,0 +1,52 @@
1#include "internal.h"
2#include <errno.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <fcntl.h>
6#include <unistd.h>
7
8const char mknod_usage[] = "mknod file b|c|u|p major minor\n"
9"\tMake special files.\n"
10"\n"
11"\tb:\tMake a block (buffered) device.\n"
12"\tc or u:\tMake a character (un-buffered) device.\n"
13"\tp:\tMake a named pipe. Major and minor are ignored for named pipes.\n";
14
15int
16mknod_main(struct FileInfo * i, int argc, char * * argv)
17{
18 mode_t mode = 0;
19 dev_t dev = 0;
20
21 switch(argv[2][0]) {
22 case 'c':
23 case 'u':
24 mode = S_IFCHR;
25 break;
26 case 'b':
27 mode = S_IFBLK;
28 break;
29 case 'p':
30 mode = S_IFIFO;
31 break;
32 default:
33 usage(mknod_usage);
34 return 1;
35 }
36
37 if ( mode == S_IFCHR || mode == S_IFBLK ) {
38 dev = (atoi(argv[3]) << 8) | atoi(argv[4]);
39 if ( argc != 5 ) {
40 usage(mknod_usage);
41 return 1;
42 }
43 }
44
45 mode |= 0666;
46
47 if ( mknod(argv[1], mode, dev) != 0 ) {
48 name_and_error(argv[1]);
49 return 1;
50 }
51 return 0;
52}
diff --git a/mkswap.c b/mkswap.c
new file mode 100644
index 000000000..f797d1395
--- /dev/null
+++ b/mkswap.c
@@ -0,0 +1,253 @@
1#include "internal.h"
2/*
3 * mkswap.c - set up a linux swap device
4 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per
6 * the Linux copyright.
7 */
8
9/*
10 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
11 *
12 * Usage: mkswap [-c] device [size-in-blocks]
13 *
14 * -c for readablility checking (use it unless you are SURE!)
15 *
16 * The device may be a block device or a image of one, but this isn't
17 * enforced (but it's not much fun on a character device :-).
18 *
19 * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
20 * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995.
21 */
22
23#include <stdio.h>
24#include <unistd.h>
25#include <string.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <sys/stat.h>
29#include <sys/ioctl.h>
30
31#include <asm/page.h>
32#include <linux/fs.h>
33
34#ifndef __linux__
35# define volatile
36#endif
37
38#define TEST_BUFFER_PAGES 8
39
40const char mkswap_usage[] = "mkswap [-c] partition [block-count]\n"
41"\n"
42"\tPrepare a disk partition to be used as a swap partition.\n"
43"\tThe default block count is the size of the entire partition.\n"
44"\n"
45"\t-c:\tCheck for read-ability.\n"
46"\tblock-count\tUse only this many blocks.\n";
47
48static const char * program_name = "mkswap";
49static const char * device_name = NULL;
50static int DEV = -1;
51static long PAGES = 0;
52static int do_check = 0;
53static int badpages = 0;
54
55
56static long bit_test_and_set (unsigned int *addr, unsigned int nr)
57{
58 unsigned int r, m;
59
60 addr += nr / (8 * sizeof(int));
61 r = *addr;
62 m = 1 << (nr & (8 * sizeof(int) - 1));
63 *addr = r | m;
64 return (r & m) != 0;
65}
66
67static int bit_test_and_clear (unsigned int *addr, unsigned int nr)
68{
69 unsigned int r, m;
70
71 addr += nr / (8 * sizeof(int));
72 r = *addr;
73 m = 1 << (nr & (8 * sizeof(int) - 1));
74 *addr = r & ~m;
75 return (r & m) != 0;
76}
77
78/*
79 * Volatile to let gcc know that this doesn't return. When trying
80 * to compile this under minix, volatile gives a warning, as
81 * exit() isn't defined as volatile under minix.
82 */
83volatile void fatal_error(const char * fmt_string)
84{
85 fprintf(stderr,fmt_string,program_name,device_name);
86 exit(1);
87}
88
89#define die(str) fatal_error("%s: " str "\n")
90
91static void check_blocks(int * signature_page)
92{
93 unsigned int current_page;
94 int do_seek = 1;
95 char buffer[PAGE_SIZE];
96
97 current_page = 0;
98 while (current_page < PAGES) {
99 if (!do_check) {
100 bit_test_and_set(signature_page,current_page++);
101 continue;
102 } else {
103 printf("\r%d", current_page);
104 }
105 if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) !=
106 current_page*PAGE_SIZE)
107 die("seek failed in check_blocks");
108 if ( (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) ) {
109 bit_test_and_clear(signature_page,current_page++);
110 badpages++;
111 continue;
112 }
113 bit_test_and_set(signature_page,current_page++);
114 }
115 if (do_check)
116 printf("\n");
117 if (badpages)
118 printf("%d bad page%s\n",badpages,(badpages>1)?"s":"");
119}
120
121static long valid_offset (int fd, int offset)
122{
123 char ch;
124
125 if (lseek (fd, offset, 0) < 0)
126 return 0;
127 if (read (fd, &ch, 1) < 1)
128 return 0;
129 return 1;
130}
131
132static int count_blocks (int fd)
133{
134 int high, low;
135
136 low = 0;
137 for (high = 1; valid_offset (fd, high); high *= 2)
138 low = high;
139 while (low < high - 1)
140 {
141 const int mid = (low + high) / 2;
142
143 if (valid_offset (fd, mid))
144 low = mid;
145 else
146 high = mid;
147 }
148 valid_offset (fd, 0);
149 return (low + 1);
150}
151
152static int get_size(const char *file)
153{
154 int fd;
155 int size;
156
157 fd = open(file, O_RDWR);
158 if (fd < 0) {
159 perror(file);
160 exit(1);
161 }
162 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
163 close(fd);
164 return (size * 512);
165 }
166
167 size = count_blocks(fd);
168 close(fd);
169 return size;
170}
171
172int
173mkswap(char *device_name, int pages, int check)
174 {
175 struct stat statbuf;
176 int goodpages;
177 int signature_page[PAGE_SIZE/sizeof(int)];
178
179 PAGES = pages;
180 do_check = check;
181
182 memset(signature_page,0,PAGE_SIZE);
183
184 if (device_name && !PAGES) {
185 PAGES = get_size(device_name) / PAGE_SIZE;
186 }
187 if (!device_name || PAGES<10) {
188 fprintf(stderr,
189 "%s: error: swap area needs to be at least %ldkB\n",
190 program_name, 10 * PAGE_SIZE / 1024);
191 /* usage(mkswap_usage); */
192 exit(1);
193 }
194 if (PAGES > 8 * (PAGE_SIZE - 10)) {
195 PAGES = 8 * (PAGE_SIZE - 10);
196 fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n",
197 program_name, PAGES * PAGE_SIZE / 1024);
198 }
199 DEV = open(device_name,O_RDWR);
200 if (DEV < 0 || fstat(DEV, &statbuf) < 0) {
201 perror(device_name);
202 exit(1);
203 }
204 if (!S_ISBLK(statbuf.st_mode))
205 do_check=0;
206 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
207 die("Will not try to make swapdevice on '%s'");
208 check_blocks(signature_page);
209 if (!bit_test_and_clear(signature_page,0))
210 die("fatal: first page unreadable");
211 goodpages = PAGES - badpages - 1;
212 if (goodpages <= 0)
213 die("Unable to set up swap-space: unreadable");
214 printf("Setting up swapspace, size = %ld bytes\n",goodpages*PAGE_SIZE);
215 strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10);
216 if (lseek(DEV, 0, SEEK_SET))
217 die("unable to rewind swap-device");
218 if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE))
219 die("unable to write signature page");
220
221 close(DEV);
222 return 0;
223}
224
225int mkswap_main(struct FileInfo * unnecessary, int argc, char ** argv)
226{
227 char * tmp;
228 long int pages=0;
229 int check=0;
230
231 if (argc && *argv)
232 program_name = *argv;
233 while (argc > 1) {
234 argv++;
235 argc--;
236 if (argv[0][0] != '-')
237 if (device_name) {
238 pages = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10);
239 if (*tmp) {
240 usage(mkswap_usage);
241 exit(1);
242 }
243 } else
244 device_name = argv[0];
245 else while (*++argv[0])
246 switch (argv[0][0]) {
247 case 'c': check=1; break;
248 default: usage(mkswap_usage);
249 exit(1);
250 }
251 }
252 return mkswap(device_name, pages, check);
253}
diff --git a/mnc.c b/mnc.c
new file mode 100644
index 000000000..9d59977da
--- /dev/null
+++ b/mnc.c
@@ -0,0 +1,148 @@
1/* mnc: mini-netcat - built from the ground up for LRP
2 Copyright (C) 1998 Charles P. Wright
3
4 0.0.1 6K It works.
5 0.0.2 5K Smaller and you can also check the exit condition if you wish.
6
7
8 19980918 Busy Boxed! Dave Cinege
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24*/
25#include "internal.h"
26#include <stdio.h>
27#include <stdlib.h>
28#include <unistd.h>
29
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <sys/time.h>
36#include <sys/ioctl.h>
37
38const char mnc_usage[] =
39"mini-netcat 0.0.1 -- Open pipe to IP:port\n"
40"\tmnc [IP] [port]\n";
41
42int
43mnc_main(struct FileInfo * i, int argc, char **argv)
44{
45
46 int sfd;
47 int result;
48 int len;
49 int pid;
50 char ch;
51
52 struct sockaddr_in address;
53 struct hostent *hostinfo;
54
55#ifdef SELECT
56 fd_set readfds, testfds;
57#endif
58
59 sfd = socket(AF_INET, SOCK_STREAM, 0);
60
61 hostinfo = (struct hostent *) gethostbyname(argv[1]);
62
63 if (!hostinfo)
64 {
65 exit(1);
66 }
67
68 address.sin_family = AF_INET;
69 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
70 address.sin_port = htons(atoi(argv[2]));
71
72 len = sizeof(address);
73
74 result = connect(sfd, (struct sockaddr *)&address, len);
75
76 if (result < 0)
77 {
78 exit(2);
79 }
80
81#ifdef SELECT
82 FD_ZERO(&readfds);
83 FD_SET(sfd, &readfds);
84 FD_SET(fileno(stdin), &readfds);
85
86 while(1)
87 {
88 int fd;
89 int nread;
90
91 testfds = readfds;
92
93 result = select(FD_SETSIZE, &testfds, (fd_set *) NULL, (fd_set *) NULL, (struct timeval *) 0);
94
95 if(result < 1)
96 {
97 exit(3);
98 }
99
100 for(fd = 0; fd < FD_SETSIZE; fd++)
101 {
102 if(FD_ISSET(fd,&testfds))
103 {
104 ioctl(fd, FIONREAD, &nread);
105
106 if (nread == 0)
107 exit(0);
108
109 if(fd == sfd)
110 {
111 read(sfd, &ch, 1);
112 write(fileno(stdout), &ch, 1);
113 }
114 else
115 {
116 read(fileno(stdin), &ch, 1);
117 write(sfd, &ch, 1);
118 }
119 }
120 }
121 }
122#else
123 pid = fork();
124
125 if (!pid)
126 {
127 int retval;
128 retval = 1;
129 while(retval == 1)
130 {
131 retval = read(fileno(stdin), &ch, 1);
132 write(sfd, &ch, 1);
133 }
134 }
135 else
136 {
137 int retval;
138 retval = 1;
139 while(retval == 1)
140 {
141 retval = read(sfd, &ch, 1);
142 write(fileno(stdout), &ch, 1);
143 }
144 }
145
146 exit(0);
147#endif
148}
diff --git a/monadic.c b/monadic.c
new file mode 100644
index 000000000..3c7fac25b
--- /dev/null
+++ b/monadic.c
@@ -0,0 +1,126 @@
1#include "internal.h"
2#include <stdio.h>
3#include <string.h>
4#include <grp.h>
5
6extern int
7monadic_main(
8 struct FileInfo * i
9,int argc
10,char * * argv)
11{
12 int status = 0;
13
14 while ( argc > 1 && argv[1][0] == '-' ) {
15 switch ( argv[1][1] ) {
16 case 'c':
17 i->create = 1;
18 break;
19 case 'f':
20 i->force = 1;
21 break;
22 case 'g':
23 if ( argc > 2 ) {
24 struct group * g;
25 if ( (g = getgrnam(argv[2])) == 0 ) {
26 fprintf(stderr, "%s: no such group.\n", argv[1]);
27 return 1;
28 }
29 i->groupID = g->gr_gid;
30 i->changeGroupID = 1;
31 i->complainInPostProcess = 1;
32 argc--;
33 argv++;
34 break;
35 }
36 usage(i->applet->usage);
37 return 1;
38 case 'm':
39 if ( argc > 2 ) {
40 status = parse_mode(
41 argv[2]
42 ,&i->orWithMode
43 ,&i->andWithMode, 0);
44
45 if ( status == 0 ) {
46 i->changeMode = 1;
47 i->complainInPostProcess = 1;
48 argc--;
49 argv++;
50 break;
51 }
52 }
53 usage(i->applet->usage);
54 return 1;
55 case 'o':
56 if ( argc > 2 ) {
57 status = parse_user_name(argv[2], i);
58 if ( status != 0 )
59 return status;
60
61 i->changeUserID = 1;
62 i->complainInPostProcess = 1;
63 argc--;
64 argv++;
65 break;
66 }
67 usage(i->applet->usage);
68 return 1;
69 case 'p':
70 i->makeParentDirectories = 1;
71 break;
72 case 'r':
73 case 'R':
74 i->recursive = 1;
75 break;
76 case 's':
77 i->makeSymbolicLink = 1;
78 break;
79 default:
80 usage(i->applet->usage);
81 return 1;
82 }
83 argv++;
84 argc--;
85 }
86 while ( argc > 1 ) {
87 char * slash;
88 i->source = argv[1];
89 if ( (slash = strrchr(i->source, '/')) != 0 ) {
90 i->directoryLength = slash - i->source;
91 if ( i->source[i->directoryLength] == '\0' )
92 i->directoryLength = 0;
93 }
94 else
95 i->directoryLength = 0;
96 if ( !i->dyadic )
97 i->destination = i->source;
98
99 if ( lstat(i->source, &i->stat) == 0 ) {
100 i->isSymbolicLink = (i->stat.st_mode & S_IFMT)==S_IFLNK;
101 if ( i->isSymbolicLink )
102 if ( stat(i->source, &i->stat) != 0 )
103 memset(&i->stat, 0, sizeof(i->stat));
104 }
105 else
106 memset(&i->stat, 0, sizeof(i->stat));
107
108 if ( i->isSymbolicLink
109 || !i->recursive
110 || ((i->stat.st_mode & S_IFMT) != S_IFDIR) ) {
111
112 if ( i->applet->function )
113 status = i->applet->function(i);
114 if ( status == 0 )
115 status = post_process(i);
116 }
117 else
118 status = descend(i, i->applet->function);
119
120 if ( status != 0 && !i->force )
121 return status;
122 argv++;
123 argc--;
124 }
125 return 0;
126}
diff --git a/more.c b/more.c
new file mode 100644
index 000000000..65409999b
--- /dev/null
+++ b/more.c
@@ -0,0 +1,110 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <sys/ioctl.h>
6#include <fcntl.h>
7
8#define BB_MORE_TERM
9
10#ifdef BB_MORE_TERM
11 #include <termios.h>
12 #include <signal.h>
13
14 FILE *cin;
15 struct termios initial_settings, new_settings;
16
17 void gotsig(int sig) {
18 tcsetattr(fileno(cin), TCSANOW, &initial_settings);
19 exit(0);
20 }
21#endif
22
23const char more_usage[] = "more [file]\n"
24"\n"
25"\tDisplays a file, one page at a time.\n"
26"\tIf there are no arguments, the standard input is displayed.\n";
27
28extern int
29more_fn(const struct FileInfo * i)
30{
31 FILE * f = stdin;
32 int c;
33 int lines = 0, tlines = 0;
34 int next_page = 0;
35 int rows = 24, cols = 79;
36#ifdef BB_MORE_TERM
37 long sizeb = 0;
38 struct stat st;
39 struct winsize win;
40#endif
41
42 if ( i ) {
43 if (! (f = fopen(i->source, "r") )) {
44 name_and_error(i->source);
45 return 1;
46 }
47 fstat(fileno(f), &st);
48 sizeb = st.st_size / 100;
49 }
50
51#ifdef BB_MORE_TERM
52 cin = fopen("/dev/tty", "r");
53 tcgetattr(fileno(cin),&initial_settings);
54 new_settings = initial_settings;
55 new_settings.c_lflag &= ~ICANON;
56 new_settings.c_lflag &= ~ECHO;
57 tcsetattr(fileno(cin), TCSANOW, &new_settings);
58
59 (void) signal(SIGINT, gotsig);
60
61 ioctl(STDOUT_FILENO, TIOCGWINSZ, &win);
62 if (win.ws_row > 4) rows = win.ws_row - 2;
63 if (win.ws_col > 0) cols = win.ws_col - 1;
64
65
66#endif
67
68 while ( (c = getc(f)) != EOF ) {
69 if ( next_page ) {
70 char garbage;
71 int len;
72 tlines += lines;
73 lines = 0;
74 next_page = 0; //Percentage is based on bytes, not lines.
75 if ( i && i->source ) //It is not very acurate, but still useful.
76 len = printf("%s - %%%2ld - line: %d", i->source, (ftell(f) - sizeb - sizeb) / sizeb, tlines);
77 else
78 len = printf("line: %d", tlines);
79
80 fflush(stdout);
81#ifndef BB_MORE_TERM
82 read(2, &garbage, 1);
83#else
84 do {
85 fread(&garbage, 1, 1, cin);
86 } while ((garbage != ' ') && (garbage != '\n'));
87
88 if (garbage == '\n') {
89 lines = rows;
90 tlines -= rows;
91 }
92 garbage = 0;
93 //clear line, since tabs don't overwrite.
94 while(len-- > 0) putchar('\b');
95 while(len++ < cols) putchar(' ');
96 while(len-- > 0) putchar('\b');
97 fflush(stdout);
98#endif
99 }
100 putchar(c);
101 if ( c == '\n' && ++lines == (rows + 1) )
102 next_page = 1;
103 }
104 if ( f != stdin )
105 fclose(f);
106#ifdef BB_MORE_TERM
107 gotsig(0);
108#endif
109 return 0;
110}
diff --git a/mount.c b/mount.c
new file mode 100644
index 000000000..010757d1e
--- /dev/null
+++ b/mount.c
@@ -0,0 +1,430 @@
1/*
2 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
3 searches through fstab when -a is passed
4 will try mounting stuff with all fses when passed -t auto
5
6 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
7*/
8
9#include "internal.h"
10#include <stdlib.h>
11#include <unistd.h>
12#include <errno.h>
13#include <string.h>
14#include <stdio.h>
15#include <mntent.h>
16#include <sys/mount.h>
17#include <ctype.h>
18
19const char mount_usage[] = "mount\n"
20"\t\tmount [flags] special-device directory\n"
21"\n"
22"Flags:\n"
23"\t-a:\tMount all file systems in fstab.\n"
24"\t-f:\t\"Fake\" mount. Add entry to mount table but don't mount it.\n"
25"\t-n:\tDon't write a mount table entry.\n"
26"\t-o option:\tOne of many filesystem options, listed below.\n"
27"\t-r:\tMount the filesystem read-only.\n"
28"\t-t filesystem-type:\tSpecify the filesystem type.\n"
29"\t-w:\tMount for reading and writing (default).\n"
30"\n"
31"Options for use with the \"-o\" flag:\n"
32"\tasync / sync:\tWrites are asynchronous / synchronous.\n"
33"\tdev / nodev:\tAllow use of special device files / disallow them.\n"
34"\texec / noexec:\tAllow use of executable files / disallow them.\n"
35"\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n"
36"\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n"
37"\tro / rw: Mount for read-only / read-write.\n"
38"\t"
39"There are EVEN MORE flags that are specific to each filesystem.\n"
40"You'll have to see the written documentation for those.\n";
41
42struct mount_options {
43 const char * name;
44 unsigned long and;
45 unsigned long or;
46};
47
48static const struct mount_options mount_options[] = {
49 { "async", ~MS_SYNCHRONOUS,0 },
50 { "defaults", ~0, 0 },
51 { "dev", ~MS_NODEV, 0 },
52 { "exec", ~MS_NOEXEC, 0 },
53 { "nodev", ~0, MS_NODEV },
54 { "noexec", ~0, MS_NOEXEC },
55 { "nosuid", ~0, MS_NOSUID },
56 { "remount", ~0, MS_REMOUNT },
57 { "ro", ~0, MS_RDONLY },
58 { "rw", ~MS_RDONLY, 0 },
59 { "suid", ~MS_NOSUID, 0 },
60 { "sync", ~0, MS_SYNCHRONOUS },
61 { 0, 0, 0 }
62};
63
64static void
65show_flags(unsigned long flags, char * buffer)
66{
67 const struct mount_options * f = mount_options;
68 while ( f->name ) {
69 if ( flags & f->and ) {
70 int length = strlen(f->name);
71 memcpy(buffer, f->name, length);
72 buffer += length;
73 *buffer++ = ',';
74 *buffer = '\0';
75 }
76 f++;
77 }
78}
79
80static void
81one_option(
82 char * option
83,unsigned long * flags
84,char * data)
85{
86 const struct mount_options * f = mount_options;
87
88 while ( f->name != 0 ) {
89 if ( strcasecmp(f->name, option) == 0 ) {
90 *flags &= f->and;
91 *flags |= f->or;
92 return;
93 }
94 f++;
95 }
96 if ( *data ) {
97 data += strlen(data);
98 *data++ = ',';
99 }
100 strcpy(data, option);
101}
102
103static void
104parse_mount_options(
105 char * options
106,unsigned long * flags
107,char * data)
108{
109 while ( *options ) {
110 char * comma = strchr(options, ',');
111 if ( comma )
112 *comma = '\0';
113 one_option(options, flags, data);
114 if ( comma ) {
115 *comma = ',';
116 options = ++comma;
117 }
118 else
119 break;
120 }
121}
122
123int
124mount_one(
125 char * blockDevice
126,char * directory
127,char * filesystemType
128,unsigned long flags
129,char * string_flags
130,int noMtab
131,int fake)
132{
133 int error = 0;
134 int status = 0;
135
136 char buf[255];
137
138 if (!fake) {
139 if (*filesystemType == 'a') { //Will fail on real FS starting with 'a'
140
141 FILE *f = fopen("/proc/filesystems", "r");
142
143 if (f == NULL) return 1;
144
145 while (fgets(buf, sizeof(buf), f) != NULL) {
146 filesystemType = buf;
147 if (*filesystemType == '\t') { // Not a nodev filesystem
148
149 while (*filesystemType && *filesystemType != '\n') filesystemType++;
150 *filesystemType = '\0';
151
152 filesystemType = buf;
153 filesystemType++; //hop past tab
154
155 status = mount(blockDevice, directory, filesystemType,
156 flags|MS_MGC_VAL ,string_flags);
157 error = errno;
158
159 if (status == 0) break;
160 }
161 }
162 fclose(f);
163 } else {
164
165 status = mount( blockDevice, directory, filesystemType,
166 flags|MS_MGC_VAL ,string_flags);
167 error = errno;
168 }
169 }
170
171 if ( status == 0 ) {
172 char * s = &string_flags[strlen(string_flags)];
173 FILE * mountTable;
174 if ( s != string_flags ) {
175 *s++ = ',';
176 show_flags(flags, s);
177 }
178 if ( !noMtab && (mountTable = setmntent("/etc/mtab", "a+")) ) {
179 int length = strlen(directory);
180 struct mntent m;
181
182 if ( length > 1 && directory[length - 1] == '/' )
183 directory[length - 1] = '\0';
184
185 if ( filesystemType == 0 ) {
186 struct mntent * p
187 = findMountPoint(blockDevice, "/proc/mounts");
188
189 if ( p && p->mnt_type )
190 filesystemType = p->mnt_type;
191 }
192 m.mnt_fsname = blockDevice;
193 m.mnt_dir = directory;
194 m.mnt_type = filesystemType ? filesystemType : "default";
195
196 if (*string_flags) {
197 m.mnt_opts = string_flags;
198 } else {
199 if ( (flags | MS_RDONLY) == flags )
200 m.mnt_opts = "ro";
201 else
202 m.mnt_opts = "rw";
203 }
204
205 m.mnt_freq = 0;
206 m.mnt_passno = 0;
207 addmntent(mountTable, &m);
208 endmntent(mountTable);
209 }
210 return 0;
211 } else {
212 fprintf(stderr, "Mount %s", blockDevice);
213 if ( filesystemType && *filesystemType )
214 fprintf(stderr, " (type %s)", filesystemType);
215
216 fprintf(
217 stderr
218 ," on %s: "
219 ,directory);
220
221 switch ( error ) {
222 case EPERM:
223 if (geteuid() == 0)
224 fprintf(
225 stderr
226 ,"mount point %s is not a directory"
227 ,blockDevice);
228 else
229 fprintf(
230 stderr
231 ,"must be superuser to use mount");
232 break;
233 case EBUSY:
234 fprintf(
235 stderr
236 ,"%s already mounted or %s busy"
237 ,blockDevice
238 ,directory);
239 break;
240 case ENOENT:
241 {
242 struct stat statbuf;
243 if ( stat(directory, &statbuf) != 0 )
244 fprintf(
245 stderr
246 ,"directory %s does not exist"
247 ,directory);
248 else if ( stat(blockDevice, &statbuf) != 0 )
249 fprintf(
250 stderr
251 ,"block device %s does not exist"
252 ,blockDevice);
253 else
254 fprintf(
255 stderr
256 ,"%s is not mounted on %s, but the mount table says it is."
257 ,blockDevice
258 ,directory);
259 break;
260 }
261 case ENOTDIR:
262 fprintf(
263 stderr
264 ,"%s is not a directory"
265 ,directory);
266 break;
267 case EINVAL:
268 fprintf(
269 stderr
270 ,"wrong filesystem type, or bad superblock on %s"
271 ,blockDevice);
272 break;
273 case EMFILE:
274 fprintf(stderr, "mount table full");
275 break;
276 case EIO:
277 fprintf(
278 stderr
279 ,"I/O error reading %s"
280 ,blockDevice);
281 break;
282 case ENODEV:
283 {
284 FILE * f = fopen("/proc/filesystems", "r");
285
286 fprintf(
287 stderr
288 ,"filesystem type %s not in kernel.\n"
289 ,filesystemType);
290 fprintf(stderr, "Do you need to load a module?\n");
291 if ( f ) {
292 char buf[100];
293
294 fprintf(
295 stderr
296 ,"Here are the filesystem types the kernel"
297 " can mount:\n");
298 while ( fgets(buf, sizeof(buf), f) != 0 )
299 fprintf(stderr, "\t%s", buf);
300 fclose(f);
301 }
302 break;
303 }
304 case ENOTBLK:
305 fprintf(
306 stderr
307 ,"%s is not a block device"
308 ,blockDevice);
309 break;
310 case ENXIO:
311 fprintf(
312 stderr
313 ,"%s is not a valid block device"
314 ,blockDevice);
315 break;
316 default:
317 fputs(strerror(errno), stderr);
318 }
319 putc('\n', stderr);
320 return -1;
321 }
322}
323
324extern int
325mount_main(struct FileInfo * i, int argc, char * * argv)
326{
327 char string_flags[1024];
328 unsigned long flags = 0;
329 char * filesystemType = "auto";
330 int fake = 0;
331 int noMtab = 0;
332 int all = 0;
333
334 *string_flags = '\0';
335
336 if ( argc == 1 ) {
337 FILE * mountTable;
338 if ( (mountTable = setmntent("/etc/mtab", "r")) ) {
339 struct mntent * m;
340 while ( (m = getmntent(mountTable)) != 0 ) {
341 printf(
342 "%s on %s type %s (%s)\n"
343 ,m->mnt_fsname
344 ,m->mnt_dir
345 ,m->mnt_type
346 ,m->mnt_opts);
347 }
348 endmntent(mountTable);
349 }
350 return 0;
351 }
352
353 while ( argc >= 2 && argv[1][0] == '-' ) {
354 switch ( argv[1][1] ) {
355 case 'f':
356 fake = 1;
357 break;
358 case 'n':
359 noMtab = 1;
360 break;
361 case 'o':
362 if ( argc < 3 ) {
363 usage(mount_usage);
364 return 1;
365 }
366 parse_mount_options(argv[2], &flags, string_flags);
367 argc--;
368 argv++;
369 break;
370 case 'r':
371 flags |= MS_RDONLY;
372 break;
373 case 't':
374 if ( argc < 3 ) {
375 usage(mount_usage);
376 return 1;
377 }
378 filesystemType = argv[2];
379 argc--;
380 argv++;
381 break;
382 case 'v':
383 break;
384 case 'w':
385 flags &= ~MS_RDONLY;
386 break;
387 case 'a':
388 all = 1;
389 break;
390 default:
391 usage(mount_usage);
392 return 1;
393 }
394 argc--;
395 argv++;
396 }
397
398 if (all == 1) {
399 struct mntent *m;
400 FILE *f = setmntent("/etc/fstab", "r");
401
402 if (f == NULL) {
403 return 1;
404 }
405
406 // FIXME: Combine read routine (make new function) with unmount_all to save space.
407
408 while ((m = getmntent(f)) != NULL) {
409 // If the file system isn't noauto, and isn't mounted on /, mount it
410 if ((!strstr(m->mnt_opts, "noauto")) && (m->mnt_dir[1] != '\0')
411 && !((m->mnt_type[0] == 's') && (m->mnt_type[1] == 'w'))
412 && !((m->mnt_type[0] == 'n') && (m->mnt_type[1] == 'f'))) {
413 mount_one(m->mnt_fsname, m->mnt_dir, m->mnt_type, flags, m->mnt_opts, noMtab, fake);
414 }
415 }
416
417 endmntent(f);
418 } else {
419 if ( argc >= 3 ) {
420 if ( mount_one( argv[1], argv[2], filesystemType, flags, string_flags, noMtab, fake) == 0 )
421 return 0;
422 else
423 return 1;
424 } else {
425 usage(mount_usage);
426 return 1;
427 }
428 }
429 return 0;
430}
diff --git a/mt.c b/mt.c
new file mode 100644
index 000000000..7d75fbd3d
--- /dev/null
+++ b/mt.c
@@ -0,0 +1,98 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/mtio.h>
4#include <sys/fcntl.h>
5
6const char mt_usage[] = "mt [-f device] opcode value\n";
7
8struct mt_opcodes {
9 char * name;
10 short value;
11};
12
13/* missing: eod/seod, stoptions, stwrthreshold, densities */
14static const struct mt_opcodes opcodes[] = {
15 { "bsf", MTBSF },
16 { "bsfm", MTBSFM },
17 { "bsr", MTBSR },
18 { "bss", MTBSS },
19 { "datacompression", MTCOMPRESSION },
20 { "eom", MTEOM },
21 { "erase", MTERASE },
22 { "fsf", MTFSF },
23 { "fsfm", MTFSFM },
24 { "fsr", MTFSR },
25 { "fss", MTFSS },
26 { "load", MTLOAD },
27 { "lock", MTLOCK },
28 { "mkpart", MTMKPART },
29 { "nop", MTNOP },
30 { "offline",MTOFFL },
31 { "rewoffline",MTOFFL },
32 { "ras1", MTRAS1 },
33 { "ras2", MTRAS2 },
34 { "ras3", MTRAS3 },
35 { "reset", MTRESET },
36 { "retension", MTRETEN },
37 { "rew", MTREW },
38 { "seek", MTSEEK },
39 { "setblk", MTSETBLK },
40 { "setdensity", MTSETDENSITY },
41 { "drvbuffer", MTSETDRVBUFFER },
42 { "setpart", MTSETPART },
43 { "tell", MTTELL },
44 { "wset", MTWSM },
45 { "unload", MTUNLOAD },
46 { "unlock", MTUNLOCK },
47 { "eof", MTWEOF },
48 { "weof", MTWEOF },
49 { 0, 0 }
50};
51
52extern int
53mt_main(struct FileInfo * i, int argc, char * * argv)
54{
55 const char * file = "/dev/tape";
56 const struct mt_opcodes * code = opcodes;
57 struct mtop op;
58 int fd;
59
60 if ( strcmp(argv[1], "-f") == 0 ) {
61 if ( argc < 4 ) {
62 usage(mt_usage);
63 return 1;
64 }
65 file = argv[2];
66 argv += 2;
67 argc -= 2;
68 }
69
70 while ( code->name != 0 ) {
71 if ( strcmp(code->name, argv[1]) == 0 )
72 break;
73 code++;
74 }
75
76 if ( code->name == 0 ) {
77 fprintf(stderr, "mt: unrecognized opcode %s.\n", argv[1]);
78 return 1;
79 }
80
81 op.mt_op = code->value;
82 if ( argc >= 3 )
83 op.mt_count = atoi(argv[2]);
84 else
85 op.mt_count = 1; /* One, not zero, right? */
86
87 if ( (fd = open(file, O_RDONLY, 0)) < 0 ) {
88 name_and_error(file);
89 return 1;
90 }
91
92 if ( ioctl(fd, MTIOCTOP, &op) != 0 ) {
93 name_and_error(file);
94 return 1;
95 }
96
97 return 0;
98}
diff --git a/mv.c b/mv.c
new file mode 100644
index 000000000..22c4a1207
--- /dev/null
+++ b/mv.c
@@ -0,0 +1,38 @@
1#include "internal.h"
2#include <stdio.h>
3#include <errno.h>
4
5const char mv_usage[] = "mv source-file destination-file\n"
6"\t\tmv source-file [source-file ...] destination-directory\n"
7"\n"
8"\tMove the source files to the destination.\n"
9"\n";
10
11extern int
12mv_fn(const struct FileInfo * i)
13{
14 struct stat destination_stat;
15 char d[1024];
16 struct FileInfo n;
17
18 if ( stat(i->destination, &destination_stat) == 0 ) {
19 if ( i->stat.st_ino == destination_stat.st_ino
20 && i->stat.st_dev == destination_stat.st_dev )
21 return 0; /* Move file to itself. */
22 }
23 if ( (destination_stat.st_mode & S_IFMT) == S_IFDIR ) {
24 n = *i;
25 n.destination = join_paths(d, i->destination, basename(i->source));
26 i = &n;
27 }
28 if ( rename(i->source, i->destination) == 0 )
29 return 0;
30 else if ( errno == EXDEV && is_a_directory(i->source) ) {
31 fprintf(stderr
32 ,"%s: Can't move directory across filesystems.\n"
33 ,i->source);
34 return 1;
35 }
36 else
37 return cp_fn(i);
38}
diff --git a/postprocess.c b/postprocess.c
new file mode 100644
index 000000000..bbc87e689
--- /dev/null
+++ b/postprocess.c
@@ -0,0 +1,41 @@
1#include "internal.h"
2
3extern int
4post_process(const struct FileInfo * i)
5{
6 int status = 0;
7
8 if ( i->destination == 0 || *i->destination == 0 )
9 return 0;
10
11 if ( status == 0 && i->changeMode ) {
12 mode_t mode = i->stat.st_mode & 07777;
13 mode &= i->andWithMode;
14 mode |= i->orWithMode;
15 status = chmod(i->destination, mode);
16
17 if ( status != 0 && i->complainInPostProcess && !i->force ) {
18 name_and_error(i->destination);
19 return 1;
20 }
21 }
22
23 if ( i->changeUserID || i->changeGroupID ) {
24 uid_t uid = i->stat.st_uid;
25 gid_t gid = i->stat.st_gid;
26
27 if ( i->changeUserID )
28 uid = i->userID;
29 if ( i->changeGroupID )
30 gid = i->groupID;
31
32 status = chown(i->destination, uid, gid);
33
34 if ( status != 0 && i->complainInPostProcess && !i->force ) {
35 name_and_error(i->destination);
36 return 1;
37 }
38 }
39
40 return status;
41}
diff --git a/printf.c b/printf.c
new file mode 100644
index 000000000..e79843c80
--- /dev/null
+++ b/printf.c
@@ -0,0 +1,531 @@
1// I may still need some more cleaning...fix my error checking
2
3#include "internal.h"
4#ifdef BB_PRINTF
5
6/* printf - format and print data
7 Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23/* Usage: printf format [argument...]
24
25 A front end to the printf function that lets it be used from the shell.
26
27 Backslash escapes:
28
29 \" = double quote
30 \\ = backslash
31 \a = alert (bell)
32 \b = backspace
33 \c = produce no further output
34 \f = form feed
35 \n = new line
36 \r = carriage return
37 \t = horizontal tab
38 \v = vertical tab
39 \0ooo = octal number (ooo is 0 to 3 digits)
40 \xhhh = hexadecimal number (hhh is 1 to 3 digits)
41
42 Additional directive:
43
44 %b = print an argument string, interpreting backslash escapes
45
46 The `format' argument is re-used as many times as necessary
47 to convert all of the given arguments.
48
49 David MacKenzie <djm@gnu.ai.mit.edu> */
50
51
52// 19990508 Busy Boxed! Dave Cinege
53
54#include <unistd.h>
55#include <stdio.h>
56#include <sys/types.h>
57#include <getopt.h>
58#include <sys/stat.h>
59#include <string.h>
60#include <errno.h>
61#include <stdlib.h>
62#include <fcntl.h>
63#include <ctype.h>
64#include <libintl.h>
65
66
67#ifndef S_IFMT
68# define S_IFMT 0170000
69#endif
70#if !defined(S_ISBLK) && defined(S_IFBLK)
71# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
72#endif
73#if !defined(S_ISCHR) && defined(S_IFCHR)
74# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
75#endif
76#if !defined(S_ISDIR) && defined(S_IFDIR)
77# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
78#endif
79#if !defined(S_ISREG) && defined(S_IFREG)
80# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
81#endif
82#if !defined(S_ISFIFO) && defined(S_IFIFO)
83# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
84#endif
85#if !defined(S_ISLNK) && defined(S_IFLNK)
86# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
87#endif
88#if !defined(S_ISSOCK) && defined(S_IFSOCK)
89# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
90#endif
91#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
92# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
93# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
94#endif
95#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
96# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
97#endif
98
99#define IN_CTYPE_DOMAIN(c) 1
100
101#ifdef isblank
102# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c))
103#else
104# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
105#endif
106#ifdef isgraph
107# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c))
108#else
109# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c))
110#endif
111
112#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
113#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c))
114#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
115#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
116#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
117#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c))
118#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
119#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
120#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
121#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
122#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
123
124#define isodigit(c) ((c) >= '0' && (c) <= '7')
125#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
126#define octtobin(c) ((c) - '0')
127
128char *xmalloc ();
129
130static double xstrtod __P ((char *s));
131static int print_esc __P ((char *escstart));
132static int print_formatted __P ((char *format, int argc, char **argv));
133static long xstrtol __P ((char *s));
134static unsigned long xstrtoul __P ((char *s));
135static void print_direc __P ((char *start, size_t length, int field_width, int precision, char *argument));
136static void print_esc_char __P ((int c));
137static void print_esc_string __P ((char *str));
138static void verify __P ((char *s, char *end));
139
140/* The value to return to the calling program. */
141static int exit_status;
142
143const char printf_usage[] = "Usage: printf format [argument...]\n";
144
145int
146printf_main(struct FileInfo * i, int argc, char * * argv)
147{
148 char *format;
149 int args_used;
150
151 exit_status = 0;
152
153 format = argv[1];
154 argc -= 2;
155 argv += 2;
156
157 do
158 {
159 args_used = print_formatted (format, argc, argv);
160 argc -= args_used;
161 argv += args_used;
162 }
163 while (args_used > 0 && argc > 0);
164
165/*
166 if (argc > 0)
167 fprintf(stderr, "excess args ignored");
168*/
169
170 exit (exit_status);
171}
172
173/* Print the text in FORMAT, using ARGV (with ARGC elements) for
174 arguments to any `%' directives.
175 Return the number of elements of ARGV used. */
176
177static int
178print_formatted (char *format, int argc, char **argv)
179{
180 int save_argc = argc; /* Preserve original value. */
181 char *f; /* Pointer into `format'. */
182 char *direc_start; /* Start of % directive. */
183 size_t direc_length; /* Length of % directive. */
184 int field_width; /* Arg to first '*', or -1 if none. */
185 int precision; /* Arg to second '*', or -1 if none. */
186
187 for (f = format; *f; ++f)
188 {
189 switch (*f)
190 {
191 case '%':
192 direc_start = f++;
193 direc_length = 1;
194 field_width = precision = -1;
195 if (*f == '%')
196 {
197 putchar ('%');
198 break;
199 }
200 if (*f == 'b')
201 {
202 if (argc > 0)
203 {
204 print_esc_string (*argv);
205 ++argv;
206 --argc;
207 }
208 break;
209 }
210 if (strchr ("-+ #", *f))
211 {
212 ++f;
213 ++direc_length;
214 }
215 if (*f == '*')
216 {
217 ++f;
218 ++direc_length;
219 if (argc > 0)
220 {
221 field_width = xstrtoul (*argv);
222 ++argv;
223 --argc;
224 }
225 else
226 field_width = 0;
227 }
228 else
229 while (ISDIGIT (*f))
230 {
231 ++f;
232 ++direc_length;
233 }
234 if (*f == '.')
235 {
236 ++f;
237 ++direc_length;
238 if (*f == '*')
239 {
240 ++f;
241 ++direc_length;
242 if (argc > 0)
243 {
244 precision = xstrtoul (*argv);
245 ++argv;
246 --argc;
247 }
248 else
249 precision = 0;
250 }
251 else
252 while (ISDIGIT (*f))
253 {
254 ++f;
255 ++direc_length;
256 }
257 }
258 if (*f == 'l' || *f == 'L' || *f == 'h')
259 {
260 ++f;
261 ++direc_length;
262 }
263 /*
264 if (!strchr ("diouxXfeEgGcs", *f))
265 fprintf(stderr, "%%%c: invalid directive", *f);
266 */
267 ++direc_length;
268 if (argc > 0)
269 {
270 print_direc (direc_start, direc_length, field_width,
271 precision, *argv);
272 ++argv;
273 --argc;
274 }
275 else
276 print_direc (direc_start, direc_length, field_width,
277 precision, "");
278 break;
279
280 case '\\':
281 f += print_esc (f);
282 break;
283
284 default:
285 putchar (*f);
286 }
287 }
288
289 return save_argc - argc;
290}
291
292/* Print a \ escape sequence starting at ESCSTART.
293 Return the number of characters in the escape sequence
294 besides the backslash. */
295
296static int
297print_esc (char *escstart)
298{
299 register char *p = escstart + 1;
300 int esc_value = 0; /* Value of \nnn escape. */
301 int esc_length; /* Length of \nnn escape. */
302
303 /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
304 if (*p == 'x')
305 {
306 for (esc_length = 0, ++p;
307 esc_length < 3 && ISXDIGIT (*p);
308 ++esc_length, ++p)
309 esc_value = esc_value * 16 + hextobin (*p);
310/* if (esc_length == 0)
311 fprintf(stderr, "missing hex in esc");
312*/
313 putchar (esc_value);
314 }
315 else if (*p == '0')
316 {
317 for (esc_length = 0, ++p;
318 esc_length < 3 && isodigit (*p);
319 ++esc_length, ++p)
320 esc_value = esc_value * 8 + octtobin (*p);
321 putchar (esc_value);
322 }
323 else if (strchr ("\"\\abcfnrtv", *p))
324 print_esc_char (*p++);
325/* else
326 fprintf(stderr, "\\%c: invalid esc", *p);
327*/
328 return p - escstart - 1;
329}
330
331/* Output a single-character \ escape. */
332
333static void
334print_esc_char (int c)
335{
336 switch (c)
337 {
338 case 'a': /* Alert. */
339 putchar (7);
340 break;
341 case 'b': /* Backspace. */
342 putchar (8);
343 break;
344 case 'c': /* Cancel the rest of the output. */
345 exit (0);
346 break;
347 case 'f': /* Form feed. */
348 putchar (12);
349 break;
350 case 'n': /* New line. */
351 putchar (10);
352 break;
353 case 'r': /* Carriage return. */
354 putchar (13);
355 break;
356 case 't': /* Horizontal tab. */
357 putchar (9);
358 break;
359 case 'v': /* Vertical tab. */
360 putchar (11);
361 break;
362 default:
363 putchar (c);
364 break;
365 }
366}
367
368/* Print string STR, evaluating \ escapes. */
369
370static void
371print_esc_string (char *str)
372{
373 for (; *str; str++)
374 if (*str == '\\')
375 str += print_esc (str);
376 else
377 putchar (*str);
378}
379
380static void
381print_direc (char *start, size_t length, int field_width, int precision, char *argument)
382{
383 char *p; /* Null-terminated copy of % directive. */
384
385 p = xmalloc ((unsigned) (length + 1));
386 strncpy (p, start, length);
387 p[length] = 0;
388
389 switch (p[length - 1])
390 {
391 case 'd':
392 case 'i':
393 if (field_width < 0)
394 {
395 if (precision < 0)
396 printf (p, xstrtol (argument));
397 else
398 printf (p, precision, xstrtol (argument));
399 }
400 else
401 {
402 if (precision < 0)
403 printf (p, field_width, xstrtol (argument));
404 else
405 printf (p, field_width, precision, xstrtol (argument));
406 }
407 break;
408
409 case 'o':
410 case 'u':
411 case 'x':
412 case 'X':
413 if (field_width < 0)
414 {
415 if (precision < 0)
416 printf (p, xstrtoul (argument));
417 else
418 printf (p, precision, xstrtoul (argument));
419 }
420 else
421 {
422 if (precision < 0)
423 printf (p, field_width, xstrtoul (argument));
424 else
425 printf (p, field_width, precision, xstrtoul (argument));
426 }
427 break;
428
429 case 'f':
430 case 'e':
431 case 'E':
432 case 'g':
433 case 'G':
434 if (field_width < 0)
435 {
436 if (precision < 0)
437 printf (p, xstrtod (argument));
438 else
439 printf (p, precision, xstrtod (argument));
440 }
441 else
442 {
443 if (precision < 0)
444 printf (p, field_width, xstrtod (argument));
445 else
446 printf (p, field_width, precision, xstrtod (argument));
447 }
448 break;
449
450 case 'c':
451 printf (p, *argument);
452 break;
453
454 case 's':
455 if (field_width < 0)
456 {
457 if (precision < 0)
458 printf (p, argument);
459 else
460 printf (p, precision, argument);
461 }
462 else
463 {
464 if (precision < 0)
465 printf (p, field_width, argument);
466 else
467 printf (p, field_width, precision, argument);
468 }
469 break;
470 }
471
472 free (p);
473}
474
475static unsigned long
476xstrtoul (char *s)
477{
478 char *end;
479 unsigned long val;
480
481 errno = 0;
482 val = strtoul (s, &end, 0);
483 verify (s, end);
484 return val;
485}
486
487static long
488xstrtol (char *s)
489{
490 char *end;
491 long val;
492
493 errno = 0;
494 val = strtol (s, &end, 0);
495 verify (s, end);
496 return val;
497}
498
499static double
500xstrtod (char *s)
501{
502 char *end;
503 double val;
504
505 errno = 0;
506 val = strtod (s, &end);
507 verify (s, end);
508 return val;
509}
510
511static void
512verify (char *s, char *end)
513{
514 if (errno)
515 {
516 fprintf(stderr, "%s", s);
517 exit_status = 1;
518 }
519 else if (*end)
520 {
521 /*
522 if (s == end)
523 fprintf(stderr, "%s: expected numeric", s);
524 else
525 fprintf(stderr, "%s: not completely converted", s);
526 */
527 exit_status = 1;
528 }
529}
530
531#endif
diff --git a/procps/kill.c b/procps/kill.c
new file mode 100644
index 000000000..da025fafc
--- /dev/null
+++ b/procps/kill.c
@@ -0,0 +1,140 @@
1#include "internal.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <signal.h>
6
7const char kill_usage[] = "kill [-signal] process-id [process-id ...]\n";
8
9struct signal_name {
10 const char * name;
11 int number;
12};
13
14const struct signal_name signames[] = {
15 { "HUP", SIGHUP },
16 { "INT", SIGINT },
17 { "QUIT", SIGQUIT },
18 { "ILL", SIGILL },
19 { "TRAP", SIGTRAP },
20 { "ABRT", SIGABRT },
21#ifndef __alpha__
22 { "IOT", SIGIOT },
23#endif
24#if defined(sparc) || defined(__alpha__)
25 { "EMT", SIGEMT },
26#else
27 { "BUS", SIGBUS },
28#endif
29 { "FPE", SIGFPE },
30 { "KILL", SIGKILL },
31#if defined(sparc) || defined(__alpha__)
32 { "BUS", SIGBUS },
33#else
34 { "USR1", SIGUSR1 },
35#endif
36 { "SEGV", SIGSEGV },
37#if defined(sparc) || defined(__alpha__)
38 { "SYS", SIGSYS },
39#else
40 { "USR2", SIGUSR2 },
41#endif
42 { "PIPE", SIGPIPE },
43 { "ALRM", SIGALRM },
44 { "TERM", SIGTERM },
45#if defined(sparc) || defined(__alpha__)
46 { "URG", SIGURG },
47 { "STOP", SIGSTOP },
48 { "TSTP", SIGTSTP },
49 { "CONT", SIGCONT },
50 { "CHLD", SIGCHLD },
51 { "TTIN", SIGTTIN },
52 { "TTOU", SIGTTOU },
53 { "IO", SIGIO },
54# ifndef __alpha__
55 { "POLL", SIGIO },
56# endif
57 { "XCPU", SIGXCPU },
58 { "XFSZ", SIGXFSZ },
59 { "VTALRM", SIGVTALRM },
60 { "PROF", SIGPROF },
61 { "WINCH", SIGWINCH },
62# ifdef __alpha__
63 { "INFO", SIGINFO },
64# else
65 { "LOST", SIGLOST },
66# endif
67 { "USR1", SIGUSR1 },
68 { "USR2", SIGUSR2 },
69#else
70 { "STKFLT", SIGSTKFLT },
71 { "CHLD", SIGCHLD },
72 { "CONT", SIGCONT },
73 { "STOP", SIGSTOP },
74 { "TSTP", SIGTSTP },
75 { "TTIN", SIGTTIN },
76 { "TTOU", SIGTTOU },
77 { "URG", SIGURG },
78 { "XCPU", SIGXCPU },
79 { "XFSZ", SIGXFSZ },
80 { "VTALRM", SIGVTALRM },
81 { "PROF", SIGPROF },
82 { "WINCH", SIGWINCH },
83 { "IO", SIGIO },
84 { "POLL", SIGPOLL },
85 { "PWR", SIGPWR },
86 { "UNUSED", SIGUNUSED },
87#endif
88 { 0, 0 }
89};
90
91extern int
92kill_main(struct FileInfo * i, int argc, char * * argv)
93{
94 int had_error = 0;
95 int sig = SIGTERM;
96 if ( argv[1][0] == '-' ) {
97 if ( argv[1][1] >= '0' && argv[1][1] <= '9' ) {
98 sig = atoi(&argv[1][1]);
99 if ( sig < 0 || sig >= NSIG ) {
100 usage(kill_usage);
101 exit(-1);
102 }
103 }
104 else {
105 const struct signal_name * s = signames;
106 for ( ; ; ) {
107 if ( strcmp(s->name, &argv[1][1]) == 0 ) {
108 sig = s->number;
109 break;
110 }
111 s++;
112 if ( s->name == 0 ) {
113 usage(kill_usage);
114 exit(-1);
115 }
116 }
117 }
118 argv++;
119 argc--;
120
121 }
122 while ( argc > 1 ) {
123 int pid;
124 if ( argv[1][0] < '0' || argv[1][0] > '9' ) {
125 usage(kill_usage);
126 exit(-1);
127 }
128 pid = atoi(argv[1]);
129 if ( kill(pid, sig) != 0 ) {
130 had_error = 1;
131 perror(argv[1]);
132 }
133 argv++;
134 argc--;
135 }
136 if ( had_error )
137 return -1;
138 else
139 return 0;
140}
diff --git a/pwd.c b/pwd.c
new file mode 100644
index 000000000..d9ab54e48
--- /dev/null
+++ b/pwd.c
@@ -0,0 +1,18 @@
1#include "internal.h"
2#include <stdio.h>
3
4const char pwd_usage[] = "Print the current directory.\n";
5
6extern int
7pwd_main(struct FileInfo * i, int argc, char * * argv)
8{
9 char buf[1024];
10
11 if ( getcwd(buf, sizeof(buf)) == NULL ) {
12 name_and_error("get working directory");
13 return 1;
14 }
15
16 printf("%s\n", buf);
17 return 0;
18}
diff --git a/reboot.c b/reboot.c
new file mode 100644
index 000000000..0388fbce7
--- /dev/null
+++ b/reboot.c
@@ -0,0 +1,12 @@
1#include "internal.h"
2#include <signal.h>
3
4const char reboot_usage[] = "reboot\n"
5"\n\t"
6"\treboot the system.\n";
7
8extern int
9reboot_main(struct FileInfo * i, int argc, char * * argv)
10{
11 return kill(1, SIGUSR2);
12}
diff --git a/rm.c b/rm.c
new file mode 100644
index 000000000..dc35b0297
--- /dev/null
+++ b/rm.c
@@ -0,0 +1,30 @@
1#include "internal.h"
2#include <errno.h>
3
4const char rm_usage[] = "rm [-r] file [file ...]\n"
5"\n"
6"\tDelete files.\n"
7"\n"
8"\t-r:\tRecursively remove files and directories.\n";
9
10extern int
11rm_main(struct FileInfo * i, int argc, char * * argv)
12{
13 i->processDirectoriesAfterTheirContents = 1;
14 return monadic_main(i, argc, argv);
15}
16
17extern int
18rm_fn(const struct FileInfo * i)
19{
20 if ( i->recursive
21 && !i->isSymbolicLink
22 && (i->stat.st_mode & S_IFMT) == S_IFDIR )
23 return rmdir_fn(i);
24 else if ( unlink(i->source) != 0 && errno != ENOENT && !i->force ) {
25 name_and_error(i->source);
26 return 1;
27 }
28 else
29 return 0;
30}
diff --git a/rmdir.c b/rmdir.c
new file mode 100644
index 000000000..069e68546
--- /dev/null
+++ b/rmdir.c
@@ -0,0 +1,17 @@
1#include "internal.h"
2#include <errno.h>
3
4const char rmdir_usage[] = "rmdir directory [directory ...]\n"
5"\n"
6"\tDelete directories.\n";
7
8extern int
9rmdir_fn(const struct FileInfo * i)
10{
11 if ( rmdir(i->source) != 0 && errno != ENOENT && !i->force ) {
12 name_and_error(i->source);
13 return 1;
14 }
15 else
16 return 0;
17}
diff --git a/sleep.c b/sleep.c
new file mode 100644
index 000000000..e48e14b2f
--- /dev/null
+++ b/sleep.c
@@ -0,0 +1,15 @@
1#include "internal.h"
2#include <stdio.h>
3
4const char sleep_usage[] = "sleep seconds\n"
5"\n"
6"\tPause program execution for the given number of seconds.\n";
7
8extern int
9sleep_main(struct FileInfo * i, int argc, char * * argv)
10{
11 if ( sleep(atoi(argv[1])) != 0 )
12 return -1;
13 else
14 return 0;
15}
diff --git a/smtpout b/smtpout
new file mode 100644
index 000000000..635a83c6f
--- /dev/null
+++ b/smtpout
@@ -0,0 +1,2 @@
1echo '.' >smtpout echo 'QUIT' >smtpout
2kjfjkjd
diff --git a/swapoff.c b/swapoff.c
new file mode 100644
index 000000000..55124d0b8
--- /dev/null
+++ b/swapoff.c
@@ -0,0 +1,52 @@
1#include <sys/swap.h>
2#include <string.h>
3#include <errno.h>
4#include <mntent.h>
5#include "internal.h"
6
7const char swapoff_usage[] = "swapoff block-device\n"
8"\n"
9"\tStop swapping virtual memory pages on the given device.\n";
10
11extern int
12swapoff_fn(const struct FileInfo * i)
13{
14 struct mntent entries[100];
15 int count = 0;
16 FILE * swapsTable = setmntent("/etc/swaps", "r");
17 struct mntent * m;
18
19 if (!(swapoff(i->source))) {
20 if ( swapsTable == 0 ) {
21 fprintf(stderr, "/etc/swaps: %s\n", strerror(errno));
22 return 1;
23 }
24 while ( (m = getmntent(swapsTable)) != 0 ) {
25 entries[count].mnt_fsname = strdup(m->mnt_fsname);
26 entries[count].mnt_dir = strdup(m->mnt_dir);
27 entries[count].mnt_type = strdup(m->mnt_type);
28 entries[count].mnt_opts = strdup(m->mnt_opts);
29 entries[count].mnt_freq = m->mnt_freq;
30 entries[count].mnt_passno = m->mnt_passno;
31 count++;
32 }
33 endmntent(swapsTable);
34 if ( (swapsTable = setmntent("/etc/swaps", "w")) ) {
35 int id;
36 for ( id = 0; id < count; id++ ) {
37 int result =
38 (strcmp(entries[id].mnt_fsname, i->source)==0
39 ||strcmp(entries[id].mnt_dir, i->source)==0);
40 if ( result )
41 continue;
42 else
43 addmntent(swapsTable, &entries[id]);
44 }
45 endmntent(swapsTable);
46 }
47 else if ( errno != EROFS )
48 fprintf(stderr, "/etc/swaps: %s\n", strerror(errno));
49 return (0);
50 }
51 return (-1);
52}
diff --git a/swapon.c b/swapon.c
new file mode 100644
index 000000000..78360a55f
--- /dev/null
+++ b/swapon.c
@@ -0,0 +1,34 @@
1#include <stdio.h>
2#include <mntent.h>
3#include <sys/swap.h>
4#include "internal.h"
5
6const char swapon_usage[] = "swapon block-device\n"
7"\n"
8"\tSwap virtual memory pages on the given device.\n";
9
10extern int
11swapon_fn(const struct FileInfo * i)
12{
13 FILE *swapsTable;
14 struct mntent m;
15
16 if (!(swapon(i->source, 0))) {
17 if ((swapsTable = setmntent("/etc/swaps", "a+"))) {
18 /* Needs the cast to avoid warning about conversion from
19 * const char* to just char*
20 */
21 m.mnt_fsname = (char*)i->source;
22 m.mnt_dir = "none";
23 m.mnt_type = "swap";
24 m.mnt_opts = "sw";
25 m.mnt_freq = 0;
26 m.mnt_passno = 0;
27 addmntent(swapsTable, &m);
28 endmntent(swapsTable);
29 }
30 return (0);
31 }
32 return (-1);
33}
34
diff --git a/sync.c b/sync.c
new file mode 100644
index 000000000..6fa5b380b
--- /dev/null
+++ b/sync.c
@@ -0,0 +1,11 @@
1#include "internal.h"
2
3const char sync_usage[] = "sync\n"
4"\n"
5"\tWrite all buffered filesystem blocks to disk.\n";
6
7extern int
8sync_main(struct FileInfo * i, int argc, char * * argv)
9{
10 return sync();
11}
diff --git a/tar.c b/tar.c
new file mode 100644
index 000000000..03da96735
--- /dev/null
+++ b/tar.c
@@ -0,0 +1,1425 @@
1/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "tar" command, taken from sash.
7 * This allows creation, extraction, and listing of tar files.
8 *
9 * Permission to distribute this code under the GPL has been granted.
10 * Modified for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
11 */
12
13
14#include "internal.h"
15
16#ifdef BB_TAR
17
18const char tar_usage[] =
19"Create, extract, or list files from a TAR file\n\n"
20"usage: tar -[cxtvOf] [tarFileName] [FILE] ...\n"
21"\tc=create, x=extract, t=list contents, v=verbose,\n"
22"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
23
24
25
26#include <stdio.h>
27#include <dirent.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <signal.h>
31#include <time.h>
32
33/*
34 * Tar file constants.
35 */
36#define TAR_BLOCK_SIZE 512
37#define TAR_NAME_SIZE 100
38
39
40/*
41 * The POSIX (and basic GNU) tar header format.
42 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
43 * with zero padding. We only process this information minimally.
44 */
45typedef struct
46{
47 char name[TAR_NAME_SIZE];
48 char mode[8];
49 char uid[8];
50 char gid[8];
51 char size[12];
52 char mtime[12];
53 char checkSum[8];
54 char typeFlag;
55 char linkName[TAR_NAME_SIZE];
56 char magic[6];
57 char version[2];
58 char uname[32];
59 char gname[32];
60 char devMajor[8];
61 char devMinor[8];
62 char prefix[155];
63} TarHeader;
64
65#define TAR_MAGIC "ustar"
66#define TAR_VERSION "00"
67
68#define TAR_TYPE_REGULAR '0'
69#define TAR_TYPE_HARD_LINK '1'
70#define TAR_TYPE_SOFT_LINK '2'
71
72
73/*
74 * Static data.
75 */
76static BOOL listFlag;
77static BOOL extractFlag;
78static BOOL createFlag;
79static BOOL verboseFlag;
80static BOOL tostdoutFlag;
81
82static BOOL inHeader;
83static BOOL badHeader;
84static BOOL errorFlag;
85static BOOL skipFileFlag;
86static BOOL warnedRoot;
87static BOOL eofFlag;
88static long dataCc;
89static int outFd;
90static char outName[TAR_NAME_SIZE];
91
92
93/*
94 * Static data associated with the tar file.
95 */
96static const char * tarName;
97static int tarFd;
98static dev_t tarDev;
99static ino_t tarInode;
100
101
102/*
103 * Local procedures to restore files from a tar file.
104 */
105static void readTarFile(int fileCount, char ** fileTable);
106static void readData(const char * cp, int count);
107static void createPath(const char * name, int mode);
108static long getOctal(const char * cp, int len);
109
110static void readHeader(const TarHeader * hp,
111 int fileCount, char ** fileTable);
112
113
114/*
115 * Local procedures to save files into a tar file.
116 */
117static void saveFile(const char * fileName, BOOL seeLinks);
118
119static void saveRegularFile(const char * fileName,
120 const struct stat * statbuf);
121
122static void saveDirectory(const char * fileName,
123 const struct stat * statbuf);
124
125static BOOL wantFileName(const char * fileName,
126 int fileCount, char ** fileTable);
127
128static void writeHeader(const char * fileName,
129 const struct stat * statbuf);
130
131static void writeTarFile(int fileCount, char ** fileTable);
132static void writeTarBlock(const char * buf, int len);
133static BOOL putOctal(char * cp, int len, long value);
134extern const char * modeString(int mode);
135extern const char * timeString(time_t timeVal);
136extern int fullWrite(int fd, const char * buf, int len);
137extern int fullRead(int fd, char * buf, int len);
138
139
140extern int
141tar_main(struct FileInfo *unused, int argc, char ** argv)
142{
143 const char * options;
144
145 argc--;
146 argv++;
147
148 if (argc < 1)
149 {
150 fprintf(stderr, "%s", tar_usage);
151 return 1;
152 }
153
154
155 errorFlag = FALSE;
156 extractFlag = FALSE;
157 createFlag = FALSE;
158 listFlag = FALSE;
159 verboseFlag = FALSE;
160 tostdoutFlag = FALSE;
161 tarName = NULL;
162 tarDev = 0;
163 tarInode = 0;
164 tarFd = -1;
165
166 /*
167 * Parse the options.
168 */
169 options = *argv++;
170 argc--;
171
172 if (**argv == '-') {
173 for (; *options; options++)
174 {
175 switch (*options)
176 {
177 case 'f':
178 if (tarName != NULL)
179 {
180 fprintf(stderr, "Only one 'f' option allowed\n");
181
182 return 1;
183 }
184
185 tarName = *argv++;
186 argc--;
187
188 break;
189
190 case 't':
191 listFlag = TRUE;
192 break;
193
194 case 'x':
195 extractFlag = TRUE;
196 break;
197
198 case 'c':
199 createFlag = TRUE;
200 break;
201
202 case 'v':
203 verboseFlag = TRUE;
204 break;
205
206 case 'O':
207 tostdoutFlag = TRUE;
208 break;
209
210 case '-':
211 break;
212
213 default:
214 fprintf(stderr, "Unknown tar flag '%c'\n", *options);
215
216 return 1;
217 }
218 }
219 }
220
221 /*
222 * Validate the options.
223 */
224 if (extractFlag + listFlag + createFlag != 1)
225 {
226 fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
227
228 return 1;
229 }
230
231 /*
232 * Do the correct type of action supplying the rest of the
233 * command line arguments as the list of files to process.
234 */
235 if (createFlag)
236 writeTarFile(argc, argv);
237 else
238 readTarFile(argc, argv);
239 if (errorFlag)
240 fprintf(stderr, "\n");
241 return( errorFlag);
242}
243
244
245/*
246 * Read a tar file and extract or list the specified files within it.
247 * If the list is empty than all files are extracted or listed.
248 */
249static void
250readTarFile(int fileCount, char ** fileTable)
251{
252 const char * cp;
253 int cc;
254 int inCc;
255 int blockSize;
256 char buf[BUF_SIZE];
257
258 skipFileFlag = FALSE;
259 badHeader = FALSE;
260 warnedRoot = FALSE;
261 eofFlag = FALSE;
262 inHeader = TRUE;
263 inCc = 0;
264 dataCc = 0;
265 outFd = -1;
266 blockSize = sizeof(buf);
267 cp = buf;
268
269 /*
270 * Open the tar file for reading.
271 */
272 if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
273 tarFd = STDIN;
274 }
275 else
276 tarFd = open(tarName, O_RDONLY);
277
278 if (tarFd < 0)
279 {
280 perror(tarName);
281 errorFlag = TRUE;
282 return;
283 }
284
285 /*
286 * Read blocks from the file until an end of file header block
287 * has been seen. (A real end of file from a read is an error.)
288 */
289 while (!eofFlag)
290 {
291 /*
292 * Read the next block of data if necessary.
293 * This will be a large block if possible, which we will
294 * then process in the small tar blocks.
295 */
296 if (inCc <= 0)
297 {
298 cp = buf;
299 inCc = fullRead(tarFd, buf, blockSize);
300
301 if (inCc < 0)
302 {
303 perror(tarName);
304 errorFlag=TRUE;
305 goto done;
306 }
307
308 if (inCc == 0)
309 {
310 fprintf(stderr,
311 "Unexpected end of file from \"%s\"",
312 tarName);
313 errorFlag=TRUE;
314 goto done;
315 }
316 }
317
318 /*
319 * If we are expecting a header block then examine it.
320 */
321 if (inHeader)
322 {
323 readHeader((const TarHeader *) cp, fileCount, fileTable);
324
325 cp += TAR_BLOCK_SIZE;
326 inCc -= TAR_BLOCK_SIZE;
327
328 continue;
329 }
330
331 /*
332 * We are currently handling the data for a file.
333 * Process the minimum of the amount of data we have available
334 * and the amount left to be processed for the file.
335 */
336 cc = inCc;
337
338 if (cc > dataCc)
339 cc = dataCc;
340
341 readData(cp, cc);
342
343 /*
344 * If the amount left isn't an exact multiple of the tar block
345 * size then round it up to the next block boundary since there
346 * is padding at the end of the file.
347 */
348 if (cc % TAR_BLOCK_SIZE)
349 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
350
351 cp += cc;
352 inCc -= cc;
353 }
354
355done:
356 /*
357 * Close the tar file if needed.
358 */
359 if ((tarFd >= 0) && (close(tarFd) < 0))
360 perror(tarName);
361
362 /*
363 * Close the output file if needed.
364 * This is only done here on a previous error and so no
365 * message is required on errors.
366 */
367 if (tostdoutFlag==FALSE) {
368 if (outFd >= 0)
369 (void) close(outFd);
370 }
371}
372
373
374/*
375 * Examine the header block that was just read.
376 * This can specify the information for another file, or it can mark
377 * the end of the tar file.
378 */
379static void
380readHeader(const TarHeader * hp, int fileCount, char ** fileTable)
381{
382 int mode;
383 int uid;
384 int gid;
385 int checkSum;
386 long size;
387 time_t mtime;
388 const char * name;
389 int cc;
390 BOOL hardLink;
391 BOOL softLink;
392
393 /*
394 * If the block is completely empty, then this is the end of the
395 * archive file. If the name is null, then just skip this header.
396 */
397 name = hp->name;
398
399 if (*name == '\0')
400 {
401 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
402 {
403 if (*name++)
404 return;
405 }
406
407 eofFlag = TRUE;
408
409 return;
410 }
411
412 /*
413 * There is another file in the archive to examine.
414 * Extract the encoded information and check it.
415 */
416 mode = getOctal(hp->mode, sizeof(hp->mode));
417 uid = getOctal(hp->uid, sizeof(hp->uid));
418 gid = getOctal(hp->gid, sizeof(hp->gid));
419 size = getOctal(hp->size, sizeof(hp->size));
420 mtime = getOctal(hp->mtime, sizeof(hp->mtime));
421 checkSum = getOctal(hp->checkSum, sizeof(hp->checkSum));
422
423 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
424 {
425 if (!badHeader)
426 fprintf(stderr, "Bad tar header, skipping\n");
427
428 badHeader = TRUE;
429
430 return;
431 }
432
433 badHeader = FALSE;
434 skipFileFlag = FALSE;
435
436 /*
437 * Check for the file modes.
438 */
439 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
440 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
441
442 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
443 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
444
445 /*
446 * Check for a directory or a regular file.
447 */
448 if (name[strlen(name) - 1] == '/')
449 mode |= S_IFDIR;
450 else if ((mode & S_IFMT) == 0)
451 mode |= S_IFREG;
452
453 /*
454 * Check for absolute paths in the file.
455 * If we find any, then warn the user and make them relative.
456 */
457 if (*name == '/')
458 {
459 while (*name == '/')
460 name++;
461
462 if (!warnedRoot)
463 {
464 fprintf(stderr,
465 "Absolute path detected, removing leading slashes\n");
466 }
467
468 warnedRoot = TRUE;
469 }
470
471 /*
472 * See if we want this file to be restored.
473 * If not, then set up to skip it.
474 */
475 if (!wantFileName(name, fileCount, fileTable))
476 {
477 if (!hardLink && !softLink && S_ISREG(mode))
478 {
479 inHeader = (size == 0);
480 dataCc = size;
481 }
482
483 skipFileFlag = TRUE;
484
485 return;
486 }
487
488 /*
489 * This file is to be handled.
490 * If we aren't extracting then just list information about the file.
491 */
492 if (!extractFlag)
493 {
494 if (verboseFlag)
495 {
496 printf("%s %3d/%-d %9ld %s %s", modeString(mode),
497 uid, gid, size, timeString(mtime), name);
498 }
499 else
500 printf("%s", name);
501
502 if (hardLink)
503 printf(" (link to \"%s\")", hp->linkName);
504 else if (softLink)
505 printf(" (symlink to \"%s\")", hp->linkName);
506 else if (S_ISREG(mode))
507 {
508 inHeader = (size == 0);
509 dataCc = size;
510 }
511
512 printf("\n");
513
514 return;
515 }
516
517 /*
518 * We really want to extract the file.
519 */
520 if (verboseFlag)
521 printf("x %s\n", name);
522
523 if (hardLink)
524 {
525 if (link(hp->linkName, name) < 0)
526 perror(name);
527
528 return;
529 }
530
531 if (softLink)
532 {
533#ifdef S_ISLNK
534 if (symlink(hp->linkName, name) < 0)
535 perror(name);
536#else
537 fprintf(stderr, "Cannot create symbolic links\n");
538#endif
539 return;
540 }
541
542 /*
543 * If the file is a directory, then just create the path.
544 */
545 if (S_ISDIR(mode))
546 {
547 createPath(name, mode);
548
549 return;
550 }
551
552 /*
553 * There is a file to write.
554 * First create the path to it if necessary with a default permission.
555 */
556 createPath(name, 0777);
557
558 inHeader = (size == 0);
559 dataCc = size;
560
561 /*
562 * Start the output file.
563 */
564 if (tostdoutFlag==TRUE)
565 outFd = STDOUT;
566 else
567 outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
568
569 if (outFd < 0)
570 {
571 perror(name);
572 skipFileFlag = TRUE;
573 return;
574 }
575
576 /*
577 * If the file is empty, then that's all we need to do.
578 */
579 if (size == 0 && tostdoutFlag == FALSE)
580 {
581 (void) close(outFd);
582 outFd = -1;
583 }
584}
585
586
587/*
588 * Handle a data block of some specified size that was read.
589 */
590static void
591readData(const char * cp, int count)
592{
593 /*
594 * Reduce the amount of data left in this file.
595 * If there is no more data left, then we need to read
596 * the header again.
597 */
598 dataCc -= count;
599
600 if (dataCc <= 0)
601 inHeader = TRUE;
602
603 /*
604 * If we aren't extracting files or this file is being
605 * skipped then do nothing more.
606 */
607 if (!extractFlag || skipFileFlag)
608 return;
609
610 /*
611 * Write the data to the output file.
612 */
613 if (fullWrite(outFd, cp, count) < 0)
614 {
615 perror(outName);
616 if (tostdoutFlag==FALSE) {
617 (void) close(outFd);
618 outFd = -1;
619 }
620 skipFileFlag = TRUE;
621 return;
622 }
623
624 /*
625 * If the write failed, close the file and disable further
626 * writes to this file.
627 */
628 if (dataCc <= 0 && tostdoutFlag==FALSE)
629 {
630 if (close(outFd))
631 perror(outName);
632
633 outFd = -1;
634 }
635}
636
637
638/*
639 * Write a tar file containing the specified files.
640 */
641static void
642writeTarFile(int fileCount, char ** fileTable)
643{
644 struct stat statbuf;
645
646 /*
647 * Make sure there is at least one file specified.
648 */
649 if (fileCount <= 0)
650 {
651 fprintf(stderr, "No files specified to be saved\n");
652 errorFlag=TRUE;
653 }
654
655 /*
656 * Create the tar file for writing.
657 */
658 if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
659 tostdoutFlag = TRUE;
660 tarFd = STDOUT;
661 }
662 else
663 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
664
665 if (tarFd < 0)
666 {
667 perror(tarName);
668 errorFlag=TRUE;
669 return;
670 }
671
672 /*
673 * Get the device and inode of the tar file for checking later.
674 */
675 if (fstat(tarFd, &statbuf) < 0)
676 {
677 perror(tarName);
678 errorFlag = TRUE;
679 goto done;
680 }
681
682 tarDev = statbuf.st_dev;
683 tarInode = statbuf.st_ino;
684
685 /*
686 * Append each file name into the archive file.
687 * Follow symbolic links for these top level file names.
688 */
689 while (!errorFlag && (fileCount-- > 0))
690 {
691 saveFile(*fileTable++, FALSE);
692 }
693
694 /*
695 * Now write an empty block of zeroes to end the archive.
696 */
697 writeTarBlock("", 1);
698
699
700done:
701 /*
702 * Close the tar file and check for errors if it was opened.
703 */
704 if ( (tostdoutFlag==FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
705 perror(tarName);
706}
707
708
709/*
710 * Save one file into the tar file.
711 * If the file is a directory, then this will recursively save all of
712 * the files and directories within the directory. The seeLinks
713 * flag indicates whether or not we want to see symbolic links as
714 * they really are, instead of blindly following them.
715 */
716static void
717saveFile(const char * fileName, BOOL seeLinks)
718{
719 int status;
720 int mode;
721 struct stat statbuf;
722
723 if (verboseFlag)
724 printf("a %s\n", fileName);
725
726 /*
727 * Check that the file name will fit in the header.
728 */
729 if (strlen(fileName) >= TAR_NAME_SIZE)
730 {
731 fprintf(stderr, "%s: File name is too long\n", fileName);
732
733 return;
734 }
735
736 /*
737 * Find out about the file.
738 */
739#ifdef S_ISLNK
740 if (seeLinks)
741 status = lstat(fileName, &statbuf);
742 else
743#endif
744 status = stat(fileName, &statbuf);
745
746 if (status < 0)
747 {
748 perror(fileName);
749
750 return;
751 }
752
753 /*
754 * Make sure we aren't trying to save our file into itself.
755 */
756 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode))
757 {
758 fprintf(stderr, "Skipping saving of archive file itself\n");
759
760 return;
761 }
762
763 /*
764 * Check the type of file.
765 */
766 mode = statbuf.st_mode;
767
768 if (S_ISDIR(mode))
769 {
770 saveDirectory(fileName, &statbuf);
771
772 return;
773 }
774
775 if (S_ISREG(mode))
776 {
777 saveRegularFile(fileName, &statbuf);
778
779 return;
780 }
781
782 /*
783 * The file is a strange type of file, ignore it.
784 */
785 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
786}
787
788
789/*
790 * Save a regular file to the tar file.
791 */
792static void
793saveRegularFile(const char * fileName, const struct stat * statbuf)
794{
795 BOOL sawEof;
796 int fileFd;
797 int cc;
798 int dataCount;
799 long fullDataCount;
800 char data[TAR_BLOCK_SIZE * 16];
801
802 /*
803 * Open the file for reading.
804 */
805 fileFd = open(fileName, O_RDONLY);
806
807 if (fileFd < 0)
808 {
809 perror(fileName);
810
811 return;
812 }
813
814 /*
815 * Write out the header for the file.
816 */
817 writeHeader(fileName, statbuf);
818
819 /*
820 * Write the data blocks of the file.
821 * We must be careful to write the amount of data that the stat
822 * buffer indicated, even if the file has changed size. Otherwise
823 * the tar file will be incorrect.
824 */
825 fullDataCount = statbuf->st_size;
826 sawEof = FALSE;
827
828 while (fullDataCount > 0)
829 {
830 /*
831 * Get the amount to write this iteration which is
832 * the minumum of the amount left to write and the
833 * buffer size.
834 */
835 dataCount = sizeof(data);
836
837 if (dataCount > fullDataCount)
838 dataCount = (int) fullDataCount;
839
840 /*
841 * Read the data from the file if we haven't seen the
842 * end of file yet.
843 */
844 cc = 0;
845
846 if (!sawEof)
847 {
848 cc = fullRead(fileFd, data, dataCount);
849
850 if (cc < 0)
851 {
852 perror(fileName);
853
854 (void) close(fileFd);
855 errorFlag = TRUE;
856
857 return;
858 }
859
860 /*
861 * If the file ended too soon, complain and set
862 * a flag so we will zero fill the rest of it.
863 */
864 if (cc < dataCount)
865 {
866 fprintf(stderr,
867 "%s: Short read - zero filling",
868 fileName);
869
870 sawEof = TRUE;
871 }
872 }
873
874 /*
875 * Zero fill the rest of the data if necessary.
876 */
877 if (cc < dataCount)
878 memset(data + cc, 0, dataCount - cc);
879
880 /*
881 * Write the buffer to the TAR file.
882 */
883 writeTarBlock(data, dataCount);
884
885 fullDataCount -= dataCount;
886 }
887
888 /*
889 * Close the file.
890 */
891 if ( (tostdoutFlag==FALSE) && close(fileFd) < 0)
892 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
893}
894
895
896/*
897 * Save a directory and all of its files to the tar file.
898 */
899static void
900saveDirectory(const char * dirName, const struct stat * statbuf)
901{
902 DIR * dir;
903 struct dirent * entry;
904 BOOL needSlash;
905 char fullName[PATH_LEN];
906
907 /*
908 * Construct the directory name as used in the tar file by appending
909 * a slash character to it.
910 */
911 strcpy(fullName, dirName);
912 strcat(fullName, "/");
913
914 /*
915 * Write out the header for the directory entry.
916 */
917 writeHeader(fullName, statbuf);
918
919 /*
920 * Open the directory.
921 */
922 dir = opendir(dirName);
923
924 if (dir == NULL)
925 {
926 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
927 dirName, strerror(errno));
928
929 return;
930 }
931
932 /*
933 * See if a slash is needed.
934 */
935 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
936
937 /*
938 * Read all of the directory entries and check them,
939 * except for the current and parent directory entries.
940 */
941 while (!errorFlag && ((entry = readdir(dir)) != NULL))
942 {
943 if ((strcmp(entry->d_name, ".") == 0) ||
944 (strcmp(entry->d_name, "..") == 0))
945 {
946 continue;
947 }
948
949 /*
950 * Build the full path name to the file.
951 */
952 strcpy(fullName, dirName);
953
954 if (needSlash)
955 strcat(fullName, "/");
956
957 strcat(fullName, entry->d_name);
958
959 /*
960 * Write this file to the tar file, noticing whether or not
961 * the file is a symbolic link.
962 */
963 saveFile(fullName, TRUE);
964 }
965
966 /*
967 * All done, close the directory.
968 */
969 closedir(dir);
970}
971
972
973/*
974 * Write a tar header for the specified file name and status.
975 * It is assumed that the file name fits.
976 */
977static void
978writeHeader(const char * fileName, const struct stat * statbuf)
979{
980 long checkSum;
981 const unsigned char * cp;
982 int len;
983 TarHeader header;
984
985 /*
986 * Zero the header block in preparation for filling it in.
987 */
988 memset((char *) &header, 0, sizeof(header));
989
990 /*
991 * Fill in the header.
992 */
993 strcpy(header.name, fileName);
994
995 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
996 strncpy(header.version, TAR_VERSION, sizeof(header.version));
997
998 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
999 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1000 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1001 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1002 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
1003
1004 header.typeFlag = TAR_TYPE_REGULAR;
1005
1006 /*
1007 * Calculate and store the checksum.
1008 * This is the sum of all of the bytes of the header,
1009 * with the checksum field itself treated as blanks.
1010 */
1011 memset(header.checkSum, ' ', sizeof(header.checkSum));
1012
1013 cp = (const unsigned char *) &header;
1014 len = sizeof(header);
1015 checkSum = 0;
1016
1017 while (len-- > 0)
1018 checkSum += *cp++;
1019
1020 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
1021
1022 /*
1023 * Write the tar header.
1024 */
1025 writeTarBlock((const char *) &header, sizeof(header));
1026}
1027
1028
1029/*
1030 * Write data to one or more blocks of the tar file.
1031 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1032 * The errorFlag static variable is set on an error.
1033 */
1034static void
1035writeTarBlock(const char * buf, int len)
1036{
1037 int partialLength;
1038 int completeLength;
1039 char fullBlock[TAR_BLOCK_SIZE];
1040
1041 /*
1042 * If we had a write error before, then do nothing more.
1043 */
1044 if (errorFlag)
1045 return;
1046
1047 /*
1048 * Get the amount of complete and partial blocks.
1049 */
1050 partialLength = len % TAR_BLOCK_SIZE;
1051 completeLength = len - partialLength;
1052
1053 /*
1054 * Write all of the complete blocks.
1055 */
1056 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength))
1057 {
1058 perror(tarName);
1059
1060 errorFlag = TRUE;
1061
1062 return;
1063 }
1064
1065 /*
1066 * If there are no partial blocks left, we are done.
1067 */
1068 if (partialLength == 0)
1069 return;
1070
1071 /*
1072 * Copy the partial data into a complete block, and pad the rest
1073 * of it with zeroes.
1074 */
1075 memcpy(fullBlock, buf + completeLength, partialLength);
1076 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1077
1078 /*
1079 * Write the last complete block.
1080 */
1081 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE))
1082 {
1083 perror(tarName);
1084
1085 errorFlag = TRUE;
1086 }
1087}
1088
1089
1090/*
1091 * Attempt to create the directories along the specified path, except for
1092 * the final component. The mode is given for the final directory only,
1093 * while all previous ones get default protections. Errors are not reported
1094 * here, as failures to restore files can be reported later.
1095 */
1096static void
1097createPath(const char * name, int mode)
1098{
1099 char * cp;
1100 char * cpOld;
1101 char buf[TAR_NAME_SIZE];
1102
1103 strcpy(buf, name);
1104
1105 cp = strchr(buf, '/');
1106
1107 while (cp)
1108 {
1109 cpOld = cp;
1110 cp = strchr(cp + 1, '/');
1111
1112 *cpOld = '\0';
1113
1114 if (mkdir(buf, cp ? 0777 : mode) == 0)
1115 printf("Directory \"%s\" created\n", buf);
1116
1117 *cpOld = '/';
1118 }
1119}
1120
1121
1122/*
1123 * Read an octal value in a field of the specified width, with optional
1124 * spaces on both sides of the number and with an optional null character
1125 * at the end. Returns -1 on an illegal format.
1126 */
1127static long
1128getOctal(const char * cp, int len)
1129{
1130 long val;
1131
1132 while ((len > 0) && (*cp == ' '))
1133 {
1134 cp++;
1135 len--;
1136 }
1137
1138 if ((len == 0) || !isOctal(*cp))
1139 return -1;
1140
1141 val = 0;
1142
1143 while ((len > 0) && isOctal(*cp))
1144 {
1145 val = val * 8 + *cp++ - '0';
1146 len--;
1147 }
1148
1149 while ((len > 0) && (*cp == ' '))
1150 {
1151 cp++;
1152 len--;
1153 }
1154
1155 if ((len > 0) && *cp)
1156 return -1;
1157
1158 return val;
1159}
1160
1161
1162/*
1163 * Put an octal string into the specified buffer.
1164 * The number is zero and space padded and possibly null padded.
1165 * Returns TRUE if successful.
1166 */
1167static BOOL
1168putOctal(char * cp, int len, long value)
1169{
1170 int tempLength;
1171 char * tempString;
1172 char tempBuffer[32];
1173
1174 /*
1175 * Create a string of the specified length with an initial space,
1176 * leading zeroes and the octal number, and a trailing null.
1177 */
1178 tempString = tempBuffer;
1179
1180 sprintf(tempString, " %0*lo", len - 2, value);
1181
1182 tempLength = strlen(tempString) + 1;
1183
1184 /*
1185 * If the string is too large, suppress the leading space.
1186 */
1187 if (tempLength > len)
1188 {
1189 tempLength--;
1190 tempString++;
1191 }
1192
1193 /*
1194 * If the string is still too large, suppress the trailing null.
1195 */
1196 if (tempLength > len)
1197 tempLength--;
1198
1199 /*
1200 * If the string is still too large, fail.
1201 */
1202 if (tempLength > len)
1203 return FALSE;
1204
1205 /*
1206 * Copy the string to the field.
1207 */
1208 memcpy(cp, tempString, len);
1209
1210 return TRUE;
1211}
1212
1213
1214/*
1215 * See if the specified file name belongs to one of the specified list
1216 * of path prefixes. An empty list implies that all files are wanted.
1217 * Returns TRUE if the file is selected.
1218 */
1219static BOOL
1220wantFileName(const char * fileName, int fileCount, char ** fileTable)
1221{
1222 const char * pathName;
1223 int fileLength;
1224 int pathLength;
1225
1226 /*
1227 * If there are no files in the list, then the file is wanted.
1228 */
1229 if (fileCount == 0)
1230 return TRUE;
1231
1232 fileLength = strlen(fileName);
1233
1234 /*
1235 * Check each of the test paths.
1236 */
1237 while (fileCount-- > 0)
1238 {
1239 pathName = *fileTable++;
1240
1241 pathLength = strlen(pathName);
1242
1243 if (fileLength < pathLength)
1244 continue;
1245
1246 if (memcmp(fileName, pathName, pathLength) != 0)
1247 continue;
1248
1249 if ((fileLength == pathLength) ||
1250 (fileName[pathLength] == '/'))
1251 {
1252 return TRUE;
1253 }
1254 }
1255
1256 return FALSE;
1257}
1258
1259
1260
1261/*
1262 * Return the standard ls-like mode string from a file mode.
1263 * This is static and so is overwritten on each call.
1264 */
1265const char *
1266modeString(int mode)
1267{
1268 static char buf[12];
1269
1270 strcpy(buf, "----------");
1271
1272 /*
1273 * Fill in the file type.
1274 */
1275 if (S_ISDIR(mode))
1276 buf[0] = 'd';
1277 if (S_ISCHR(mode))
1278 buf[0] = 'c';
1279 if (S_ISBLK(mode))
1280 buf[0] = 'b';
1281 if (S_ISFIFO(mode))
1282 buf[0] = 'p';
1283#ifdef S_ISLNK
1284 if (S_ISLNK(mode))
1285 buf[0] = 'l';
1286#endif
1287#ifdef S_ISSOCK
1288 if (S_ISSOCK(mode))
1289 buf[0] = 's';
1290#endif
1291
1292 /*
1293 * Now fill in the normal file permissions.
1294 */
1295 if (mode & S_IRUSR)
1296 buf[1] = 'r';
1297 if (mode & S_IWUSR)
1298 buf[2] = 'w';
1299 if (mode & S_IXUSR)
1300 buf[3] = 'x';
1301 if (mode & S_IRGRP)
1302 buf[4] = 'r';
1303 if (mode & S_IWGRP)
1304 buf[5] = 'w';
1305 if (mode & S_IXGRP)
1306 buf[6] = 'x';
1307 if (mode & S_IROTH)
1308 buf[7] = 'r';
1309 if (mode & S_IWOTH)
1310 buf[8] = 'w';
1311 if (mode & S_IXOTH)
1312 buf[9] = 'x';
1313
1314 /*
1315 * Finally fill in magic stuff like suid and sticky text.
1316 */
1317 if (mode & S_ISUID)
1318 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
1319 if (mode & S_ISGID)
1320 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
1321 if (mode & S_ISVTX)
1322 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
1323
1324 return buf;
1325}
1326
1327
1328/*
1329 * Get the time string to be used for a file.
1330 * This is down to the minute for new files, but only the date for old files.
1331 * The string is returned from a static buffer, and so is overwritten for
1332 * each call.
1333 */
1334const char *
1335timeString(time_t timeVal)
1336{
1337 time_t now;
1338 char * str;
1339 static char buf[26];
1340
1341 time(&now);
1342
1343 str = ctime(&timeVal);
1344
1345 strcpy(buf, &str[4]);
1346 buf[12] = '\0';
1347
1348 if ((timeVal > now) || (timeVal < now - 365*24*60*60L))
1349 {
1350 strcpy(&buf[7], &str[20]);
1351 buf[11] = '\0';
1352 }
1353
1354 return buf;
1355}
1356
1357
1358
1359/*
1360 * Write all of the supplied buffer out to a file.
1361 * This does multiple writes as necessary.
1362 * Returns the amount written, or -1 on an error.
1363 */
1364int
1365fullWrite(int fd, const char * buf, int len)
1366{
1367 int cc;
1368 int total;
1369
1370 total = 0;
1371
1372 while (len > 0)
1373 {
1374 cc = write(fd, buf, len);
1375
1376 if (cc < 0)
1377 return -1;
1378
1379 buf += cc;
1380 total+= cc;
1381 len -= cc;
1382 }
1383
1384 return total;
1385}
1386
1387
1388/*
1389 * Read all of the supplied buffer from a file.
1390 * This does multiple reads as necessary.
1391 * Returns the amount read, or -1 on an error.
1392 * A short read is returned on an end of file.
1393 */
1394int
1395fullRead(int fd, char * buf, int len)
1396{
1397 int cc;
1398 int total;
1399
1400 total = 0;
1401
1402 while (len > 0)
1403 {
1404 cc = read(fd, buf, len);
1405
1406 if (cc < 0)
1407 return -1;
1408
1409 if (cc == 0)
1410 break;
1411
1412 buf += cc;
1413 total+= cc;
1414 len -= cc;
1415 }
1416
1417 return total;
1418}
1419
1420
1421
1422#endif
1423/* END CODE */
1424
1425
diff --git a/touch.c b/touch.c
new file mode 100644
index 000000000..ca4b98108
--- /dev/null
+++ b/touch.c
@@ -0,0 +1,20 @@
1#include "internal.h"
2#include <sys/types.h>
3#include <stdio.h>
4#include <utime.h>
5
6const char touch_usage[] = "touch [-c] file [file ...]\n"
7"\n"
8"\tUpdate the last-modified date on the given file[s].\n";
9
10extern int
11touch_fn(const struct FileInfo * i)
12{
13 if ( (utime(i->source, 0) != 0) && (i->create != 1) ) {
14 if ( fopen(i->source, "w") == NULL ) {
15 name_and_error(i->source);
16 return 1;
17 }
18 }
19 return 0;
20}
diff --git a/umount.c b/umount.c
new file mode 100644
index 000000000..4efc9f9d9
--- /dev/null
+++ b/umount.c
@@ -0,0 +1,135 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <unistd.h>
4#include <errno.h>
5#include <string.h>
6#include <stdio.h>
7#include <mntent.h>
8#include <sys/mount.h>
9
10const char umount_usage[] = "umount {filesystem|directory}\n"
11"\tumount -a\n"
12"\n"
13"\tUnmount a filesystem.\n"
14"\t-a:\tUnmounts all mounted filesystems.\n";
15
16static char *
17stralloc(const char * string)
18{
19 int length = strlen(string) + 1;
20 char * n = malloc(length);
21 memcpy(n, string, length);
22 return n;
23}
24
25extern void
26erase_mtab(const char * name)
27{
28 struct mntent entries[100];
29 int count = 0;
30 FILE * mountTable = setmntent("/etc/mtab", "r");
31 struct mntent * m;
32
33 if ( mountTable == 0
34 && (mountTable = setmntent("/proc/mounts", "r")) == 0 ) {
35 name_and_error("/etc/mtab");
36 return;
37 }
38
39 while ( (m = getmntent(mountTable)) != 0 ) {
40 entries[count].mnt_fsname = stralloc(m->mnt_fsname);
41 entries[count].mnt_dir = stralloc(m->mnt_dir);
42 entries[count].mnt_type = stralloc(m->mnt_type);
43 entries[count].mnt_opts = stralloc(m->mnt_opts);
44 entries[count].mnt_freq = m->mnt_freq;
45 entries[count].mnt_passno = m->mnt_passno;
46 count++;
47 }
48 endmntent(mountTable);
49 if ( (mountTable = setmntent("/etc/mtab", "w")) ) {
50 int i;
51 for ( i = 0; i < count; i++ ) {
52 int result = ( strcmp(entries[i].mnt_fsname, name) == 0
53 || strcmp(entries[i].mnt_dir, name) == 0 );
54
55 if ( result )
56 continue;
57 else
58 addmntent(mountTable, &entries[i]);
59 }
60 endmntent(mountTable);
61 }
62 else if ( errno != EROFS )
63 name_and_error("/etc/mtab");
64}
65
66static int
67umount_all(int noMtab)
68{
69 struct mntent entries[100];
70 int count = 0;
71 FILE * mountTable = setmntent("/etc/mtab", "r");
72 struct mntent * m;
73 int status = 0;
74
75 if ( mountTable == 0
76 && (mountTable = setmntent("/proc/mounts", "r")) == 0 ) {
77 name_and_error("/etc/mtab");
78 return 1;
79 }
80
81 while ( (m = getmntent(mountTable)) != 0 ) {
82 entries[count].mnt_fsname = stralloc(m->mnt_fsname);
83 count++;
84 }
85 endmntent(mountTable);
86
87 while ( count > 0 ) {
88 int result = umount(entries[--count].mnt_fsname) == 0;
89 /* free(entries[count].mnt_fsname); */
90 if ( result ) {
91 if ( !noMtab )
92 erase_mtab(entries[count].mnt_fsname);
93 }
94 else {
95 status = 1;
96 name_and_error(entries[count].mnt_fsname);
97 }
98 }
99 return status;
100}
101
102extern int
103do_umount(const char * name, int noMtab)
104{
105 if ( umount(name) == 0 ) {
106 if ( !noMtab )
107 erase_mtab(name);
108 return 0;
109 }
110 return 1;
111}
112
113extern int
114umount_main(struct FileInfo * i, int argc, char * * argv)
115{
116 int noMtab = 0;
117
118 if ( argv[1][0] == '-' ) {
119 switch ( argv[1][1] ) {
120 case 'a':
121 return umount_all(noMtab);
122 case 'n':
123 noMtab = 1;
124 break;
125 default:
126 usage(umount_usage);
127 return 1;
128 }
129 }
130 if ( do_umount(argv[1],noMtab) != 0 ) {
131 fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
132 return 1;
133 }
134 return 0;
135}
diff --git a/update.c b/update.c
new file mode 100644
index 000000000..f3b7fc0c8
--- /dev/null
+++ b/update.c
@@ -0,0 +1,48 @@
1#include "internal.h"
2#include <linux/unistd.h>
3
4const char update_usage[] = "update\n"
5"\n"
6"\tFlush buffered data to the disk devices every 30 seconds.\n";
7
8#if defined(__GLIBC__)
9#include <sys/kdaemon.h>
10#else
11_syscall2(int, bdflush, int, func, int, data);
12#endif /* __GLIBC__ */
13
14extern int
15update_main(struct FileInfo * i, int argc, char * * argv)
16{
17 /*
18 * Update is actually two daemons, bdflush and update.
19 */
20 int pid;
21
22 pid = fork();
23 if ( pid < 0 )
24 return pid;
25 else if ( pid == 0 ) {
26 /*
27 * This is no longer necessary since 1.3.5x, but it will harmlessly
28 * exit if that is the case.
29 */
30 strcpy(argv[0], "bdflush (update)");
31 argv[1] = 0;
32 argv[2] = 0;
33 bdflush(1, 0);
34 _exit(0);
35 }
36 pid = fork();
37 if ( pid < 0 )
38 return pid;
39 else if ( pid == 0 ) {
40 argv[0] = "update";
41 for ( ; ; ) {
42 sync();
43 sleep(30);
44 }
45 }
46
47 return 0;
48}
diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c
new file mode 100644
index 000000000..a63fa3d39
--- /dev/null
+++ b/util-linux/dmesg.c
@@ -0,0 +1,95 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <unistd.h>
4#include <time.h>
5
6/* dmesg.c -- Print out the contents of the kernel ring buffer
7 * Created: Sat Oct 9 16:19:47 1993
8 * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
9 * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
10 * This program comes with ABSOLUTELY NO WARRANTY.
11 * Modifications by Rick Sladkey (jrs@world.std.com)
12 * from util-linux; adapted for busybox
13 */
14
15#include <linux/unistd.h>
16#include <stdio.h>
17#include <getopt.h>
18
19#define __NR_klog __NR_syslog
20
21#if defined(__GLIBC__)
22#include <sys/klog.h>
23#define klog klogctl
24#else
25static inline _syscall3(int,klog,int,type,char *,b,int,len)
26#endif /* __GLIBC__ */
27
28const char dmesg_usage[] = "dmesg";
29
30int
31dmesg_main(struct FileInfo * info, int argc, char * * argv)
32{
33
34 char buf[4096];
35 int i;
36 int n;
37 int c;
38 int level = 0;
39 int lastc;
40 int cmd = 3;
41
42 while ((c = getopt( argc, argv, "cn:" )) != EOF) {
43 switch (c) {
44 case 'c':
45 cmd = 4;
46 break;
47 case 'n':
48 cmd = 8;
49 level = atoi(optarg);
50 break;
51 case '?':
52 default:
53 usage(dmesg_usage);
54 exit(1);
55 }
56 }
57 argc -= optind;
58 argv += optind;
59
60 if (argc > 1) {
61 usage(dmesg_usage);
62 exit(1);
63 }
64
65 if (cmd == 8) {
66 n = klog( cmd, NULL, level );
67 if (n < 0) {
68 perror( "klog" );
69 exit( 1 );
70 }
71 exit( 0 );
72 }
73
74 n = klog( cmd, buf, sizeof( buf ) );
75 if (n < 0) {
76 perror( "klog" );
77 exit( 1 );
78 }
79
80 lastc = '\n';
81 for (i = 0; i < n; i++) {
82 if ((i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
83 i++;
84 while (buf[i] >= '0' && buf[i] <= '9')
85 i++;
86 if (buf[i] == '>')
87 i++;
88 }
89 lastc = buf[i];
90 putchar( lastc );
91 }
92 if (lastc != '\n')
93 putchar( '\n' );
94 return 0;
95}
diff --git a/util-linux/fdflush.c b/util-linux/fdflush.c
new file mode 100644
index 000000000..a15e9b3f7
--- /dev/null
+++ b/util-linux/fdflush.c
@@ -0,0 +1,36 @@
1#include "internal.h"
2#include <sys/ioctl.h>
3#include <linux/fd.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7
8const char fdflush_usage[] = "fdflush device";
9
10int
11fdflush(const char *filename)
12{
13 int status;
14 int fd = open(filename, 0);
15
16 if ( fd < 0 ) {
17 name_and_error(filename);
18 return 1;
19 }
20
21 status = ioctl(fd, FDFLUSH, 0);
22 close(fd);
23
24 if ( status != 0 ) {
25 name_and_error(filename);
26 return 1;
27 }
28 return 0;
29}
30
31
32int
33fdflush_fn(const struct FileInfo * i)
34{
35 return fdflush(i->source);
36}
diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c
new file mode 100644
index 000000000..f797d1395
--- /dev/null
+++ b/util-linux/mkswap.c
@@ -0,0 +1,253 @@
1#include "internal.h"
2/*
3 * mkswap.c - set up a linux swap device
4 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per
6 * the Linux copyright.
7 */
8
9/*
10 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
11 *
12 * Usage: mkswap [-c] device [size-in-blocks]
13 *
14 * -c for readablility checking (use it unless you are SURE!)
15 *
16 * The device may be a block device or a image of one, but this isn't
17 * enforced (but it's not much fun on a character device :-).
18 *
19 * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
20 * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995.
21 */
22
23#include <stdio.h>
24#include <unistd.h>
25#include <string.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <sys/stat.h>
29#include <sys/ioctl.h>
30
31#include <asm/page.h>
32#include <linux/fs.h>
33
34#ifndef __linux__
35# define volatile
36#endif
37
38#define TEST_BUFFER_PAGES 8
39
40const char mkswap_usage[] = "mkswap [-c] partition [block-count]\n"
41"\n"
42"\tPrepare a disk partition to be used as a swap partition.\n"
43"\tThe default block count is the size of the entire partition.\n"
44"\n"
45"\t-c:\tCheck for read-ability.\n"
46"\tblock-count\tUse only this many blocks.\n";
47
48static const char * program_name = "mkswap";
49static const char * device_name = NULL;
50static int DEV = -1;
51static long PAGES = 0;
52static int do_check = 0;
53static int badpages = 0;
54
55
56static long bit_test_and_set (unsigned int *addr, unsigned int nr)
57{
58 unsigned int r, m;
59
60 addr += nr / (8 * sizeof(int));
61 r = *addr;
62 m = 1 << (nr & (8 * sizeof(int) - 1));
63 *addr = r | m;
64 return (r & m) != 0;
65}
66
67static int bit_test_and_clear (unsigned int *addr, unsigned int nr)
68{
69 unsigned int r, m;
70
71 addr += nr / (8 * sizeof(int));
72 r = *addr;
73 m = 1 << (nr & (8 * sizeof(int) - 1));
74 *addr = r & ~m;
75 return (r & m) != 0;
76}
77
78/*
79 * Volatile to let gcc know that this doesn't return. When trying
80 * to compile this under minix, volatile gives a warning, as
81 * exit() isn't defined as volatile under minix.
82 */
83volatile void fatal_error(const char * fmt_string)
84{
85 fprintf(stderr,fmt_string,program_name,device_name);
86 exit(1);
87}
88
89#define die(str) fatal_error("%s: " str "\n")
90
91static void check_blocks(int * signature_page)
92{
93 unsigned int current_page;
94 int do_seek = 1;
95 char buffer[PAGE_SIZE];
96
97 current_page = 0;
98 while (current_page < PAGES) {
99 if (!do_check) {
100 bit_test_and_set(signature_page,current_page++);
101 continue;
102 } else {
103 printf("\r%d", current_page);
104 }
105 if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) !=
106 current_page*PAGE_SIZE)
107 die("seek failed in check_blocks");
108 if ( (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) ) {
109 bit_test_and_clear(signature_page,current_page++);
110 badpages++;
111 continue;
112 }
113 bit_test_and_set(signature_page,current_page++);
114 }
115 if (do_check)
116 printf("\n");
117 if (badpages)
118 printf("%d bad page%s\n",badpages,(badpages>1)?"s":"");
119}
120
121static long valid_offset (int fd, int offset)
122{
123 char ch;
124
125 if (lseek (fd, offset, 0) < 0)
126 return 0;
127 if (read (fd, &ch, 1) < 1)
128 return 0;
129 return 1;
130}
131
132static int count_blocks (int fd)
133{
134 int high, low;
135
136 low = 0;
137 for (high = 1; valid_offset (fd, high); high *= 2)
138 low = high;
139 while (low < high - 1)
140 {
141 const int mid = (low + high) / 2;
142
143 if (valid_offset (fd, mid))
144 low = mid;
145 else
146 high = mid;
147 }
148 valid_offset (fd, 0);
149 return (low + 1);
150}
151
152static int get_size(const char *file)
153{
154 int fd;
155 int size;
156
157 fd = open(file, O_RDWR);
158 if (fd < 0) {
159 perror(file);
160 exit(1);
161 }
162 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
163 close(fd);
164 return (size * 512);
165 }
166
167 size = count_blocks(fd);
168 close(fd);
169 return size;
170}
171
172int
173mkswap(char *device_name, int pages, int check)
174 {
175 struct stat statbuf;
176 int goodpages;
177 int signature_page[PAGE_SIZE/sizeof(int)];
178
179 PAGES = pages;
180 do_check = check;
181
182 memset(signature_page,0,PAGE_SIZE);
183
184 if (device_name && !PAGES) {
185 PAGES = get_size(device_name) / PAGE_SIZE;
186 }
187 if (!device_name || PAGES<10) {
188 fprintf(stderr,
189 "%s: error: swap area needs to be at least %ldkB\n",
190 program_name, 10 * PAGE_SIZE / 1024);
191 /* usage(mkswap_usage); */
192 exit(1);
193 }
194 if (PAGES > 8 * (PAGE_SIZE - 10)) {
195 PAGES = 8 * (PAGE_SIZE - 10);
196 fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n",
197 program_name, PAGES * PAGE_SIZE / 1024);
198 }
199 DEV = open(device_name,O_RDWR);
200 if (DEV < 0 || fstat(DEV, &statbuf) < 0) {
201 perror(device_name);
202 exit(1);
203 }
204 if (!S_ISBLK(statbuf.st_mode))
205 do_check=0;
206 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
207 die("Will not try to make swapdevice on '%s'");
208 check_blocks(signature_page);
209 if (!bit_test_and_clear(signature_page,0))
210 die("fatal: first page unreadable");
211 goodpages = PAGES - badpages - 1;
212 if (goodpages <= 0)
213 die("Unable to set up swap-space: unreadable");
214 printf("Setting up swapspace, size = %ld bytes\n",goodpages*PAGE_SIZE);
215 strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10);
216 if (lseek(DEV, 0, SEEK_SET))
217 die("unable to rewind swap-device");
218 if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE))
219 die("unable to write signature page");
220
221 close(DEV);
222 return 0;
223}
224
225int mkswap_main(struct FileInfo * unnecessary, int argc, char ** argv)
226{
227 char * tmp;
228 long int pages=0;
229 int check=0;
230
231 if (argc && *argv)
232 program_name = *argv;
233 while (argc > 1) {
234 argv++;
235 argc--;
236 if (argv[0][0] != '-')
237 if (device_name) {
238 pages = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10);
239 if (*tmp) {
240 usage(mkswap_usage);
241 exit(1);
242 }
243 } else
244 device_name = argv[0];
245 else while (*++argv[0])
246 switch (argv[0][0]) {
247 case 'c': check=1; break;
248 default: usage(mkswap_usage);
249 exit(1);
250 }
251 }
252 return mkswap(device_name, pages, check);
253}
diff --git a/util-linux/more.c b/util-linux/more.c
new file mode 100644
index 000000000..65409999b
--- /dev/null
+++ b/util-linux/more.c
@@ -0,0 +1,110 @@
1#include "internal.h"
2#include <stdio.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <sys/ioctl.h>
6#include <fcntl.h>
7
8#define BB_MORE_TERM
9
10#ifdef BB_MORE_TERM
11 #include <termios.h>
12 #include <signal.h>
13
14 FILE *cin;
15 struct termios initial_settings, new_settings;
16
17 void gotsig(int sig) {
18 tcsetattr(fileno(cin), TCSANOW, &initial_settings);
19 exit(0);
20 }
21#endif
22
23const char more_usage[] = "more [file]\n"
24"\n"
25"\tDisplays a file, one page at a time.\n"
26"\tIf there are no arguments, the standard input is displayed.\n";
27
28extern int
29more_fn(const struct FileInfo * i)
30{
31 FILE * f = stdin;
32 int c;
33 int lines = 0, tlines = 0;
34 int next_page = 0;
35 int rows = 24, cols = 79;
36#ifdef BB_MORE_TERM
37 long sizeb = 0;
38 struct stat st;
39 struct winsize win;
40#endif
41
42 if ( i ) {
43 if (! (f = fopen(i->source, "r") )) {
44 name_and_error(i->source);
45 return 1;
46 }
47 fstat(fileno(f), &st);
48 sizeb = st.st_size / 100;
49 }
50
51#ifdef BB_MORE_TERM
52 cin = fopen("/dev/tty", "r");
53 tcgetattr(fileno(cin),&initial_settings);
54 new_settings = initial_settings;
55 new_settings.c_lflag &= ~ICANON;
56 new_settings.c_lflag &= ~ECHO;
57 tcsetattr(fileno(cin), TCSANOW, &new_settings);
58
59 (void) signal(SIGINT, gotsig);
60
61 ioctl(STDOUT_FILENO, TIOCGWINSZ, &win);
62 if (win.ws_row > 4) rows = win.ws_row - 2;
63 if (win.ws_col > 0) cols = win.ws_col - 1;
64
65
66#endif
67
68 while ( (c = getc(f)) != EOF ) {
69 if ( next_page ) {
70 char garbage;
71 int len;
72 tlines += lines;
73 lines = 0;
74 next_page = 0; //Percentage is based on bytes, not lines.
75 if ( i && i->source ) //It is not very acurate, but still useful.
76 len = printf("%s - %%%2ld - line: %d", i->source, (ftell(f) - sizeb - sizeb) / sizeb, tlines);
77 else
78 len = printf("line: %d", tlines);
79
80 fflush(stdout);
81#ifndef BB_MORE_TERM
82 read(2, &garbage, 1);
83#else
84 do {
85 fread(&garbage, 1, 1, cin);
86 } while ((garbage != ' ') && (garbage != '\n'));
87
88 if (garbage == '\n') {
89 lines = rows;
90 tlines -= rows;
91 }
92 garbage = 0;
93 //clear line, since tabs don't overwrite.
94 while(len-- > 0) putchar('\b');
95 while(len++ < cols) putchar(' ');
96 while(len-- > 0) putchar('\b');
97 fflush(stdout);
98#endif
99 }
100 putchar(c);
101 if ( c == '\n' && ++lines == (rows + 1) )
102 next_page = 1;
103 }
104 if ( f != stdin )
105 fclose(f);
106#ifdef BB_MORE_TERM
107 gotsig(0);
108#endif
109 return 0;
110}
diff --git a/util-linux/mount.c b/util-linux/mount.c
new file mode 100644
index 000000000..010757d1e
--- /dev/null
+++ b/util-linux/mount.c
@@ -0,0 +1,430 @@
1/*
2 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
3 searches through fstab when -a is passed
4 will try mounting stuff with all fses when passed -t auto
5
6 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
7*/
8
9#include "internal.h"
10#include <stdlib.h>
11#include <unistd.h>
12#include <errno.h>
13#include <string.h>
14#include <stdio.h>
15#include <mntent.h>
16#include <sys/mount.h>
17#include <ctype.h>
18
19const char mount_usage[] = "mount\n"
20"\t\tmount [flags] special-device directory\n"
21"\n"
22"Flags:\n"
23"\t-a:\tMount all file systems in fstab.\n"
24"\t-f:\t\"Fake\" mount. Add entry to mount table but don't mount it.\n"
25"\t-n:\tDon't write a mount table entry.\n"
26"\t-o option:\tOne of many filesystem options, listed below.\n"
27"\t-r:\tMount the filesystem read-only.\n"
28"\t-t filesystem-type:\tSpecify the filesystem type.\n"
29"\t-w:\tMount for reading and writing (default).\n"
30"\n"
31"Options for use with the \"-o\" flag:\n"
32"\tasync / sync:\tWrites are asynchronous / synchronous.\n"
33"\tdev / nodev:\tAllow use of special device files / disallow them.\n"
34"\texec / noexec:\tAllow use of executable files / disallow them.\n"
35"\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n"
36"\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n"
37"\tro / rw: Mount for read-only / read-write.\n"
38"\t"
39"There are EVEN MORE flags that are specific to each filesystem.\n"
40"You'll have to see the written documentation for those.\n";
41
42struct mount_options {
43 const char * name;
44 unsigned long and;
45 unsigned long or;
46};
47
48static const struct mount_options mount_options[] = {
49 { "async", ~MS_SYNCHRONOUS,0 },
50 { "defaults", ~0, 0 },
51 { "dev", ~MS_NODEV, 0 },
52 { "exec", ~MS_NOEXEC, 0 },
53 { "nodev", ~0, MS_NODEV },
54 { "noexec", ~0, MS_NOEXEC },
55 { "nosuid", ~0, MS_NOSUID },
56 { "remount", ~0, MS_REMOUNT },
57 { "ro", ~0, MS_RDONLY },
58 { "rw", ~MS_RDONLY, 0 },
59 { "suid", ~MS_NOSUID, 0 },
60 { "sync", ~0, MS_SYNCHRONOUS },
61 { 0, 0, 0 }
62};
63
64static void
65show_flags(unsigned long flags, char * buffer)
66{
67 const struct mount_options * f = mount_options;
68 while ( f->name ) {
69 if ( flags & f->and ) {
70 int length = strlen(f->name);
71 memcpy(buffer, f->name, length);
72 buffer += length;
73 *buffer++ = ',';
74 *buffer = '\0';
75 }
76 f++;
77 }
78}
79
80static void
81one_option(
82 char * option
83,unsigned long * flags
84,char * data)
85{
86 const struct mount_options * f = mount_options;
87
88 while ( f->name != 0 ) {
89 if ( strcasecmp(f->name, option) == 0 ) {
90 *flags &= f->and;
91 *flags |= f->or;
92 return;
93 }
94 f++;
95 }
96 if ( *data ) {
97 data += strlen(data);
98 *data++ = ',';
99 }
100 strcpy(data, option);
101}
102
103static void
104parse_mount_options(
105 char * options
106,unsigned long * flags
107,char * data)
108{
109 while ( *options ) {
110 char * comma = strchr(options, ',');
111 if ( comma )
112 *comma = '\0';
113 one_option(options, flags, data);
114 if ( comma ) {
115 *comma = ',';
116 options = ++comma;
117 }
118 else
119 break;
120 }
121}
122
123int
124mount_one(
125 char * blockDevice
126,char * directory
127,char * filesystemType
128,unsigned long flags
129,char * string_flags
130,int noMtab
131,int fake)
132{
133 int error = 0;
134 int status = 0;
135
136 char buf[255];
137
138 if (!fake) {
139 if (*filesystemType == 'a') { //Will fail on real FS starting with 'a'
140
141 FILE *f = fopen("/proc/filesystems", "r");
142
143 if (f == NULL) return 1;
144
145 while (fgets(buf, sizeof(buf), f) != NULL) {
146 filesystemType = buf;
147 if (*filesystemType == '\t') { // Not a nodev filesystem
148
149 while (*filesystemType && *filesystemType != '\n') filesystemType++;
150 *filesystemType = '\0';
151
152 filesystemType = buf;
153 filesystemType++; //hop past tab
154
155 status = mount(blockDevice, directory, filesystemType,
156 flags|MS_MGC_VAL ,string_flags);
157 error = errno;
158
159 if (status == 0) break;
160 }
161 }
162 fclose(f);
163 } else {
164
165 status = mount( blockDevice, directory, filesystemType,
166 flags|MS_MGC_VAL ,string_flags);
167 error = errno;
168 }
169 }
170
171 if ( status == 0 ) {
172 char * s = &string_flags[strlen(string_flags)];
173 FILE * mountTable;
174 if ( s != string_flags ) {
175 *s++ = ',';
176 show_flags(flags, s);
177 }
178 if ( !noMtab && (mountTable = setmntent("/etc/mtab", "a+")) ) {
179 int length = strlen(directory);
180 struct mntent m;
181
182 if ( length > 1 && directory[length - 1] == '/' )
183 directory[length - 1] = '\0';
184
185 if ( filesystemType == 0 ) {
186 struct mntent * p
187 = findMountPoint(blockDevice, "/proc/mounts");
188
189 if ( p && p->mnt_type )
190 filesystemType = p->mnt_type;
191 }
192 m.mnt_fsname = blockDevice;
193 m.mnt_dir = directory;
194 m.mnt_type = filesystemType ? filesystemType : "default";
195
196 if (*string_flags) {
197 m.mnt_opts = string_flags;
198 } else {
199 if ( (flags | MS_RDONLY) == flags )
200 m.mnt_opts = "ro";
201 else
202 m.mnt_opts = "rw";
203 }
204
205 m.mnt_freq = 0;
206 m.mnt_passno = 0;
207 addmntent(mountTable, &m);
208 endmntent(mountTable);
209 }
210 return 0;
211 } else {
212 fprintf(stderr, "Mount %s", blockDevice);
213 if ( filesystemType && *filesystemType )
214 fprintf(stderr, " (type %s)", filesystemType);
215
216 fprintf(
217 stderr
218 ," on %s: "
219 ,directory);
220
221 switch ( error ) {
222 case EPERM:
223 if (geteuid() == 0)
224 fprintf(
225 stderr
226 ,"mount point %s is not a directory"
227 ,blockDevice);
228 else
229 fprintf(
230 stderr
231 ,"must be superuser to use mount");
232 break;
233 case EBUSY:
234 fprintf(
235 stderr
236 ,"%s already mounted or %s busy"
237 ,blockDevice
238 ,directory);
239 break;
240 case ENOENT:
241 {
242 struct stat statbuf;
243 if ( stat(directory, &statbuf) != 0 )
244 fprintf(
245 stderr
246 ,"directory %s does not exist"
247 ,directory);
248 else if ( stat(blockDevice, &statbuf) != 0 )
249 fprintf(
250 stderr
251 ,"block device %s does not exist"
252 ,blockDevice);
253 else
254 fprintf(
255 stderr
256 ,"%s is not mounted on %s, but the mount table says it is."
257 ,blockDevice
258 ,directory);
259 break;
260 }
261 case ENOTDIR:
262 fprintf(
263 stderr
264 ,"%s is not a directory"
265 ,directory);
266 break;
267 case EINVAL:
268 fprintf(
269 stderr
270 ,"wrong filesystem type, or bad superblock on %s"
271 ,blockDevice);
272 break;
273 case EMFILE:
274 fprintf(stderr, "mount table full");
275 break;
276 case EIO:
277 fprintf(
278 stderr
279 ,"I/O error reading %s"
280 ,blockDevice);
281 break;
282 case ENODEV:
283 {
284 FILE * f = fopen("/proc/filesystems", "r");
285
286 fprintf(
287 stderr
288 ,"filesystem type %s not in kernel.\n"
289 ,filesystemType);
290 fprintf(stderr, "Do you need to load a module?\n");
291 if ( f ) {
292 char buf[100];
293
294 fprintf(
295 stderr
296 ,"Here are the filesystem types the kernel"
297 " can mount:\n");
298 while ( fgets(buf, sizeof(buf), f) != 0 )
299 fprintf(stderr, "\t%s", buf);
300 fclose(f);
301 }
302 break;
303 }
304 case ENOTBLK:
305 fprintf(
306 stderr
307 ,"%s is not a block device"
308 ,blockDevice);
309 break;
310 case ENXIO:
311 fprintf(
312 stderr
313 ,"%s is not a valid block device"
314 ,blockDevice);
315 break;
316 default:
317 fputs(strerror(errno), stderr);
318 }
319 putc('\n', stderr);
320 return -1;
321 }
322}
323
324extern int
325mount_main(struct FileInfo * i, int argc, char * * argv)
326{
327 char string_flags[1024];
328 unsigned long flags = 0;
329 char * filesystemType = "auto";
330 int fake = 0;
331 int noMtab = 0;
332 int all = 0;
333
334 *string_flags = '\0';
335
336 if ( argc == 1 ) {
337 FILE * mountTable;
338 if ( (mountTable = setmntent("/etc/mtab", "r")) ) {
339 struct mntent * m;
340 while ( (m = getmntent(mountTable)) != 0 ) {
341 printf(
342 "%s on %s type %s (%s)\n"
343 ,m->mnt_fsname
344 ,m->mnt_dir
345 ,m->mnt_type
346 ,m->mnt_opts);
347 }
348 endmntent(mountTable);
349 }
350 return 0;
351 }
352
353 while ( argc >= 2 && argv[1][0] == '-' ) {
354 switch ( argv[1][1] ) {
355 case 'f':
356 fake = 1;
357 break;
358 case 'n':
359 noMtab = 1;
360 break;
361 case 'o':
362 if ( argc < 3 ) {
363 usage(mount_usage);
364 return 1;
365 }
366 parse_mount_options(argv[2], &flags, string_flags);
367 argc--;
368 argv++;
369 break;
370 case 'r':
371 flags |= MS_RDONLY;
372 break;
373 case 't':
374 if ( argc < 3 ) {
375 usage(mount_usage);
376 return 1;
377 }
378 filesystemType = argv[2];
379 argc--;
380 argv++;
381 break;
382 case 'v':
383 break;
384 case 'w':
385 flags &= ~MS_RDONLY;
386 break;
387 case 'a':
388 all = 1;
389 break;
390 default:
391 usage(mount_usage);
392 return 1;
393 }
394 argc--;
395 argv++;
396 }
397
398 if (all == 1) {
399 struct mntent *m;
400 FILE *f = setmntent("/etc/fstab", "r");
401
402 if (f == NULL) {
403 return 1;
404 }
405
406 // FIXME: Combine read routine (make new function) with unmount_all to save space.
407
408 while ((m = getmntent(f)) != NULL) {
409 // If the file system isn't noauto, and isn't mounted on /, mount it
410 if ((!strstr(m->mnt_opts, "noauto")) && (m->mnt_dir[1] != '\0')
411 && !((m->mnt_type[0] == 's') && (m->mnt_type[1] == 'w'))
412 && !((m->mnt_type[0] == 'n') && (m->mnt_type[1] == 'f'))) {
413 mount_one(m->mnt_fsname, m->mnt_dir, m->mnt_type, flags, m->mnt_opts, noMtab, fake);
414 }
415 }
416
417 endmntent(f);
418 } else {
419 if ( argc >= 3 ) {
420 if ( mount_one( argv[1], argv[2], filesystemType, flags, string_flags, noMtab, fake) == 0 )
421 return 0;
422 else
423 return 1;
424 } else {
425 usage(mount_usage);
426 return 1;
427 }
428 }
429 return 0;
430}
diff --git a/util-linux/umount.c b/util-linux/umount.c
new file mode 100644
index 000000000..4efc9f9d9
--- /dev/null
+++ b/util-linux/umount.c
@@ -0,0 +1,135 @@
1#include "internal.h"
2#include <stdlib.h>
3#include <unistd.h>
4#include <errno.h>
5#include <string.h>
6#include <stdio.h>
7#include <mntent.h>
8#include <sys/mount.h>
9
10const char umount_usage[] = "umount {filesystem|directory}\n"
11"\tumount -a\n"
12"\n"
13"\tUnmount a filesystem.\n"
14"\t-a:\tUnmounts all mounted filesystems.\n";
15
16static char *
17stralloc(const char * string)
18{
19 int length = strlen(string) + 1;
20 char * n = malloc(length);
21 memcpy(n, string, length);
22 return n;
23}
24
25extern void
26erase_mtab(const char * name)
27{
28 struct mntent entries[100];
29 int count = 0;
30 FILE * mountTable = setmntent("/etc/mtab", "r");
31 struct mntent * m;
32
33 if ( mountTable == 0
34 && (mountTable = setmntent("/proc/mounts", "r")) == 0 ) {
35 name_and_error("/etc/mtab");
36 return;
37 }
38
39 while ( (m = getmntent(mountTable)) != 0 ) {
40 entries[count].mnt_fsname = stralloc(m->mnt_fsname);
41 entries[count].mnt_dir = stralloc(m->mnt_dir);
42 entries[count].mnt_type = stralloc(m->mnt_type);
43 entries[count].mnt_opts = stralloc(m->mnt_opts);
44 entries[count].mnt_freq = m->mnt_freq;
45 entries[count].mnt_passno = m->mnt_passno;
46 count++;
47 }
48 endmntent(mountTable);
49 if ( (mountTable = setmntent("/etc/mtab", "w")) ) {
50 int i;
51 for ( i = 0; i < count; i++ ) {
52 int result = ( strcmp(entries[i].mnt_fsname, name) == 0
53 || strcmp(entries[i].mnt_dir, name) == 0 );
54
55 if ( result )
56 continue;
57 else
58 addmntent(mountTable, &entries[i]);
59 }
60 endmntent(mountTable);
61 }
62 else if ( errno != EROFS )
63 name_and_error("/etc/mtab");
64}
65
66static int
67umount_all(int noMtab)
68{
69 struct mntent entries[100];
70 int count = 0;
71 FILE * mountTable = setmntent("/etc/mtab", "r");
72 struct mntent * m;
73 int status = 0;
74
75 if ( mountTable == 0
76 && (mountTable = setmntent("/proc/mounts", "r")) == 0 ) {
77 name_and_error("/etc/mtab");
78 return 1;
79 }
80
81 while ( (m = getmntent(mountTable)) != 0 ) {
82 entries[count].mnt_fsname = stralloc(m->mnt_fsname);
83 count++;
84 }
85 endmntent(mountTable);
86
87 while ( count > 0 ) {
88 int result = umount(entries[--count].mnt_fsname) == 0;
89 /* free(entries[count].mnt_fsname); */
90 if ( result ) {
91 if ( !noMtab )
92 erase_mtab(entries[count].mnt_fsname);
93 }
94 else {
95 status = 1;
96 name_and_error(entries[count].mnt_fsname);
97 }
98 }
99 return status;
100}
101
102extern int
103do_umount(const char * name, int noMtab)
104{
105 if ( umount(name) == 0 ) {
106 if ( !noMtab )
107 erase_mtab(name);
108 return 0;
109 }
110 return 1;
111}
112
113extern int
114umount_main(struct FileInfo * i, int argc, char * * argv)
115{
116 int noMtab = 0;
117
118 if ( argv[1][0] == '-' ) {
119 switch ( argv[1][1] ) {
120 case 'a':
121 return umount_all(noMtab);
122 case 'n':
123 noMtab = 1;
124 break;
125 default:
126 usage(umount_usage);
127 return 1;
128 }
129 }
130 if ( do_umount(argv[1],noMtab) != 0 ) {
131 fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
132 return 1;
133 }
134 return 0;
135}
diff --git a/utility.c b/utility.c
new file mode 100644
index 000000000..68259710b
--- /dev/null
+++ b/utility.c
@@ -0,0 +1,1181 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
21 * Permission has been granted to redistribute this code under the GPL.
22 *
23 */
24
25#include "utility.h"
26
27#if 0
28
29extern char *
30join_paths(char * buffer, const char * a, const char * b)
31{
32 int length = 0;
33
34 if ( a && *a ) {
35 length = strlen(a);
36 memcpy(buffer, a, length);
37 }
38 if ( b && *b ) {
39 if ( length > 0 && buffer[length - 1] != '/' )
40 buffer[length++] = '/';
41 if ( *b == '/' )
42 b++;
43 strcpy(&buffer[length], b);
44 }
45 return buffer;
46}
47
48#endif
49
50
51
52
53
54
55static CHUNK * chunkList;
56
57extern void
58name_and_error(const char * name)
59{
60 fprintf(stderr, "%s: %s\n", name, strerror(errno));
61}
62
63
64
65/*
66 * Return the standard ls-like mode string from a file mode.
67 * This is static and so is overwritten on each call.
68 */
69const char *
70modeString(int mode)
71{
72 static char buf[12];
73
74 strcpy(buf, "----------");
75
76 /*
77 * Fill in the file type.
78 */
79 if (S_ISDIR(mode))
80 buf[0] = 'd';
81 if (S_ISCHR(mode))
82 buf[0] = 'c';
83 if (S_ISBLK(mode))
84 buf[0] = 'b';
85 if (S_ISFIFO(mode))
86 buf[0] = 'p';
87#ifdef S_ISLNK
88 if (S_ISLNK(mode))
89 buf[0] = 'l';
90#endif
91#ifdef S_ISSOCK
92 if (S_ISSOCK(mode))
93 buf[0] = 's';
94#endif
95
96 /*
97 * Now fill in the normal file permissions.
98 */
99 if (mode & S_IRUSR)
100 buf[1] = 'r';
101 if (mode & S_IWUSR)
102 buf[2] = 'w';
103 if (mode & S_IXUSR)
104 buf[3] = 'x';
105 if (mode & S_IRGRP)
106 buf[4] = 'r';
107 if (mode & S_IWGRP)
108 buf[5] = 'w';
109 if (mode & S_IXGRP)
110 buf[6] = 'x';
111 if (mode & S_IROTH)
112 buf[7] = 'r';
113 if (mode & S_IWOTH)
114 buf[8] = 'w';
115 if (mode & S_IXOTH)
116 buf[9] = 'x';
117
118 /*
119 * Finally fill in magic stuff like suid and sticky text.
120 */
121 if (mode & S_ISUID)
122 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
123 if (mode & S_ISGID)
124 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
125 if (mode & S_ISVTX)
126 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
127
128 return buf;
129}
130
131
132/*
133 * Get the time string to be used for a file.
134 * This is down to the minute for new files, but only the date for old files.
135 * The string is returned from a static buffer, and so is overwritten for
136 * each call.
137 */
138const char *
139timeString(time_t timeVal)
140{
141 time_t now;
142 char * str;
143 static char buf[26];
144
145 time(&now);
146
147 str = ctime(&timeVal);
148
149 strcpy(buf, &str[4]);
150 buf[12] = '\0';
151
152 if ((timeVal > now) || (timeVal < now - 365*24*60*60L))
153 {
154 strcpy(&buf[7], &str[20]);
155 buf[11] = '\0';
156 }
157
158 return buf;
159}
160
161
162/*
163 * Return TRUE if a fileName is a directory.
164 * Nonexistant files return FALSE.
165 */
166BOOL
167isDirectory(const char * name)
168{
169 struct stat statBuf;
170
171 if (stat(name, &statBuf) < 0)
172 return FALSE;
173
174 return S_ISDIR(statBuf.st_mode);
175}
176
177
178/*
179 * Return TRUE if a filename is a block or character device.
180 * Nonexistant files return FALSE.
181 */
182BOOL
183isDevice(const char * name)
184{
185 struct stat statBuf;
186
187 if (stat(name, &statBuf) < 0)
188 return FALSE;
189
190 return S_ISBLK(statBuf.st_mode) || S_ISCHR(statBuf.st_mode);
191}
192
193
194/*
195 * Copy one file to another, while possibly preserving its modes, times,
196 * and modes. Returns TRUE if successful, or FALSE on a failure with an
197 * error message output. (Failure is not indicted if the attributes cannot
198 * be set.)
199 */
200BOOL
201copyFile(
202 const char * srcName,
203 const char * destName,
204 BOOL setModes
205)
206{
207 int rfd;
208 int wfd;
209 int rcc;
210 char buf[BUF_SIZE];
211 struct stat statBuf1;
212 struct stat statBuf2;
213 struct utimbuf times;
214
215 if (stat(srcName, &statBuf1) < 0)
216 {
217 perror(srcName);
218
219 return FALSE;
220 }
221
222 if (stat(destName, &statBuf2) < 0)
223 {
224 statBuf2.st_ino = -1;
225 statBuf2.st_dev = -1;
226 }
227
228 if ((statBuf1.st_dev == statBuf2.st_dev) &&
229 (statBuf1.st_ino == statBuf2.st_ino))
230 {
231 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
232
233 return FALSE;
234 }
235
236 rfd = open(srcName, O_RDONLY);
237
238 if (rfd < 0)
239 {
240 perror(srcName);
241
242 return FALSE;
243 }
244
245 wfd = creat(destName, statBuf1.st_mode);
246
247 if (wfd < 0)
248 {
249 perror(destName);
250 close(rfd);
251
252 return FALSE;
253 }
254
255 while ((rcc = read(rfd, buf, sizeof(buf))) > 0)
256 {
257 if (fullWrite(wfd, buf, rcc) < 0)
258 goto error_exit;
259 }
260
261 if (rcc < 0)
262 {
263 perror(srcName);
264 goto error_exit;
265 }
266
267 (void) close(rfd);
268
269 if (close(wfd) < 0)
270 {
271 perror(destName);
272
273 return FALSE;
274 }
275
276 if (setModes)
277 {
278 (void) chmod(destName, statBuf1.st_mode);
279
280 (void) chown(destName, statBuf1.st_uid, statBuf1.st_gid);
281
282 times.actime = statBuf1.st_atime;
283 times.modtime = statBuf1.st_mtime;
284
285 (void) utime(destName, &times);
286 }
287
288 return TRUE;
289
290
291error_exit:
292 close(rfd);
293 close(wfd);
294
295 return FALSE;
296}
297
298
299/*
300 * Build a path name from the specified directory name and file name.
301 * If the directory name is NULL, then the original fileName is returned.
302 * The built path is in a static area, and is overwritten for each call.
303 */
304const char *
305buildName(const char * dirName, const char * fileName)
306{
307 const char * cp;
308 static char buf[PATH_LEN];
309
310 if ((dirName == NULL) || (*dirName == '\0'))
311 return fileName;
312
313 cp = strrchr(fileName, '/');
314
315 if (cp)
316 fileName = cp + 1;
317
318 strcpy(buf, dirName);
319 strcat(buf, "/");
320 strcat(buf, fileName);
321
322 return buf;
323}
324
325
326
327/*
328 * Expand the wildcards in a fileName wildcard pattern, if any.
329 * Returns an argument list with matching fileNames in sorted order.
330 * The expanded names are stored in memory chunks which can later all
331 * be freed at once. The returned list is only valid until the next
332 * call or until the next command. Returns zero if the name is not a
333 * wildcard, or returns the count of matched files if the name is a
334 * wildcard and there was at least one match, or returns -1 if either
335 * no fileNames matched or there was an allocation error.
336 */
337int
338expandWildCards(const char * fileNamePattern, const char *** retFileTable)
339{
340 const char * last;
341 const char * cp1;
342 const char * cp2;
343 const char * cp3;
344 char * str;
345 DIR * dirp;
346 struct dirent * dp;
347 int dirLen;
348 int newFileTableSize;
349 char ** newFileTable;
350 char dirName[PATH_LEN];
351
352 static int fileCount;
353 static int fileTableSize;
354 static char ** fileTable;
355
356 /*
357 * Clear the return values until we know their final values.
358 */
359 fileCount = 0;
360 *retFileTable = NULL;
361
362 /*
363 * Scan the file name pattern for any wildcard characters.
364 */
365 cp1 = strchr(fileNamePattern, '*');
366 cp2 = strchr(fileNamePattern, '?');
367 cp3 = strchr(fileNamePattern, '[');
368
369 /*
370 * If there are no wildcard characters then return zero to
371 * indicate that there was actually no wildcard pattern.
372 */
373 if ((cp1 == NULL) && (cp2 == NULL) && (cp3 == NULL))
374 return 0;
375
376 /*
377 * There are wildcards in the specified filename.
378 * Get the last component of the file name.
379 */
380 last = strrchr(fileNamePattern, '/');
381
382 if (last)
383 last++;
384 else
385 last = fileNamePattern;
386
387 /*
388 * If any wildcards were found before the last filename component
389 * then return an error.
390 */
391 if ((cp1 && (cp1 < last)) || (cp2 && (cp2 < last)) ||
392 (cp3 && (cp3 < last)))
393 {
394 fprintf(stderr,
395 "Wildcards only implemented for last file name component\n");
396
397 return -1;
398 }
399
400 /*
401 * Assume at first that we are scanning the current directory.
402 */
403 dirName[0] = '.';
404 dirName[1] = '\0';
405
406 /*
407 * If there was a directory given as part of the file name then
408 * copy it and null terminate it.
409 */
410 if (last != fileNamePattern)
411 {
412 memcpy(dirName, fileNamePattern, last - fileNamePattern);
413 dirName[last - fileNamePattern - 1] = '\0';
414
415 if (dirName[0] == '\0')
416 {
417 dirName[0] = '/';
418 dirName[1] = '\0';
419 }
420 }
421
422 /*
423 * Open the directory containing the files to be checked.
424 */
425 dirp = opendir(dirName);
426
427 if (dirp == NULL)
428 {
429 perror(dirName);
430
431 return -1;
432 }
433
434 /*
435 * Prepare the directory name for use in making full path names.
436 */
437 dirLen = strlen(dirName);
438
439 if (last == fileNamePattern)
440 {
441 dirLen = 0;
442 dirName[0] = '\0';
443 }
444 else if (dirName[dirLen - 1] != '/')
445 {
446 dirName[dirLen++] = '/';
447 dirName[dirLen] = '\0';
448 }
449
450 /*
451 * Find all of the files in the directory and check them against
452 * the wildcard pattern.
453 */
454 while ((dp = readdir(dirp)) != NULL)
455 {
456 /*
457 * Skip the current and parent directories.
458 */
459 if ((strcmp(dp->d_name, ".") == 0) ||
460 (strcmp(dp->d_name, "..") == 0))
461 {
462 continue;
463 }
464
465 /*
466 * If the file name doesn't match the pattern then skip it.
467 */
468 if (!match(dp->d_name, last))
469 continue;
470
471 /*
472 * This file name is selected.
473 * See if we need to reallocate the file name table.
474 */
475 if (fileCount >= fileTableSize)
476 {
477 /*
478 * Increment the file table size and reallocate it.
479 */
480 newFileTableSize = fileTableSize + EXPAND_ALLOC;
481
482 newFileTable = (char **) realloc((char *) fileTable,
483 (newFileTableSize * sizeof(char *)));
484
485 if (newFileTable == NULL)
486 {
487 fprintf(stderr, "Cannot allocate file list\n");
488 closedir(dirp);
489
490 return -1;
491 }
492
493 fileTable = newFileTable;
494 fileTableSize = newFileTableSize;
495 }
496
497 /*
498 * Allocate space for storing the file name in a chunk.
499 */
500 str = getChunk(dirLen + strlen(dp->d_name) + 1);
501
502 if (str == NULL)
503 {
504 fprintf(stderr, "No memory for file name\n");
505 closedir(dirp);
506
507 return -1;
508 }
509
510 /*
511 * Save the file name in the chunk.
512 */
513 if (dirLen)
514 memcpy(str, dirName, dirLen);
515
516 strcpy(str + dirLen, dp->d_name);
517
518 /*
519 * Save the allocated file name into the file table.
520 */
521 fileTable[fileCount++] = str;
522 }
523
524 /*
525 * Close the directory and check for any matches.
526 */
527 closedir(dirp);
528
529 if (fileCount == 0)
530 {
531 fprintf(stderr, "No matches\n");
532
533 return -1;
534 }
535
536 /*
537 * Sort the list of file names.
538 */
539 qsort((void *) fileTable, fileCount, sizeof(char *), nameSort);
540
541 /*
542 * Return the file list and count.
543 */
544 *retFileTable = (const char **) fileTable;
545
546 return fileCount;
547}
548
549
550/*
551 * Sort routine for list of fileNames.
552 */
553int
554nameSort(const void * p1, const void * p2)
555{
556 const char ** s1;
557 const char ** s2;
558
559 s1 = (const char **) p1;
560 s2 = (const char **) p2;
561
562 return strcmp(*s1, *s2);
563}
564
565
566
567/*
568 * Routine to see if a text string is matched by a wildcard pattern.
569 * Returns TRUE if the text is matched, or FALSE if it is not matched
570 * or if the pattern is invalid.
571 * * matches zero or more characters
572 * ? matches a single character
573 * [abc] matches 'a', 'b' or 'c'
574 * \c quotes character c
575 * Adapted from code written by Ingo Wilken.
576 */
577BOOL
578match(const char * text, const char * pattern)
579{
580 const char * retryPat;
581 const char * retryText;
582 int ch;
583 BOOL found;
584
585 retryPat = NULL;
586 retryText = NULL;
587
588 while (*text || *pattern)
589 {
590 ch = *pattern++;
591
592 switch (ch)
593 {
594 case '*':
595 retryPat = pattern;
596 retryText = text;
597 break;
598
599 case '[':
600 found = FALSE;
601
602 while ((ch = *pattern++) != ']')
603 {
604 if (ch == '\\')
605 ch = *pattern++;
606
607 if (ch == '\0')
608 return FALSE;
609
610 if (*text == ch)
611 found = TRUE;
612 }
613
614 if (!found)
615 {
616 pattern = retryPat;
617 text = ++retryText;
618 }
619
620 /* fall into next case */
621
622 case '?':
623 if (*text++ == '\0')
624 return FALSE;
625
626 break;
627
628 case '\\':
629 ch = *pattern++;
630
631 if (ch == '\0')
632 return FALSE;
633
634 /* fall into next case */
635
636 default:
637 if (*text == ch)
638 {
639 if (*text)
640 text++;
641 break;
642 }
643
644 if (*text)
645 {
646 pattern = retryPat;
647 text = ++retryText;
648 break;
649 }
650
651 return FALSE;
652 }
653
654 if (pattern == NULL)
655 return FALSE;
656 }
657
658 return TRUE;
659}
660
661
662/*
663 * Take a command string and break it up into an argc, argv list while
664 * handling quoting and wildcards. The returned argument list and
665 * strings are in static memory, and so are overwritten on each call.
666 * The argument list is ended with a NULL pointer for convenience.
667 * Returns TRUE if successful, or FALSE on an error with a message
668 * already output.
669 */
670BOOL
671makeArgs(const char * cmd, int * retArgc, const char *** retArgv)
672{
673 const char * argument;
674 char * cp;
675 char * cpOut;
676 char * newStrings;
677 const char ** fileTable;
678 const char ** newArgTable;
679 int newArgTableSize;
680 int fileCount;
681 int len;
682 int ch;
683 int quote;
684 BOOL quotedWildCards;
685 BOOL unquotedWildCards;
686
687 static int stringsLength;
688 static char * strings;
689 static int argCount;
690 static int argTableSize;
691 static const char ** argTable;
692
693 /*
694 * Clear the returned values until we know them.
695 */
696 argCount = 0;
697 *retArgc = 0;
698 *retArgv = NULL;
699
700 /*
701 * Copy the command string into a buffer that we can modify,
702 * reallocating it if necessary.
703 */
704 len = strlen(cmd) + 1;
705
706 if (len > stringsLength)
707 {
708 newStrings = realloc(strings, len);
709
710 if (newStrings == NULL)
711 {
712 fprintf(stderr, "Cannot allocate string\n");
713
714 return FALSE;
715 }
716
717 strings = newStrings;
718 stringsLength = len;
719 }
720
721 memcpy(strings, cmd, len);
722 cp = strings;
723
724 /*
725 * Keep parsing the command string as long as there are any
726 * arguments left.
727 */
728 while (*cp)
729 {
730 /*
731 * Save the beginning of this argument.
732 */
733 argument = cp;
734 cpOut = cp;
735
736 /*
737 * Reset quoting and wildcarding for this argument.
738 */
739 quote = '\0';
740 quotedWildCards = FALSE;
741 unquotedWildCards = FALSE;
742
743 /*
744 * Loop over the string collecting the next argument while
745 * looking for quoted strings or quoted characters, and
746 * remembering whether there are any wildcard characters
747 * in the argument.
748 */
749 while (*cp)
750 {
751 ch = *cp++;
752
753 /*
754 * If we are not in a quote and we see a blank then
755 * this argument is done.
756 */
757 if (isBlank(ch) && (quote == '\0'))
758 break;
759
760 /*
761 * If we see a backslash then accept the next
762 * character no matter what it is.
763 */
764 if (ch == '\\')
765 {
766 ch = *cp++;
767
768 /*
769 * Make sure there is a next character.
770 */
771 if (ch == '\0')
772 {
773 fprintf(stderr,
774 "Bad quoted character\n");
775
776 return FALSE;
777 }
778
779 /*
780 * Remember whether the quoted character
781 * is a wildcard.
782 */
783 if (isWildCard(ch))
784 quotedWildCards = TRUE;
785
786 *cpOut++ = ch;
787
788 continue;
789 }
790
791 /*
792 * If we see one of the wildcard characters then
793 * remember whether it was seen inside or outside
794 * of quotes.
795 */
796 if (isWildCard(ch))
797 {
798 if (quote)
799 quotedWildCards = TRUE;
800 else
801 unquotedWildCards = TRUE;
802 }
803
804 /*
805 * If we were in a quote and we saw the same quote
806 * character again then the quote is done.
807 */
808 if (ch == quote)
809 {
810 quote = '\0';
811
812 continue;
813 }
814
815 /*
816 * If we weren't in a quote and we see either type
817 * of quote character, then remember that we are
818 * now inside of a quote.
819 */
820 if ((quote == '\0') && ((ch == '\'') || (ch == '"')))
821 {
822 quote = ch;
823
824 continue;
825 }
826
827 /*
828 * Store the character.
829 */
830 *cpOut++ = ch;
831 }
832
833 /*
834 * Make sure that quoting is terminated properly.
835 */
836 if (quote)
837 {
838 fprintf(stderr, "Unmatched quote character\n");
839
840 return FALSE;
841 }
842
843 /*
844 * Null terminate the argument if it had shrunk, and then
845 * skip over all blanks to the next argument, nulling them
846 * out too.
847 */
848 if (cp != cpOut)
849 *cpOut = '\0';
850
851 while (isBlank(*cp))
852 *cp++ = '\0';
853
854 /*
855 * If both quoted and unquoted wildcards were used then
856 * complain since we don't handle them properly.
857 */
858 if (quotedWildCards && unquotedWildCards)
859 {
860 fprintf(stderr,
861 "Cannot use quoted and unquoted wildcards\n");
862
863 return FALSE;
864 }
865
866 /*
867 * Expand the argument into the matching filenames or accept
868 * it as is depending on whether there were any unquoted
869 * wildcard characters in it.
870 */
871 if (unquotedWildCards)
872 {
873 /*
874 * Expand the argument into the matching filenames.
875 */
876 fileCount = expandWildCards(argument, &fileTable);
877
878 /*
879 * Return an error if the wildcards failed to match.
880 */
881 if (fileCount < 0)
882 return FALSE;
883
884 if (fileCount == 0)
885 {
886 fprintf(stderr, "Wildcard expansion error\n");
887
888 return FALSE;
889 }
890 }
891 else
892 {
893 /*
894 * Set up to only store the argument itself.
895 */
896 fileTable = &argument;
897 fileCount = 1;
898 }
899
900 /*
901 * Now reallocate the argument table to hold the file name.
902 */
903 if (argCount + fileCount >= argTableSize)
904 {
905 newArgTableSize = argCount + fileCount + 1;
906
907 newArgTable = (const char **) realloc(argTable,
908 (sizeof(const char *) * newArgTableSize));
909
910 if (newArgTable == NULL)
911 {
912 fprintf(stderr, "No memory for arg list\n");
913
914 return FALSE;
915 }
916
917 argTable = newArgTable;
918 argTableSize = newArgTableSize;
919 }
920
921 /*
922 * Copy the new arguments to the end of the old ones.
923 */
924 memcpy((void *) &argTable[argCount], (const void *) fileTable,
925 (sizeof(const char **) * fileCount));
926
927 /*
928 * Add to the argument count.
929 */
930 argCount += fileCount;
931 }
932
933 /*
934 * Null terminate the argument list and return it.
935 */
936 argTable[argCount] = NULL;
937
938 *retArgc = argCount;
939 *retArgv = argTable;
940
941 return TRUE;
942}
943
944
945/*
946 * Make a NULL-terminated string out of an argc, argv pair.
947 * Returns TRUE if successful, or FALSE if the string is too long,
948 * with an error message given. This does not handle spaces within
949 * arguments correctly.
950 */
951BOOL
952makeString(
953 int argc,
954 const char ** argv,
955 char * buf,
956 int bufLen
957)
958{
959 int len;
960
961 while (argc-- > 0)
962 {
963 len = strlen(*argv);
964
965 if (len >= bufLen)
966 {
967 fprintf(stderr, "Argument string too long\n");
968
969 return FALSE;
970 }
971
972 strcpy(buf, *argv++);
973
974 buf += len;
975 bufLen -= len;
976
977 if (argc)
978 *buf++ = ' ';
979
980 bufLen--;
981 }
982
983 *buf = '\0';
984
985 return TRUE;
986}
987
988
989/*
990 * Allocate a chunk of memory (like malloc).
991 * The difference, though, is that the memory allocated is put on a
992 * list of chunks which can be freed all at one time. You CAN NOT free
993 * an individual chunk.
994 */
995char *
996getChunk(int size)
997{
998 CHUNK * chunk;
999
1000 if (size < CHUNK_INIT_SIZE)
1001 size = CHUNK_INIT_SIZE;
1002
1003 chunk = (CHUNK *) malloc(size + sizeof(CHUNK) - CHUNK_INIT_SIZE);
1004
1005 if (chunk == NULL)
1006 return NULL;
1007
1008 chunk->next = chunkList;
1009 chunkList = chunk;
1010
1011 return chunk->data;
1012}
1013
1014
1015/*
1016 * Duplicate a string value using the chunk allocator.
1017 * The returned string cannot be individually freed, but can only be freed
1018 * with other strings when freeChunks is called. Returns NULL on failure.
1019 */
1020char *
1021chunkstrdup(const char * str)
1022{
1023 int len;
1024 char * newStr;
1025
1026 len = strlen(str) + 1;
1027 newStr = getChunk(len);
1028
1029 if (newStr)
1030 memcpy(newStr, str, len);
1031
1032 return newStr;
1033}
1034
1035
1036/*
1037 * Free all chunks of memory that had been allocated since the last
1038 * call to this routine.
1039 */
1040void
1041freeChunks(void)
1042{
1043 CHUNK * chunk;
1044
1045 while (chunkList)
1046 {
1047 chunk = chunkList;
1048 chunkList = chunk->next;
1049 free((char *) chunk);
1050 }
1051}
1052
1053
1054/*
1055 * Write all of the supplied buffer out to a file.
1056 * This does multiple writes as necessary.
1057 * Returns the amount written, or -1 on an error.
1058 */
1059int
1060fullWrite(int fd, const char * buf, int len)
1061{
1062 int cc;
1063 int total;
1064
1065 total = 0;
1066
1067 while (len > 0)
1068 {
1069 cc = write(fd, buf, len);
1070
1071 if (cc < 0)
1072 return -1;
1073
1074 buf += cc;
1075 total+= cc;
1076 len -= cc;
1077 }
1078
1079 return total;
1080}
1081
1082
1083/*
1084 * Read all of the supplied buffer from a file.
1085 * This does multiple reads as necessary.
1086 * Returns the amount read, or -1 on an error.
1087 * A short read is returned on an end of file.
1088 */
1089int
1090fullRead(int fd, char * buf, int len)
1091{
1092 int cc;
1093 int total;
1094
1095 total = 0;
1096
1097 while (len > 0)
1098 {
1099 cc = read(fd, buf, len);
1100
1101 if (cc < 0)
1102 return -1;
1103
1104 if (cc == 0)
1105 break;
1106
1107 buf += cc;
1108 total+= cc;
1109 len -= cc;
1110 }
1111
1112 return total;
1113}
1114
1115
1116/*
1117 * Read all of the supplied buffer from a file.
1118 * This does multiple reads as necessary.
1119 * Returns the amount read, or -1 on an error.
1120 * A short read is returned on an end of file.
1121 */
1122int
1123recursive( const char *fileName, BOOL followLinks, const char* pattern,
1124 int (*fileAction)(const char* fileName, const struct stat* statbuf),
1125 int (*dirAction)(const char* fileName, const struct stat* statbuf))
1126{
1127 int status;
1128 struct stat statbuf;
1129 struct dirent* next;
1130
1131 if (followLinks)
1132 status = stat(fileName, &statbuf);
1133 else
1134 status = lstat(fileName, &statbuf);
1135
1136 if (status < 0) {
1137 perror(fileName);
1138 return( -1);
1139 }
1140
1141 if (S_ISREG(statbuf.st_mode)) {
1142 if (match(fileName, pattern)) {
1143 if (fileAction==NULL)
1144 fprintf( stdout, "%s\n", fileName);
1145 else
1146 return(fileAction(fileName, &statbuf));
1147 }
1148 }
1149 else if (S_ISDIR(statbuf.st_mode)) {
1150 if (dirAction==NULL) {
1151 DIR *dir;
1152 if (! match(fileName, pattern))
1153 return 1;
1154 dir = opendir(fileName);
1155 if (!dir) {
1156 perror(fileName);
1157 return( -1);
1158 }
1159 while ((next = readdir (dir)) != NULL) {
1160 status = recursive(fileName, followLinks, pattern, fileAction, dirAction);
1161 if (status < 0) {
1162 closedir(dir);
1163 return(status);
1164 }
1165 }
1166 status = closedir (dir);
1167 if (status < 0) {
1168 perror(fileName);
1169 return( -1);
1170 }
1171 }
1172 else
1173 return(dirAction(fileName, &statbuf));
1174 }
1175 return( 1);
1176
1177}
1178
1179
1180
1181/* END CODE */
diff --git a/utility.h b/utility.h
new file mode 100644
index 000000000..7b275baa4
--- /dev/null
+++ b/utility.h
@@ -0,0 +1,73 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
21 * Permission has been granted to redistribute this code under the GPL.
22 *
23 */
24
25#include "internal.h"
26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
29#include <fcntl.h>
30//#include <sys/types.h>
31//#include <sys/stat.h>
32#include <dirent.h>
33#include <time.h>
34#include <utime.h>
35
36/*
37 * A chunk of data.
38 * Chunks contain data which is allocated as needed, but which is
39 * not freed until all of the data needs freeing, such as at
40 * the beginning of the next command.
41 */
42typedef struct chunk CHUNK;
43#define CHUNK_INIT_SIZE 4
44
45struct chunk {
46 CHUNK *next;
47 char data[CHUNK_INIT_SIZE]; /* actually of varying length */
48};
49
50const char *modeString(int mode);
51const char *timeString(time_t timeVal);
52BOOL isDirectory(const char *name);
53BOOL isDevice(const char *name);
54BOOL copyFile(const char *srcName, const char *destName, BOOL setModes);
55const char *buildName(const char *dirName, const char *fileName);
56BOOL match(const char *text, const char *pattern);
57BOOL makeArgs(const char *cmd, int *retArgc, const char ***retArgv);
58BOOL makeString(int argc, const char **argv, char *buf, int bufLen);
59char *getChunk(int size);
60char *chunkstrdup(const char *str);
61void freeChunks(void);
62int fullWrite(int fd, const char *buf, int len);
63int fullRead(int fd, char *buf, int len);
64int
65recursive(const char *fileName, BOOL followLinks, const char *pattern,
66 int (*fileAction) (const char *fileName,
67 const struct stat * statbuf),
68 int (*dirAction) (const char *fileName,
69 const struct stat * statbuf));
70
71int nameSort(const void *p1, const void *p2);
72int expandWildCards(const char *fileNamePattern,
73 const char ***retFileTable);
diff --git a/zcat.c b/zcat.c
new file mode 100644
index 000000000..50fcdfc47
--- /dev/null
+++ b/zcat.c
@@ -0,0 +1,2262 @@
1/* zcat : stripped version based on gzip sources
2 Sven Rudolph <sr1@inf.tu-dresden.de>
3 */
4
5#include "internal.h"
6
7const char zcat_usage[] = "zcat\n"
8"\n"
9"\tuncompress gzipped data from stdin to stdout\n";
10
11
12
13/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
14 * Copyright (C) 1992-1993 Jean-loup Gailly
15 * The unzip code was written and put in the public domain by Mark Adler.
16 * Portions of the lzw code are derived from the public domain 'compress'
17 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
18 * Ken Turkowski, Dave Mack and Peter Jannesen.
19 *
20 * See the license_msg below and the file COPYING for the software license.
21 * See the file algorithm.doc for the compression algorithms and file formats.
22 */
23
24#if 0
25static char *license_msg[] = {
26" Copyright (C) 1992-1993 Jean-loup Gailly",
27" This program is free software; you can redistribute it and/or modify",
28" it under the terms of the GNU General Public License as published by",
29" the Free Software Foundation; either version 2, or (at your option)",
30" any later version.",
31"",
32" This program is distributed in the hope that it will be useful,",
33" but WITHOUT ANY WARRANTY; without even the implied warranty of",
34" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
35" GNU General Public License for more details.",
36"",
37" You should have received a copy of the GNU General Public License",
38" along with this program; if not, write to the Free Software",
39" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
400};
41#endif
42
43/* Compress files with zip algorithm and 'compress' interface.
44 * See usage() and help() functions below for all options.
45 * Outputs:
46 * file.gz: compressed file with same mode, owner, and utimes
47 * or stdout with -c option or if stdin used as input.
48 * If the output file name had to be truncated, the original name is kept
49 * in the compressed file.
50 * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
51 *
52 * Using gz on MSDOS would create too many file name conflicts. For
53 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
54 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
55 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
56 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
57 *
58 * For the meaning of all compilation flags, see comments in Makefile.in.
59 */
60
61#ifdef RCSID
62static char rcsid[] = "$Id: zcat.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
63#endif
64
65#include <ctype.h>
66#include <sys/types.h>
67#include <signal.h>
68#include <sys/stat.h>
69#include <errno.h>
70
71/* #include "tailor.h" */
72
73/* tailor.h -- target dependent definitions
74 * Copyright (C) 1992-1993 Jean-loup Gailly.
75 * This is free software; you can redistribute it and/or modify it under the
76 * terms of the GNU General Public License, see the file COPYING.
77 */
78
79/* The target dependent definitions should be defined here only.
80 * The target dependent functions should be defined in tailor.c.
81 */
82
83/* $Id: zcat.c,v 1.1 1999/10/05 16:24:56 andersen Exp $ */
84
85#define RECORD_IO 0
86
87#define get_char() get_byte()
88#define put_char(c) put_byte(c)
89
90/* #include "gzip.h" */
91
92/* gzip.h -- common declarations for all gzip modules
93 * Copyright (C) 1992-1993 Jean-loup Gailly.
94 * This is free software; you can redistribute it and/or modify it under the
95 * terms of the GNU General Public License, see the file COPYING.
96 */
97
98#if defined(__STDC__) || defined(PROTO)
99# define OF(args) args
100#else
101# define OF(args) ()
102#endif
103
104#ifdef __STDC__
105 typedef void *voidp;
106#else
107 typedef char *voidp;
108#endif
109
110/* I don't like nested includes, but the string and io functions are used
111 * too often
112 */
113#include <stdio.h>
114#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
115# include <string.h>
116# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
117# include <memory.h>
118# endif
119# define memzero(s, n) memset ((voidp)(s), 0, (n))
120#else
121# include <strings.h>
122# define strchr index
123# define strrchr rindex
124# define memcpy(d, s, n) bcopy((s), (d), (n))
125# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
126# define memzero(s, n) bzero((s), (n))
127#endif
128
129#ifndef RETSIGTYPE
130# define RETSIGTYPE void
131#endif
132
133#define local static
134
135typedef unsigned char uch;
136typedef unsigned short ush;
137typedef unsigned long ulg;
138
139/* Return codes from gzip */
140#define OK 0
141#define ERROR 1
142#define WARNING 2
143
144/* Compression methods (see algorithm.doc) */
145#define DEFLATED 8
146
147extern int method; /* compression method */
148
149/* To save memory for 16 bit systems, some arrays are overlaid between
150 * the various modules:
151 * deflate: prev+head window d_buf l_buf outbuf
152 * unlzw: tab_prefix tab_suffix stack inbuf outbuf
153 * inflate: window inbuf
154 * unpack: window inbuf prefix_len
155 * unlzh: left+right window c_table inbuf c_len
156 * For compression, input is done in window[]. For decompression, output
157 * is done in window except for unlzw.
158 */
159
160#ifndef INBUFSIZ
161# ifdef SMALL_MEM
162# define INBUFSIZ 0x2000 /* input buffer size */
163# else
164# define INBUFSIZ 0x8000 /* input buffer size */
165# endif
166#endif
167#define INBUF_EXTRA 64 /* required by unlzw() */
168
169#ifndef OUTBUFSIZ
170# ifdef SMALL_MEM
171# define OUTBUFSIZ 8192 /* output buffer size */
172# else
173# define OUTBUFSIZ 16384 /* output buffer size */
174# endif
175#endif
176#define OUTBUF_EXTRA 2048 /* required by unlzw() */
177
178#define SMALL_MEM
179
180#ifndef DIST_BUFSIZE
181# ifdef SMALL_MEM
182# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
183# else
184# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
185# endif
186#endif
187
188/*#define DYN_ALLOC*/
189
190#ifdef DYN_ALLOC
191# define EXTERN(type, array) extern type * array
192# define DECLARE(type, array, size) type * array
193# define ALLOC(type, array, size) { \
194 array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
195 if (array == NULL) error("insufficient memory"); \
196 }
197# define FREE(array) {if (array != NULL) free(array), array=NULL;}
198#else
199# define EXTERN(type, array) extern type array[]
200# define DECLARE(type, array, size) type array[size]
201# define ALLOC(type, array, size)
202# define FREE(array)
203#endif
204
205EXTERN(uch, inbuf); /* input buffer */
206EXTERN(uch, outbuf); /* output buffer */
207EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
208EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
209#define tab_suffix window
210#ifndef MAXSEG_64K
211# define tab_prefix prev /* hash link (see deflate.c) */
212# define head (prev+WSIZE) /* hash head (see deflate.c) */
213 EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
214#else
215# define tab_prefix0 prev
216# define head tab_prefix1
217 EXTERN(ush, tab_prefix0); /* prefix for even codes */
218 EXTERN(ush, tab_prefix1); /* prefix for odd codes */
219#endif
220
221extern unsigned insize; /* valid bytes in inbuf */
222extern unsigned inptr; /* index of next byte to be processed in inbuf */
223extern unsigned outcnt; /* bytes in output buffer */
224
225extern long bytes_in; /* number of input bytes */
226extern long bytes_out; /* number of output bytes */
227extern long header_bytes;/* number of bytes in gzip header */
228
229extern int ifd; /* input file descriptor */
230extern int ofd; /* output file descriptor */
231
232extern long ifile_size; /* input file size, -1 for devices (debug only) */
233
234typedef int file_t; /* Do not use stdio */
235#define NO_FILE (-1) /* in memory compression */
236
237
238#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
239
240/* gzip flag byte */
241#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
242#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
243#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
244#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
245#define COMMENT 0x10 /* bit 4 set: file comment present */
246#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
247#define RESERVED 0xC0 /* bit 6,7: reserved */
248
249#ifndef WSIZE
250# define WSIZE 0x8000 /* window size--must be a power of two, and */
251#endif /* at least 32K for zip's deflate method */
252
253#define MIN_MATCH 3
254#define MAX_MATCH 258
255/* The minimum and maximum match lengths */
256
257#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
258/* Minimum amount of lookahead, except at the end of the input file.
259 * See deflate.c for comments about the MIN_MATCH+1.
260 */
261
262#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
263/* In order to simplify the code, particularly on 16 bit machines, match
264 * distances are limited to MAX_DIST instead of WSIZE.
265 */
266
267extern int exit_code; /* program exit code */
268extern int verbose; /* be verbose (-v) */
269extern int level; /* compression level */
270extern int test; /* check .z file integrity */
271extern int to_stdout; /* output to stdout (-c) */
272extern int save_orig_name; /* set if original name must be saved */
273
274#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
275#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
276
277/* put_byte is used for the compressed output, put_ubyte for the
278 * uncompressed output. However unlzw() uses window for its
279 * suffix table instead of its output buffer, so it does not use put_ubyte
280 * (to be cleaned up).
281 */
282#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
283 flush_outbuf();}
284#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
285 flush_window();}
286
287/* Output a 16 bit value, lsb first */
288#define put_short(w) \
289{ if (outcnt < OUTBUFSIZ-2) { \
290 outbuf[outcnt++] = (uch) ((w) & 0xff); \
291 outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
292 } else { \
293 put_byte((uch)((w) & 0xff)); \
294 put_byte((uch)((ush)(w) >> 8)); \
295 } \
296}
297
298/* Output a 32 bit value to the bit stream, lsb first */
299#define put_long(n) { \
300 put_short((n) & 0xffff); \
301 put_short(((ulg)(n)) >> 16); \
302}
303
304#define seekable() 0 /* force sequential output */
305#define translate_eol 0 /* no option -a yet */
306
307#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
308
309/* Macros for getting two-byte and four-byte header values */
310#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
311#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
312
313/* Diagnostic functions */
314#ifdef DEBUG
315# define Assert(cond,msg) {if(!(cond)) error(msg);}
316# define Trace(x) fprintf x
317# define Tracev(x) {if (verbose) fprintf x ;}
318# define Tracevv(x) {if (verbose>1) fprintf x ;}
319# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
320# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
321#else
322# define Assert(cond,msg)
323# define Trace(x)
324# define Tracev(x)
325# define Tracevv(x)
326# define Tracec(c,x)
327# define Tracecv(c,x)
328#endif
329
330#define WARN(msg) {fprintf msg ; \
331 if (exit_code == OK) exit_code = WARNING;}
332
333 /* in unzip.c */
334extern int unzip OF((int in, int out));
335
336 /* in gzip.c */
337RETSIGTYPE abort_gzip OF((void));
338
339 /* in deflate.c */
340void lm_init OF((int pack_level, ush *flags));
341ulg deflate OF((void));
342
343 /* in trees.c */
344void ct_init OF((ush *attr, int *method));
345int ct_tally OF((int dist, int lc));
346ulg flush_block OF((char *buf, ulg stored_len, int eof));
347
348 /* in bits.c */
349void bi_init OF((file_t zipfile));
350void send_bits OF((int value, int length));
351unsigned bi_reverse OF((unsigned value, int length));
352void bi_windup OF((void));
353void copy_block OF((char *buf, unsigned len, int header));
354extern int (*read_buf) OF((char *buf, unsigned size));
355
356 /* in util.c: */
357extern int copy OF((int in, int out));
358extern ulg updcrc OF((uch *s, unsigned n));
359extern void clear_bufs OF((void));
360extern int fill_inbuf OF((int eof_ok));
361extern void flush_outbuf OF((void));
362extern void flush_window OF((void));
363extern void write_buf OF((int fd, voidp buf, unsigned cnt));
364#ifndef __linux__
365extern char *basename OF((char *fname));
366#endif /* not __linux__ */
367extern void error OF((char *m));
368extern void warn OF((char *a, char *b));
369extern void read_error OF((void));
370extern void write_error OF((void));
371extern voidp xmalloc OF((unsigned int size));
372
373 /* in inflate.c */
374extern int inflate OF((void));
375
376/* #include "lzw.h" */
377
378/* lzw.h -- define the lzw functions.
379 * Copyright (C) 1992-1993 Jean-loup Gailly.
380 * This is free software; you can redistribute it and/or modify it under the
381 * terms of the GNU General Public License, see the file COPYING.
382 */
383
384#if !defined(OF) && defined(lint)
385# include "gzip.h"
386#endif
387
388#ifndef BITS
389# define BITS 16
390#endif
391#define INIT_BITS 9 /* Initial number of bits per code */
392
393#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
394
395#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
396/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
397 * It's a pity that old uncompress does not check bit 0x20. That makes
398 * extension of the format actually undesirable because old compress
399 * would just crash on the new format instead of giving a meaningful
400 * error message. It does check the number of bits, but it's more
401 * helpful to say "unsupported format, get a new version" than
402 * "can only handle 16 bits".
403 */
404
405#define BLOCK_MODE 0x80
406/* Block compression: if table is full and compression rate is dropping,
407 * clear the dictionary.
408 */
409
410#define LZW_RESERVED 0x60 /* reserved bits */
411
412#define CLEAR 256 /* flush the dictionary */
413#define FIRST (CLEAR+1) /* first free entry */
414
415extern int maxbits; /* max bits per code for LZW */
416extern int block_mode; /* block compress mode -C compatible with 2.0 */
417
418extern int lzw OF((int in, int out));
419extern int unlzw OF((int in, int out));
420
421
422/* #include "revision.h" */
423
424/* revision.h -- define the version number
425 * Copyright (C) 1992-1993 Jean-loup Gailly.
426 * This is free software; you can redistribute it and/or modify it under the
427 * terms of the GNU General Public License, see the file COPYING.
428 */
429
430#define VERSION "1.2.4"
431#define PATCHLEVEL 0
432#define REVDATE "18 Aug 93"
433
434/* This version does not support compression into old compress format: */
435#ifdef LZW
436# undef LZW
437#endif
438
439/* $Id: zcat.c,v 1.1 1999/10/05 16:24:56 andersen Exp $ */
440
441/* #include "getopt.h" */
442
443/* Declarations for getopt.
444 Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
445
446 This program is free software; you can redistribute it and/or modify it
447 under the terms of the GNU General Public License as published by the
448 Free Software Foundation; either version 2, or (at your option) any
449 later version.
450
451 This program is distributed in the hope that it will be useful,
452 but WITHOUT ANY WARRANTY; without even the implied warranty of
453 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
454 GNU General Public License for more details.
455
456 You should have received a copy of the GNU General Public License
457 along with this program; if not, write to the Free Software
458 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
459
460#ifndef _GETOPT_H
461#define _GETOPT_H 1
462
463#ifdef __cplusplus
464extern "C" {
465#endif
466
467/* For communication from `getopt' to the caller.
468 When `getopt' finds an option that takes an argument,
469 the argument value is returned here.
470 Also, when `ordering' is RETURN_IN_ORDER,
471 each non-option ARGV-element is returned here. */
472
473extern char *optarg;
474
475/* Index in ARGV of the next element to be scanned.
476 This is used for communication to and from the caller
477 and for communication between successive calls to `getopt'.
478
479 On entry to `getopt', zero means this is the first call; initialize.
480
481 When `getopt' returns EOF, this is the index of the first of the
482 non-option elements that the caller should itself scan.
483
484 Otherwise, `optind' communicates from one call to the next
485 how much of ARGV has been scanned so far. */
486
487extern int optind;
488
489/* Callers store zero here to inhibit the error message `getopt' prints
490 for unrecognized options. */
491
492extern int opterr;
493
494/* Set to an option character which was unrecognized. */
495
496extern int optopt;
497
498/* Describe the long-named options requested by the application.
499 The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
500 of `struct option' terminated by an element containing a name which is
501 zero.
502
503 The field `has_arg' is:
504 no_argument (or 0) if the option does not take an argument,
505 required_argument (or 1) if the option requires an argument,
506 optional_argument (or 2) if the option takes an optional argument.
507
508 If the field `flag' is not NULL, it points to a variable that is set
509 to the value given in the field `val' when the option is found, but
510 left unchanged if the option is not found.
511
512 To have a long-named option do something other than set an `int' to
513 a compiled-in constant, such as set a value from `optarg', set the
514 option's `flag' field to zero and its `val' field to a nonzero
515 value (the equivalent single-letter option character, if there is
516 one). For long options that have a zero `flag' field, `getopt'
517 returns the contents of the `val' field. */
518
519struct option
520{
521#if __STDC__
522 const char *name;
523#else
524 char *name;
525#endif
526 /* has_arg can't be an enum because some compilers complain about
527 type mismatches in all the code that assumes it is an int. */
528 int has_arg;
529 int *flag;
530 int val;
531};
532
533/* Names for the values of the `has_arg' field of `struct option'. */
534
535#define no_argument 0
536#define required_argument 1
537#define optional_argument 2
538
539#if __STDC__ || defined(PROTO)
540#if defined(__GNU_LIBRARY__)
541/* Many other libraries have conflicting prototypes for getopt, with
542 differences in the consts, in stdlib.h. To avoid compilation
543 errors, only prototype getopt for the GNU C library. */
544extern int getopt (int argc, char *const *argv, const char *shortopts);
545#endif /* not __GNU_LIBRARY__ */
546extern int getopt_long (int argc, char *const *argv, const char *shortopts,
547 const struct option *longopts, int *longind);
548extern int getopt_long_only (int argc, char *const *argv,
549 const char *shortopts,
550 const struct option *longopts, int *longind);
551
552/* Internal only. Users should not call this directly. */
553extern int _getopt_internal (int argc, char *const *argv,
554 const char *shortopts,
555 const struct option *longopts, int *longind,
556 int long_only);
557#else /* not __STDC__ */
558extern int getopt ();
559extern int getopt_long ();
560extern int getopt_long_only ();
561
562extern int _getopt_internal ();
563#endif /* not __STDC__ */
564
565#ifdef __cplusplus
566}
567#endif
568
569#endif /* _GETOPT_H */
570
571
572#include <time.h>
573#include <fcntl.h>
574#include <unistd.h>
575
576#include <stdlib.h>
577
578#if defined(DIRENT)
579# include <dirent.h>
580 typedef struct dirent dir_type;
581# define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
582# define DIR_OPT "DIRENT"
583#else
584# define NLENGTH(dirent) ((dirent)->d_namlen)
585# ifdef SYSDIR
586# include <sys/dir.h>
587 typedef struct direct dir_type;
588# define DIR_OPT "SYSDIR"
589# else
590# ifdef SYSNDIR
591# include <sys/ndir.h>
592 typedef struct direct dir_type;
593# define DIR_OPT "SYSNDIR"
594# else
595# ifdef NDIR
596# include <ndir.h>
597 typedef struct direct dir_type;
598# define DIR_OPT "NDIR"
599# else
600# define NO_DIR
601# define DIR_OPT "NO_DIR"
602# endif
603# endif
604# endif
605#endif
606
607#if !defined(S_ISDIR) && defined(S_IFDIR)
608# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
609#endif
610#if !defined(S_ISREG) && defined(S_IFREG)
611# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
612#endif
613
614typedef RETSIGTYPE (*sig_type) OF((int));
615
616#ifndef O_BINARY
617# define O_BINARY 0 /* creation mode for open() */
618#endif
619
620#ifndef O_CREAT
621 /* Pure BSD system? */
622# include <sys/file.h>
623# ifndef O_CREAT
624# define O_CREAT FCREAT
625# endif
626# ifndef O_EXCL
627# define O_EXCL FEXCL
628# endif
629#endif
630
631#ifndef S_IRUSR
632# define S_IRUSR 0400
633#endif
634#ifndef S_IWUSR
635# define S_IWUSR 0200
636#endif
637#define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
638
639#ifndef MAX_PATH_LEN
640# define MAX_PATH_LEN 1024 /* max pathname length */
641#endif
642
643#ifndef SEEK_END
644# define SEEK_END 2
645#endif
646
647#ifdef NO_OFF_T
648 typedef long off_t;
649 off_t lseek OF((int fd, off_t offset, int whence));
650#endif
651
652
653 /* global buffers */
654
655DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
656DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
657DECLARE(ush, d_buf, DIST_BUFSIZE);
658DECLARE(uch, window, 2L*WSIZE);
659#ifndef MAXSEG_64K
660 DECLARE(ush, tab_prefix, 1L<<BITS);
661#else
662 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
663 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
664#endif
665
666 /* local variables */
667
668int force = 0; /* don't ask questions, compress links (-f) */
669int foreground; /* set if program run in foreground */
670int maxbits = BITS; /* max bits per code for LZW */
671int method = DEFLATED;/* compression method */
672int exit_code = OK; /* program exit code */
673int last_member; /* set for .zip and .Z files */
674int part_nb; /* number of parts in .gz file */
675long ifile_size; /* input file size, -1 for devices (debug only) */
676
677long bytes_in; /* number of input bytes */
678long bytes_out; /* number of output bytes */
679long total_in = 0; /* input bytes for all files */
680long total_out = 0; /* output bytes for all files */
681struct stat istat; /* status for input file */
682int ifd; /* input file descriptor */
683int ofd; /* output file descriptor */
684unsigned insize; /* valid bytes in inbuf */
685unsigned inptr; /* index of next byte to be processed in inbuf */
686unsigned outcnt; /* bytes in output buffer */
687
688long header_bytes; /* number of bytes in gzip header */
689
690/* local functions */
691
692local void treat_stdin OF((void));
693local int get_method OF((int in));
694local void do_exit OF((int exitcode));
695 int main OF((int argc, char **argv));
696int (*work) OF((int infile, int outfile)) = unzip; /* function to call */
697
698#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
699
700/* ======================================================================== */
701int zcat_main (struct FileInfo * i, int argc, char * * argv)
702{
703 int file_count; /* number of files to precess */
704
705 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
706 if (foreground) {
707 (void) signal (SIGINT, (sig_type)abort_gzip);
708 }
709#ifdef SIGTERM
710 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
711 (void) signal(SIGTERM, (sig_type)abort_gzip);
712 }
713#endif
714#ifdef SIGHUP
715 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
716 (void) signal(SIGHUP, (sig_type)abort_gzip);
717 }
718#endif
719
720 file_count = argc - optind;
721
722 /* Allocate all global buffers (for DYN_ALLOC option) */
723 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
724 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
725 ALLOC(ush, d_buf, DIST_BUFSIZE);
726 ALLOC(uch, window, 2L*WSIZE);
727#ifndef MAXSEG_64K
728 ALLOC(ush, tab_prefix, 1L<<BITS);
729#else
730 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
731 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
732#endif
733
734 /* And get to work */
735 treat_stdin();
736
737 do_exit(exit_code);
738 return exit_code; /* just to avoid lint warning */
739}
740
741/* ========================================================================
742 * Compress or decompress stdin
743 */
744local void treat_stdin()
745{
746 ifile_size = -1L; /* convention for unknown size */
747
748 clear_bufs(); /* clear input and output buffers */
749 part_nb = 0;
750
751 method = get_method(ifd);
752
753 if (method < 0) {
754 do_exit(exit_code); /* error message already emitted */
755 }
756
757 (*work)(fileno(stdin), fileno(stdout));
758
759}
760
761
762/* ========================================================================
763 * Check the magic number of the input file and update ofname if an
764 * original name was given and to_stdout is not set.
765 * Return the compression method, -1 for error, -2 for warning.
766 * Set inptr to the offset of the next byte to be processed.
767 * Updates time_stamp if there is one and --no-time is not used.
768 * This function may be called repeatedly for an input file consisting
769 * of several contiguous gzip'ed members.
770 * IN assertions: there is at least one remaining compressed member.
771 * If the member is a zip file, it must be the only one.
772 */
773local int get_method(in)
774 int in; /* input file descriptor */
775{
776 uch flags; /* compression flags */
777 char magic[2]; /* magic header */
778
779 /* If --force and --stdout, zcat == cat, so do not complain about
780 * premature end of file: use try_byte instead of get_byte.
781 */
782 if (force) {
783 magic[0] = (char)try_byte();
784 magic[1] = (char)try_byte();
785 /* If try_byte returned EOF, magic[1] == 0xff */
786 } else {
787 magic[0] = (char)get_byte();
788 magic[1] = (char)get_byte();
789 }
790 method = -1; /* unknown yet */
791 part_nb++; /* number of parts in gzip file */
792 header_bytes = 0;
793 last_member = RECORD_IO;
794 /* assume multiple members in gzip file except for record oriented I/O */
795
796 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
797
798 method = (int)get_byte();
799 if (method != DEFLATED) {
800 fprintf(stderr,
801 "unknown method %d -- get newer version of gzip\n",
802 method);
803 exit_code = ERROR;
804 return -1;
805 }
806 work = unzip;
807 flags = (uch)get_byte();
808
809 (ulg)get_byte(); /* Ignore time stamp */
810 (ulg)get_byte();
811 (ulg)get_byte();
812 (ulg)get_byte();
813
814 (void)get_byte(); /* Ignore extra flags for the moment */
815 (void)get_byte(); /* Ignore OS type for the moment */
816
817 if ((flags & EXTRA_FIELD) != 0) {
818 unsigned len = (unsigned)get_byte();
819 len |= ((unsigned)get_byte())<<8;
820
821 while (len--) (void)get_byte();
822 }
823
824 /* Discard original name if any */
825 if ((flags & ORIG_NAME) != 0) {
826 while (get_char() != 0) /* null */ ;
827 }
828
829 /* Discard file comment if any */
830 if ((flags & COMMENT) != 0) {
831 while (get_char() != 0) /* null */ ;
832 }
833 if (part_nb == 1) {
834 header_bytes = inptr + 2*sizeof(long); /* include crc and size */
835 }
836
837 }
838
839 if (method >= 0) return method;
840
841 if (part_nb == 1) {
842 fprintf(stderr, "\nnot in gzip format\n");
843 exit_code = ERROR;
844 return -1;
845 } else {
846 WARN((stderr, "\ndecompression OK, trailing garbage ignored\n"));
847 return -2;
848 }
849}
850
851
852/* ========================================================================
853 * Free all dynamically allocated variables and exit with the given code.
854 */
855local void do_exit(exitcode)
856 int exitcode;
857{
858 static int in_exit = 0;
859
860 if (in_exit) exit(exitcode);
861 in_exit = 1;
862 FREE(inbuf);
863 FREE(outbuf);
864 FREE(d_buf);
865 FREE(window);
866#ifndef MAXSEG_64K
867 FREE(tab_prefix);
868#else
869 FREE(tab_prefix0);
870 FREE(tab_prefix1);
871#endif
872 exit(exitcode);
873}
874
875/* ========================================================================
876 * Signal and error handler.
877 */
878RETSIGTYPE abort_gzip()
879{
880 do_exit(ERROR);
881}
882/* unzip.c -- decompress files in gzip or pkzip format.
883 * Copyright (C) 1992-1993 Jean-loup Gailly
884 * This is free software; you can redistribute it and/or modify it under the
885 * terms of the GNU General Public License, see the file COPYING.
886 *
887 * The code in this file is derived from the file funzip.c written
888 * and put in the public domain by Mark Adler.
889 */
890
891/*
892 This version can extract files in gzip or pkzip format.
893 For the latter, only the first entry is extracted, and it has to be
894 either deflated or stored.
895 */
896
897#ifdef RCSID
898static char rcsid[] = "$Id: zcat.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
899#endif
900
901/* #include "crypt.h" */
902
903/* crypt.h (dummy version) -- do not perform encryption
904 * Hardly worth copyrighting :-)
905 */
906
907#ifdef CRYPT
908# undef CRYPT /* dummy version */
909#endif
910
911#define RAND_HEAD_LEN 12 /* length of encryption random header */
912
913#define zencode
914#define zdecode
915
916/* PKZIP header definitions */
917#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
918#define LOCFLG 6 /* offset of bit flag */
919#define CRPFLG 1 /* bit for encrypted entry */
920#define EXTFLG 8 /* bit for extended local header */
921#define LOCHOW 8 /* offset of compression method */
922#define LOCTIM 10 /* file mod time (for decryption) */
923#define LOCCRC 14 /* offset of crc */
924#define LOCSIZ 18 /* offset of compressed size */
925#define LOCLEN 22 /* offset of uncompressed length */
926#define LOCFIL 26 /* offset of file name field length */
927#define LOCEXT 28 /* offset of extra field length */
928#define LOCHDR 30 /* size of local header, including sig */
929#define EXTHDR 16 /* size of extended local header, inc sig */
930
931
932/* Globals */
933
934char *key; /* not used--needed to link crypt.c */
935int pkzip = 0; /* set for a pkzip file */
936int ext_header = 0; /* set if extended local header */
937
938/* ===========================================================================
939 * Unzip in to out. This routine works on both gzip and pkzip files.
940 *
941 * IN assertions: the buffer inbuf contains already the beginning of
942 * the compressed data, from offsets inptr to insize-1 included.
943 * The magic header has already been checked. The output buffer is cleared.
944 */
945int unzip(in, out)
946 int in, out; /* input and output file descriptors */
947{
948 ulg orig_crc = 0; /* original crc */
949 ulg orig_len = 0; /* original uncompressed length */
950 int n;
951 uch buf[EXTHDR]; /* extended local header */
952
953 ifd = in;
954 ofd = out;
955
956 updcrc(NULL, 0); /* initialize crc */
957
958 if (pkzip && !ext_header) { /* crc and length at the end otherwise */
959 orig_crc = LG(inbuf + LOCCRC);
960 orig_len = LG(inbuf + LOCLEN);
961 }
962
963 /* Decompress */
964 if (method == DEFLATED) {
965
966 int res = inflate();
967
968 if (res == 3) {
969 error("out of memory");
970 } else if (res != 0) {
971 error("invalid compressed data--format violated");
972 }
973
974 } else {
975 error("internal error, invalid method");
976 }
977
978 /* Get the crc and original length */
979 if (!pkzip) {
980 /* crc32 (see algorithm.doc)
981 * uncompressed input size modulo 2^32
982 */
983 for (n = 0; n < 8; n++) {
984 buf[n] = (uch)get_byte(); /* may cause an error if EOF */
985 }
986 orig_crc = LG(buf);
987 orig_len = LG(buf+4);
988
989 } else if (ext_header) { /* If extended header, check it */
990 /* signature - 4bytes: 0x50 0x4b 0x07 0x08
991 * CRC-32 value
992 * compressed size 4-bytes
993 * uncompressed size 4-bytes
994 */
995 for (n = 0; n < EXTHDR; n++) {
996 buf[n] = (uch)get_byte(); /* may cause an error if EOF */
997 }
998 orig_crc = LG(buf+4);
999 orig_len = LG(buf+12);
1000 }
1001
1002 /* Validate decompression */
1003 if (orig_crc != updcrc(outbuf, 0)) {
1004 error("invalid compressed data--crc error");
1005 }
1006 if (orig_len != (ulg)bytes_out) {
1007 error("invalid compressed data--length error");
1008 }
1009
1010 /* Check if there are more entries in a pkzip file */
1011 if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
1012 WARN((stderr,"has more than one entry--rest ignored\n"));
1013 }
1014 ext_header = pkzip = 0; /* for next file */
1015 return OK;
1016}
1017/* util.c -- utility functions for gzip support
1018 * Copyright (C) 1992-1993 Jean-loup Gailly
1019 * This is free software; you can redistribute it and/or modify it under the
1020 * terms of the GNU General Public License, see the file COPYING.
1021 */
1022
1023#ifdef RCSID
1024static char rcsid[] = "$Id: zcat.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
1025#endif
1026
1027#include <ctype.h>
1028#include <errno.h>
1029#include <sys/types.h>
1030
1031#ifdef HAVE_UNISTD_H
1032# include <unistd.h>
1033#endif
1034#ifndef NO_FCNTL_H
1035# include <fcntl.h>
1036#endif
1037
1038#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
1039# include <stdlib.h>
1040#else
1041 extern int errno;
1042#endif
1043
1044extern ulg crc_32_tab[]; /* crc table, defined below */
1045
1046/* ===========================================================================
1047 * Run a set of bytes through the crc shift register. If s is a NULL
1048 * pointer, then initialize the crc shift register contents instead.
1049 * Return the current crc in either case.
1050 */
1051ulg updcrc(s, n)
1052 uch *s; /* pointer to bytes to pump through */
1053 unsigned n; /* number of bytes in s[] */
1054{
1055 register ulg c; /* temporary variable */
1056
1057 static ulg crc = (ulg)0xffffffffL; /* shift register contents */
1058
1059 if (s == NULL) {
1060 c = 0xffffffffL;
1061 } else {
1062 c = crc;
1063 if (n) do {
1064 c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
1065 } while (--n);
1066 }
1067 crc = c;
1068 return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
1069}
1070
1071/* ===========================================================================
1072 * Clear input and output buffers
1073 */
1074void clear_bufs()
1075{
1076 outcnt = 0;
1077 insize = inptr = 0;
1078 bytes_in = bytes_out = 0L;
1079}
1080
1081/* ===========================================================================
1082 * Fill the input buffer. This is called only when the buffer is empty.
1083 */
1084int fill_inbuf(eof_ok)
1085 int eof_ok; /* set if EOF acceptable as a result */
1086{
1087 int len;
1088
1089 /* Read as much as possible */
1090 insize = 0;
1091 errno = 0;
1092 do {
1093 len = read(ifd, (char*)inbuf+insize, INBUFSIZ-insize);
1094 if (len == 0 || len == EOF) break;
1095 insize += len;
1096 } while (insize < INBUFSIZ);
1097
1098 if (insize == 0) {
1099 if (eof_ok) return EOF;
1100 read_error();
1101 }
1102 bytes_in += (ulg)insize;
1103 inptr = 1;
1104 return inbuf[0];
1105}
1106
1107/* ===========================================================================
1108 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
1109 * (used for the compressed data only)
1110 */
1111void flush_outbuf()
1112{
1113 if (outcnt == 0) return;
1114
1115 write_buf(ofd, (char *)outbuf, outcnt);
1116 bytes_out += (ulg)outcnt;
1117 outcnt = 0;
1118}
1119
1120/* ===========================================================================
1121 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
1122 * (Used for the decompressed data only.)
1123 */
1124void flush_window()
1125{
1126 if (outcnt == 0) return;
1127 updcrc(window, outcnt);
1128
1129 write_buf(ofd, (char *)window, outcnt);
1130
1131 bytes_out += (ulg)outcnt;
1132 outcnt = 0;
1133}
1134
1135/* ===========================================================================
1136 * Does the same as write(), but also handles partial pipe writes and checks
1137 * for error return.
1138 */
1139void write_buf(fd, buf, cnt)
1140 int fd;
1141 voidp buf;
1142 unsigned cnt;
1143{
1144 unsigned n;
1145
1146 while ((n = write(fd, buf, cnt)) != cnt) {
1147 if (n == (unsigned)(-1)) {
1148 write_error();
1149 }
1150 cnt -= n;
1151 buf = (voidp)((char*)buf+n);
1152 }
1153}
1154
1155#if defined(NO_STRING_H) && !defined(STDC_HEADERS)
1156
1157/* Provide missing strspn and strcspn functions. */
1158
1159# ifndef __STDC__
1160# define const
1161# endif
1162
1163int strspn OF((const char *s, const char *accept));
1164int strcspn OF((const char *s, const char *reject));
1165
1166/* ========================================================================
1167 * Return the length of the maximum initial segment
1168 * of s which contains only characters in accept.
1169 */
1170int strspn(s, accept)
1171 const char *s;
1172 const char *accept;
1173{
1174 register const char *p;
1175 register const char *a;
1176 register int count = 0;
1177
1178 for (p = s; *p != '\0'; ++p) {
1179 for (a = accept; *a != '\0'; ++a) {
1180 if (*p == *a) break;
1181 }
1182 if (*a == '\0') return count;
1183 ++count;
1184 }
1185 return count;
1186}
1187
1188/* ========================================================================
1189 * Return the length of the maximum inital segment of s
1190 * which contains no characters from reject.
1191 */
1192int strcspn(s, reject)
1193 const char *s;
1194 const char *reject;
1195{
1196 register int count = 0;
1197
1198 while (*s != '\0') {
1199 if (strchr(reject, *s++) != NULL) return count;
1200 ++count;
1201 }
1202 return count;
1203}
1204
1205#endif /* NO_STRING_H */
1206
1207
1208/* ========================================================================
1209 * Error handlers.
1210 */
1211void error(m)
1212 char *m;
1213{
1214 fprintf(stderr, "\n%s\n", m);
1215 abort_gzip();
1216}
1217
1218void warn(a, b)
1219 char *a, *b; /* message strings juxtaposed in output */
1220{
1221 WARN((stderr, "warning: %s%s\n", a, b));
1222}
1223
1224void read_error()
1225{
1226 fprintf(stderr, "\n");
1227 if (errno != 0) {
1228 perror("");
1229 } else {
1230 fprintf(stderr, "unexpected end of file\n");
1231 }
1232 abort_gzip();
1233}
1234
1235void write_error()
1236{
1237 fprintf(stderr, "\n");
1238 perror("");
1239 abort_gzip();
1240}
1241
1242
1243/* ========================================================================
1244 * Semi-safe malloc -- never returns NULL.
1245 */
1246voidp xmalloc (size)
1247 unsigned size;
1248{
1249 voidp cp = (voidp)malloc (size);
1250
1251 if (cp == NULL) error("out of memory");
1252 return cp;
1253}
1254
1255/* ========================================================================
1256 * Table of CRC-32's of all single-byte values (made by makecrc.c)
1257 */
1258ulg crc_32_tab[] = {
1259 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
1260 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
1261 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
1262 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
1263 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
1264 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
1265 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
1266 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
1267 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
1268 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
1269 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
1270 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
1271 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
1272 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
1273 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
1274 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
1275 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
1276 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
1277 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
1278 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
1279 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
1280 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
1281 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
1282 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
1283 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
1284 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
1285 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
1286 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
1287 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
1288 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
1289 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
1290 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
1291 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
1292 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
1293 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
1294 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
1295 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
1296 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
1297 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
1298 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
1299 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
1300 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
1301 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
1302 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
1303 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
1304 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
1305 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
1306 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
1307 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
1308 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
1309 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
1310 0x2d02ef8dL
1311};
1312/* inflate.c -- Not copyrighted 1992 by Mark Adler
1313 version c10p1, 10 January 1993 */
1314
1315/* You can do whatever you like with this source file, though I would
1316 prefer that if you modify it and redistribute it that you include
1317 comments to that effect with your name and the date. Thank you.
1318 [The history has been moved to the file ChangeLog.]
1319 */
1320
1321/*
1322 Inflate deflated (PKZIP's method 8 compressed) data. The compression
1323 method searches for as much of the current string of bytes (up to a
1324 length of 258) in the previous 32K bytes. If it doesn't find any
1325 matches (of at least length 3), it codes the next byte. Otherwise, it
1326 codes the length of the matched string and its distance backwards from
1327 the current position. There is a single Huffman code that codes both
1328 single bytes (called "literals") and match lengths. A second Huffman
1329 code codes the distance information, which follows a length code. Each
1330 length or distance code actually represents a base value and a number
1331 of "extra" (sometimes zero) bits to get to add to the base value. At
1332 the end of each deflated block is a special end-of-block (EOB) literal/
1333 length code. The decoding process is basically: get a literal/length
1334 code; if EOB then done; if a literal, emit the decoded byte; if a
1335 length then get the distance and emit the referred-to bytes from the
1336 sliding window of previously emitted data.
1337
1338 There are (currently) three kinds of inflate blocks: stored, fixed, and
1339 dynamic. The compressor deals with some chunk of data at a time, and
1340 decides which method to use on a chunk-by-chunk basis. A chunk might
1341 typically be 32K or 64K. If the chunk is uncompressible, then the
1342 "stored" method is used. In this case, the bytes are simply stored as
1343 is, eight bits per byte, with none of the above coding. The bytes are
1344 preceded by a count, since there is no longer an EOB code.
1345
1346 If the data is compressible, then either the fixed or dynamic methods
1347 are used. In the dynamic method, the compressed data is preceded by
1348 an encoding of the literal/length and distance Huffman codes that are
1349 to be used to decode this block. The representation is itself Huffman
1350 coded, and so is preceded by a description of that code. These code
1351 descriptions take up a little space, and so for small blocks, there is
1352 a predefined set of codes, called the fixed codes. The fixed method is
1353 used if the block codes up smaller that way (usually for quite small
1354 chunks), otherwise the dynamic method is used. In the latter case, the
1355 codes are customized to the probabilities in the current block, and so
1356 can code it much better than the pre-determined fixed codes.
1357
1358 The Huffman codes themselves are decoded using a mutli-level table
1359 lookup, in order to maximize the speed of decoding plus the speed of
1360 building the decoding tables. See the comments below that precede the
1361 lbits and dbits tuning parameters.
1362 */
1363
1364
1365/*
1366 Notes beyond the 1.93a appnote.txt:
1367
1368 1. Distance pointers never point before the beginning of the output
1369 stream.
1370 2. Distance pointers can point back across blocks, up to 32k away.
1371 3. There is an implied maximum of 7 bits for the bit length table and
1372 15 bits for the actual data.
1373 4. If only one code exists, then it is encoded using one bit. (Zero
1374 would be more efficient, but perhaps a little confusing.) If two
1375 codes exist, they are coded using one bit each (0 and 1).
1376 5. There is no way of sending zero distance codes--a dummy must be
1377 sent if there are none. (History: a pre 2.0 version of PKZIP would
1378 store blocks with no distance codes, but this was discovered to be
1379 too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
1380 zero distance codes, which is sent as one code of zero bits in
1381 length.
1382 6. There are up to 286 literal/length codes. Code 256 represents the
1383 end-of-block. Note however that the static length tree defines
1384 288 codes just to fill out the Huffman codes. Codes 286 and 287
1385 cannot be used though, since there is no length base or extra bits
1386 defined for them. Similarly, there are up to 30 distance codes.
1387 However, static trees define 32 codes (all 5 bits) to fill out the
1388 Huffman codes, but the last two had better not show up in the data.
1389 7. Unzip can check dynamic Huffman blocks for complete code sets.
1390 The exception is that a single code would not be complete (see #4).
1391 8. The five bits following the block type is really the number of
1392 literal codes sent minus 257.
1393 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
1394 (1+6+6). Therefore, to output three times the length, you output
1395 three codes (1+1+1), whereas to output four times the same length,
1396 you only need two codes (1+3). Hmm.
1397 10. In the tree reconstruction algorithm, Code = Code + Increment
1398 only if BitLength(i) is not zero. (Pretty obvious.)
1399 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
1400 12. Note: length code 284 can represent 227-258, but length code 285
1401 really is 258. The last length deserves its own, short code
1402 since it gets used a lot in very redundant files. The length
1403 258 is special since 258 - 3 (the min match length) is 255.
1404 13. The literal/length and distance code bit lengths are read as a
1405 single stream of lengths. It is possible (and advantageous) for
1406 a repeat code (16, 17, or 18) to go across the boundary between
1407 the two sets of lengths.
1408 */
1409
1410#ifdef RCSID
1411static char rcsid[] = "$Id: zcat.c,v 1.1 1999/10/05 16:24:56 andersen Exp $";
1412#endif
1413
1414#include <sys/types.h>
1415
1416#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
1417# include <stdlib.h>
1418#endif
1419
1420
1421#define slide window
1422
1423/* Huffman code lookup table entry--this entry is four bytes for machines
1424 that have 16-bit pointers (e.g. PC's in the small or medium model).
1425 Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
1426 means that v is a literal, 16 < e < 32 means that v is a pointer to
1427 the next table, which codes e - 16 bits, and lastly e == 99 indicates
1428 an unused code. If a code with e == 99 is looked up, this implies an
1429 error in the data. */
1430struct huft {
1431 uch e; /* number of extra bits or operation */
1432 uch b; /* number of bits in this code or subcode */
1433 union {
1434 ush n; /* literal, length base, or distance base */
1435 struct huft *t; /* pointer to next level of table */
1436 } v;
1437};
1438
1439
1440/* Function prototypes */
1441int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
1442 struct huft **, int *));
1443int huft_free OF((struct huft *));
1444int inflate_codes OF((struct huft *, struct huft *, int, int));
1445int inflate_stored OF((void));
1446int inflate_fixed OF((void));
1447int inflate_dynamic OF((void));
1448int inflate_block OF((int *));
1449int inflate OF((void));
1450
1451
1452/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
1453 stream to find repeated byte strings. This is implemented here as a
1454 circular buffer. The index is updated simply by incrementing and then
1455 and'ing with 0x7fff (32K-1). */
1456/* It is left to other modules to supply the 32K area. It is assumed
1457 to be usable as if it were declared "uch slide[32768];" or as just
1458 "uch *slide;" and then malloc'ed in the latter case. The definition
1459 must be in unzip.h, included above. */
1460/* unsigned wp; current position in slide */
1461#define wp outcnt
1462#define flush_output(w) (wp=(w),flush_window())
1463
1464/* Tables for deflate from PKZIP's appnote.txt. */
1465static unsigned border[] = { /* Order of the bit length code lengths */
1466 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
1467static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
1468 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
1469 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
1470 /* note: see note #13 above about the 258 in this list. */
1471static ush cplext[] = { /* Extra bits for literal codes 257..285 */
1472 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
1473 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
1474static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
1475 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
1476 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
1477 8193, 12289, 16385, 24577};
1478static ush cpdext[] = { /* Extra bits for distance codes */
1479 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
1480 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
1481 12, 12, 13, 13};
1482
1483
1484
1485/* Macros for inflate() bit peeking and grabbing.
1486 The usage is:
1487
1488 NEEDBITS(j)
1489 x = b & mask_bits[j];
1490 DUMPBITS(j)
1491
1492 where NEEDBITS makes sure that b has at least j bits in it, and
1493 DUMPBITS removes the bits from b. The macros use the variable k
1494 for the number of bits in b. Normally, b and k are register
1495 variables for speed, and are initialized at the beginning of a
1496 routine that uses these macros from a global bit buffer and count.
1497
1498 If we assume that EOB will be the longest code, then we will never
1499 ask for bits with NEEDBITS that are beyond the end of the stream.
1500 So, NEEDBITS should not read any more bytes than are needed to
1501 meet the request. Then no bytes need to be "returned" to the buffer
1502 at the end of the last block.
1503
1504 However, this assumption is not true for fixed blocks--the EOB code
1505 is 7 bits, but the other literal/length codes can be 8 or 9 bits.
1506 (The EOB code is shorter than other codes because fixed blocks are
1507 generally short. So, while a block always has an EOB, many other
1508 literal/length codes have a significantly lower probability of
1509 showing up at all.) However, by making the first table have a
1510 lookup of seven bits, the EOB code will be found in that first
1511 lookup, and so will not require that too many bits be pulled from
1512 the stream.
1513 */
1514
1515ulg bb; /* bit buffer */
1516unsigned bk; /* bits in bit buffer */
1517
1518ush mask_bits[] = {
1519 0x0000,
1520 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
1521 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
1522};
1523
1524#ifdef CRYPT
1525 uch cc;
1526# define NEXTBYTE() (cc = get_byte(), zdecode(cc), cc)
1527#else
1528# define NEXTBYTE() (uch)get_byte()
1529#endif
1530#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
1531#define DUMPBITS(n) {b>>=(n);k-=(n);}
1532
1533
1534/*
1535 Huffman code decoding is performed using a multi-level table lookup.
1536 The fastest way to decode is to simply build a lookup table whose
1537 size is determined by the longest code. However, the time it takes
1538 to build this table can also be a factor if the data being decoded
1539 is not very long. The most common codes are necessarily the
1540 shortest codes, so those codes dominate the decoding time, and hence
1541 the speed. The idea is you can have a shorter table that decodes the
1542 shorter, more probable codes, and then point to subsidiary tables for
1543 the longer codes. The time it costs to decode the longer codes is
1544 then traded against the time it takes to make longer tables.
1545
1546 This results of this trade are in the variables lbits and dbits
1547 below. lbits is the number of bits the first level table for literal/
1548 length codes can decode in one step, and dbits is the same thing for
1549 the distance codes. Subsequent tables are also less than or equal to
1550 those sizes. These values may be adjusted either when all of the
1551 codes are shorter than that, in which case the longest code length in
1552 bits is used, or when the shortest code is *longer* than the requested
1553 table size, in which case the length of the shortest code in bits is
1554 used.
1555
1556 There are two different values for the two tables, since they code a
1557 different number of possibilities each. The literal/length table
1558 codes 286 possible values, or in a flat code, a little over eight
1559 bits. The distance table codes 30 possible values, or a little less
1560 than five bits, flat. The optimum values for speed end up being
1561 about one bit more than those, so lbits is 8+1 and dbits is 5+1.
1562 The optimum values may differ though from machine to machine, and
1563 possibly even between compilers. Your mileage may vary.
1564 */
1565
1566
1567int lbits = 9; /* bits in base literal/length lookup table */
1568int dbits = 6; /* bits in base distance lookup table */
1569
1570
1571/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
1572#define BMAX 16 /* maximum bit length of any code (16 for explode) */
1573#define N_MAX 288 /* maximum number of codes in any set */
1574
1575
1576unsigned hufts; /* track memory usage */
1577
1578
1579int huft_build(b, n, s, d, e, t, m)
1580unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
1581unsigned n; /* number of codes (assumed <= N_MAX) */
1582unsigned s; /* number of simple-valued codes (0..s-1) */
1583ush *d; /* list of base values for non-simple codes */
1584ush *e; /* list of extra bits for non-simple codes */
1585struct huft **t; /* result: starting table */
1586int *m; /* maximum lookup bits, returns actual */
1587/* Given a list of code lengths and a maximum table size, make a set of
1588 tables to decode that set of codes. Return zero on success, one if
1589 the given code set is incomplete (the tables are still built in this
1590 case), two if the input is invalid (all zero length codes or an
1591 oversubscribed set of lengths), and three if not enough memory. */
1592{
1593 unsigned a; /* counter for codes of length k */
1594 unsigned c[BMAX+1]; /* bit length count table */
1595 unsigned f; /* i repeats in table every f entries */
1596 int g; /* maximum code length */
1597 int h; /* table level */
1598 register unsigned i; /* counter, current code */
1599 register unsigned j; /* counter */
1600 register int k; /* number of bits in current code */
1601 int l; /* bits per table (returned in m) */
1602 register unsigned *p; /* pointer into c[], b[], or v[] */
1603 register struct huft *q; /* points to current table */
1604 struct huft r; /* table entry for structure assignment */
1605 struct huft *u[BMAX]; /* table stack */
1606 unsigned v[N_MAX]; /* values in order of bit length */
1607 register int w; /* bits before this table == (l * h) */
1608 unsigned x[BMAX+1]; /* bit offsets, then code stack */
1609 unsigned *xp; /* pointer into x */
1610 int y; /* number of dummy codes added */
1611 unsigned z; /* number of entries in current table */
1612
1613
1614 /* Generate counts for each bit length */
1615 memzero(c, sizeof(c));
1616 p = b; i = n;
1617 do {
1618 Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
1619 n-i, *p));
1620 c[*p]++; /* assume all entries <= BMAX */
1621 p++; /* Can't combine with above line (Solaris bug) */
1622 } while (--i);
1623 if (c[0] == n) /* null input--all zero length codes */
1624 {
1625 *t = (struct huft *)NULL;
1626 *m = 0;
1627 return 0;
1628 }
1629
1630
1631 /* Find minimum and maximum length, bound *m by those */
1632 l = *m;
1633 for (j = 1; j <= BMAX; j++)
1634 if (c[j])
1635 break;
1636 k = j; /* minimum code length */
1637 if ((unsigned)l < j)
1638 l = j;
1639 for (i = BMAX; i; i--)
1640 if (c[i])
1641 break;
1642 g = i; /* maximum code length */
1643 if ((unsigned)l > i)
1644 l = i;
1645 *m = l;
1646
1647
1648 /* Adjust last length count to fill out codes, if needed */
1649 for (y = 1 << j; j < i; j++, y <<= 1)
1650 if ((y -= c[j]) < 0)
1651 return 2; /* bad input: more codes than bits */
1652 if ((y -= c[i]) < 0)
1653 return 2;
1654 c[i] += y;
1655
1656
1657 /* Generate starting offsets into the value table for each length */
1658 x[1] = j = 0;
1659 p = c + 1; xp = x + 2;
1660 while (--i) { /* note that i == g from above */
1661 *xp++ = (j += *p++);
1662 }
1663
1664
1665 /* Make a table of values in order of bit lengths */
1666 p = b; i = 0;
1667 do {
1668 if ((j = *p++) != 0)
1669 v[x[j]++] = i;
1670 } while (++i < n);
1671
1672
1673 /* Generate the Huffman codes and for each, make the table entries */
1674 x[0] = i = 0; /* first Huffman code is zero */
1675 p = v; /* grab values in bit order */
1676 h = -1; /* no tables yet--level -1 */
1677 w = -l; /* bits decoded == (l * h) */
1678 u[0] = (struct huft *)NULL; /* just to keep compilers happy */
1679 q = (struct huft *)NULL; /* ditto */
1680 z = 0; /* ditto */
1681
1682 /* go through the bit lengths (k already is bits in shortest code) */
1683 for (; k <= g; k++)
1684 {
1685 a = c[k];
1686 while (a--)
1687 {
1688 /* here i is the Huffman code of length k bits for value *p */
1689 /* make tables up to required level */
1690 while (k > w + l)
1691 {
1692 h++;
1693 w += l; /* previous table always l bits */
1694
1695 /* compute minimum size table less than or equal to l bits */
1696 z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
1697 if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
1698 { /* too few codes for k-w bit table */
1699 f -= a + 1; /* deduct codes from patterns left */
1700 xp = c + k;
1701 while (++j < z) /* try smaller tables up to z bits */
1702 {
1703 if ((f <<= 1) <= *++xp)
1704 break; /* enough codes to use up j bits */
1705 f -= *xp; /* else deduct codes from patterns */
1706 }
1707 }
1708 z = 1 << j; /* table entries for j-bit table */
1709
1710 /* allocate and link in new table */
1711 if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
1712 (struct huft *)NULL)
1713 {
1714 if (h)
1715 huft_free(u[0]);
1716 return 3; /* not enough memory */
1717 }
1718 hufts += z + 1; /* track memory usage */
1719 *t = q + 1; /* link to list for huft_free() */
1720 *(t = &(q->v.t)) = (struct huft *)NULL;
1721 u[h] = ++q; /* table starts after link */
1722
1723 /* connect to last table, if there is one */
1724 if (h)
1725 {
1726 x[h] = i; /* save pattern for backing up */
1727 r.b = (uch)l; /* bits to dump before this table */
1728 r.e = (uch)(16 + j); /* bits in this table */
1729 r.v.t = q; /* pointer to this table */
1730 j = i >> (w - l); /* (get around Turbo C bug) */
1731 u[h-1][j] = r; /* connect to last table */
1732 }
1733 }
1734
1735 /* set up table entry in r */
1736 r.b = (uch)(k - w);
1737 if (p >= v + n)
1738 r.e = 99; /* out of values--invalid code */
1739 else if (*p < s)
1740 {
1741 r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
1742 r.v.n = (ush)(*p); /* simple code is just the value */
1743 p++; /* one compiler does not like *p++ */
1744 }
1745 else
1746 {
1747 r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
1748 r.v.n = d[*p++ - s];
1749 }
1750
1751 /* fill code-like entries with r */
1752 f = 1 << (k - w);
1753 for (j = i >> w; j < z; j += f)
1754 q[j] = r;
1755
1756 /* backwards increment the k-bit code i */
1757 for (j = 1 << (k - 1); i & j; j >>= 1)
1758 i ^= j;
1759 i ^= j;
1760
1761 /* backup over finished tables */
1762 while ((i & ((1 << w) - 1)) != x[h])
1763 {
1764 h--; /* don't need to update q */
1765 w -= l;
1766 }
1767 }
1768 }
1769
1770
1771 /* Return true (1) if we were given an incomplete table */
1772 return y != 0 && g != 1;
1773}
1774
1775
1776
1777int huft_free(t)
1778struct huft *t; /* table to free */
1779/* Free the malloc'ed tables built by huft_build(), which makes a linked
1780 list of the tables it made, with the links in a dummy first entry of
1781 each table. */
1782{
1783 register struct huft *p, *q;
1784
1785
1786 /* Go through linked list, freeing from the malloced (t[-1]) address. */
1787 p = t;
1788 while (p != (struct huft *)NULL)
1789 {
1790 q = (--p)->v.t;
1791 free((char*)p);
1792 p = q;
1793 }
1794 return 0;
1795}
1796
1797
1798int inflate_codes(tl, td, bl, bd)
1799struct huft *tl, *td; /* literal/length and distance decoder tables */
1800int bl, bd; /* number of bits decoded by tl[] and td[] */
1801/* inflate (decompress) the codes in a deflated (compressed) block.
1802 Return an error code or zero if it all goes ok. */
1803{
1804 register unsigned e; /* table entry flag/number of extra bits */
1805 unsigned n, d; /* length and index for copy */
1806 unsigned w; /* current window position */
1807 struct huft *t; /* pointer to table entry */
1808 unsigned ml, md; /* masks for bl and bd bits */
1809 register ulg b; /* bit buffer */
1810 register unsigned k; /* number of bits in bit buffer */
1811
1812
1813 /* make local copies of globals */
1814 b = bb; /* initialize bit buffer */
1815 k = bk;
1816 w = wp; /* initialize window position */
1817
1818 /* inflate the coded data */
1819 ml = mask_bits[bl]; /* precompute masks for speed */
1820 md = mask_bits[bd];
1821 for (;;) /* do until end of block */
1822 {
1823 NEEDBITS((unsigned)bl)
1824 if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
1825 do {
1826 if (e == 99)
1827 return 1;
1828 DUMPBITS(t->b)
1829 e -= 16;
1830 NEEDBITS(e)
1831 } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
1832 DUMPBITS(t->b)
1833 if (e == 16) /* then it's a literal */
1834 {
1835 slide[w++] = (uch)t->v.n;
1836 Tracevv((stderr, "%c", slide[w-1]));
1837 if (w == WSIZE)
1838 {
1839 flush_output(w);
1840 w = 0;
1841 }
1842 }
1843 else /* it's an EOB or a length */
1844 {
1845 /* exit if end of block */
1846 if (e == 15)
1847 break;
1848
1849 /* get length of block to copy */
1850 NEEDBITS(e)
1851 n = t->v.n + ((unsigned)b & mask_bits[e]);
1852 DUMPBITS(e);
1853
1854 /* decode distance of block to copy */
1855 NEEDBITS((unsigned)bd)
1856 if ((e = (t = td + ((unsigned)b & md))->e) > 16)
1857 do {
1858 if (e == 99)
1859 return 1;
1860 DUMPBITS(t->b)
1861 e -= 16;
1862 NEEDBITS(e)
1863 } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
1864 DUMPBITS(t->b)
1865 NEEDBITS(e)
1866 d = w - t->v.n - ((unsigned)b & mask_bits[e]);
1867 DUMPBITS(e)
1868 Tracevv((stderr,"\\[%d,%d]", w-d, n));
1869
1870 /* do the copy */
1871 do {
1872 n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
1873#if !defined(NOMEMCPY) && !defined(DEBUG)
1874 if (w - d >= e) /* (this test assumes unsigned comparison) */
1875 {
1876 memcpy(slide + w, slide + d, e);
1877 w += e;
1878 d += e;
1879 }
1880 else /* do it slow to avoid memcpy() overlap */
1881#endif /* !NOMEMCPY */
1882 do {
1883 slide[w++] = slide[d++];
1884 Tracevv((stderr, "%c", slide[w-1]));
1885 } while (--e);
1886 if (w == WSIZE)
1887 {
1888 flush_output(w);
1889 w = 0;
1890 }
1891 } while (n);
1892 }
1893 }
1894
1895
1896 /* restore the globals from the locals */
1897 wp = w; /* restore global window pointer */
1898 bb = b; /* restore global bit buffer */
1899 bk = k;
1900
1901 /* done */
1902 return 0;
1903}
1904
1905
1906
1907int inflate_stored()
1908/* "decompress" an inflated type 0 (stored) block. */
1909{
1910 unsigned n; /* number of bytes in block */
1911 unsigned w; /* current window position */
1912 register ulg b; /* bit buffer */
1913 register unsigned k; /* number of bits in bit buffer */
1914
1915
1916 /* make local copies of globals */
1917 b = bb; /* initialize bit buffer */
1918 k = bk;
1919 w = wp; /* initialize window position */
1920
1921
1922 /* go to byte boundary */
1923 n = k & 7;
1924 DUMPBITS(n);
1925
1926
1927 /* get the length and its complement */
1928 NEEDBITS(16)
1929 n = ((unsigned)b & 0xffff);
1930 DUMPBITS(16)
1931 NEEDBITS(16)
1932 if (n != (unsigned)((~b) & 0xffff))
1933 return 1; /* error in compressed data */
1934 DUMPBITS(16)
1935
1936
1937 /* read and output the compressed data */
1938 while (n--)
1939 {
1940 NEEDBITS(8)
1941 slide[w++] = (uch)b;
1942 if (w == WSIZE)
1943 {
1944 flush_output(w);
1945 w = 0;
1946 }
1947 DUMPBITS(8)
1948 }
1949
1950
1951 /* restore the globals from the locals */
1952 wp = w; /* restore global window pointer */
1953 bb = b; /* restore global bit buffer */
1954 bk = k;
1955 return 0;
1956}
1957
1958
1959
1960int inflate_fixed()
1961/* decompress an inflated type 1 (fixed Huffman codes) block. We should
1962 either replace this with a custom decoder, or at least precompute the
1963 Huffman tables. */
1964{
1965 int i; /* temporary variable */
1966 struct huft *tl; /* literal/length code table */
1967 struct huft *td; /* distance code table */
1968 int bl; /* lookup bits for tl */
1969 int bd; /* lookup bits for td */
1970 unsigned l[288]; /* length list for huft_build */
1971
1972
1973 /* set up literal table */
1974 for (i = 0; i < 144; i++)
1975 l[i] = 8;
1976 for (; i < 256; i++)
1977 l[i] = 9;
1978 for (; i < 280; i++)
1979 l[i] = 7;
1980 for (; i < 288; i++) /* make a complete, but wrong code set */
1981 l[i] = 8;
1982 bl = 7;
1983 if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
1984 return i;
1985
1986
1987 /* set up distance table */
1988 for (i = 0; i < 30; i++) /* make an incomplete code set */
1989 l[i] = 5;
1990 bd = 5;
1991 if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
1992 {
1993 huft_free(tl);
1994 return i;
1995 }
1996
1997
1998 /* decompress until an end-of-block code */
1999 if (inflate_codes(tl, td, bl, bd))
2000 return 1;
2001
2002
2003 /* free the decoding tables, return */
2004 huft_free(tl);
2005 huft_free(td);
2006 return 0;
2007}
2008
2009
2010
2011int inflate_dynamic()
2012/* decompress an inflated type 2 (dynamic Huffman codes) block. */
2013{
2014 int i; /* temporary variables */
2015 unsigned j;
2016 unsigned l; /* last length */
2017 unsigned m; /* mask for bit lengths table */
2018 unsigned n; /* number of lengths to get */
2019 struct huft *tl; /* literal/length code table */
2020 struct huft *td; /* distance code table */
2021 int bl; /* lookup bits for tl */
2022 int bd; /* lookup bits for td */
2023 unsigned nb; /* number of bit length codes */
2024 unsigned nl; /* number of literal/length codes */
2025 unsigned nd; /* number of distance codes */
2026#ifdef PKZIP_BUG_WORKAROUND
2027 unsigned ll[288+32]; /* literal/length and distance code lengths */
2028#else
2029 unsigned ll[286+30]; /* literal/length and distance code lengths */
2030#endif
2031 register ulg b; /* bit buffer */
2032 register unsigned k; /* number of bits in bit buffer */
2033
2034
2035 /* make local bit buffer */
2036 b = bb;
2037 k = bk;
2038
2039
2040 /* read in table lengths */
2041 NEEDBITS(5)
2042 nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
2043 DUMPBITS(5)
2044 NEEDBITS(5)
2045 nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
2046 DUMPBITS(5)
2047 NEEDBITS(4)
2048 nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
2049 DUMPBITS(4)
2050#ifdef PKZIP_BUG_WORKAROUND
2051 if (nl > 288 || nd > 32)
2052#else
2053 if (nl > 286 || nd > 30)
2054#endif
2055 return 1; /* bad lengths */
2056
2057
2058 /* read in bit-length-code lengths */
2059 for (j = 0; j < nb; j++)
2060 {
2061 NEEDBITS(3)
2062 ll[border[j]] = (unsigned)b & 7;
2063 DUMPBITS(3)
2064 }
2065 for (; j < 19; j++)
2066 ll[border[j]] = 0;
2067
2068
2069 /* build decoding table for trees--single level, 7 bit lookup */
2070 bl = 7;
2071 if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
2072 {
2073 if (i == 1)
2074 huft_free(tl);
2075 return i; /* incomplete code set */
2076 }
2077
2078
2079 /* read in literal and distance code lengths */
2080 n = nl + nd;
2081 m = mask_bits[bl];
2082 i = l = 0;
2083 while ((unsigned)i < n)
2084 {
2085 NEEDBITS((unsigned)bl)
2086 j = (td = tl + ((unsigned)b & m))->b;
2087 DUMPBITS(j)
2088 j = td->v.n;
2089 if (j < 16) /* length of code in bits (0..15) */
2090 ll[i++] = l = j; /* save last length in l */
2091 else if (j == 16) /* repeat last length 3 to 6 times */
2092 {
2093 NEEDBITS(2)
2094 j = 3 + ((unsigned)b & 3);
2095 DUMPBITS(2)
2096 if ((unsigned)i + j > n)
2097 return 1;
2098 while (j--)
2099 ll[i++] = l;
2100 }
2101 else if (j == 17) /* 3 to 10 zero length codes */
2102 {
2103 NEEDBITS(3)
2104 j = 3 + ((unsigned)b & 7);
2105 DUMPBITS(3)
2106 if ((unsigned)i + j > n)
2107 return 1;
2108 while (j--)
2109 ll[i++] = 0;
2110 l = 0;
2111 }
2112 else /* j == 18: 11 to 138 zero length codes */
2113 {
2114 NEEDBITS(7)
2115 j = 11 + ((unsigned)b & 0x7f);
2116 DUMPBITS(7)
2117 if ((unsigned)i + j > n)
2118 return 1;
2119 while (j--)
2120 ll[i++] = 0;
2121 l = 0;
2122 }
2123 }
2124
2125
2126 /* free decoding table for trees */
2127 huft_free(tl);
2128
2129
2130 /* restore the global bit buffer */
2131 bb = b;
2132 bk = k;
2133
2134
2135 /* build the decoding tables for literal/length and distance codes */
2136 bl = lbits;
2137 if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
2138 {
2139 if (i == 1) {
2140 fprintf(stderr, " incomplete literal tree\n");
2141 huft_free(tl);
2142 }
2143 return i; /* incomplete code set */
2144 }
2145 bd = dbits;
2146 if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
2147 {
2148 if (i == 1) {
2149 fprintf(stderr, " incomplete distance tree\n");
2150#ifdef PKZIP_BUG_WORKAROUND
2151 i = 0;
2152 }
2153#else
2154 huft_free(td);
2155 }
2156 huft_free(tl);
2157 return i; /* incomplete code set */
2158#endif
2159 }
2160
2161
2162 /* decompress until an end-of-block code */
2163 if (inflate_codes(tl, td, bl, bd))
2164 return 1;
2165
2166
2167 /* free the decoding tables, return */
2168 huft_free(tl);
2169 huft_free(td);
2170 return 0;
2171}
2172
2173
2174
2175int inflate_block(e)
2176int *e; /* last block flag */
2177/* decompress an inflated block */
2178{
2179 unsigned t; /* block type */
2180 register ulg b; /* bit buffer */
2181 register unsigned k; /* number of bits in bit buffer */
2182
2183
2184 /* make local bit buffer */
2185 b = bb;
2186 k = bk;
2187
2188
2189 /* read in last block bit */
2190 NEEDBITS(1)
2191 *e = (int)b & 1;
2192 DUMPBITS(1)
2193
2194
2195 /* read in block type */
2196 NEEDBITS(2)
2197 t = (unsigned)b & 3;
2198 DUMPBITS(2)
2199
2200
2201 /* restore the global bit buffer */
2202 bb = b;
2203 bk = k;
2204
2205
2206 /* inflate that block type */
2207 if (t == 2)
2208 return inflate_dynamic();
2209 if (t == 0)
2210 return inflate_stored();
2211 if (t == 1)
2212 return inflate_fixed();
2213
2214
2215 /* bad block type */
2216 return 2;
2217}
2218
2219
2220
2221int inflate()
2222/* decompress an inflated entry */
2223{
2224 int e; /* last block flag */
2225 int r; /* result code */
2226 unsigned h; /* maximum struct huft's malloc'ed */
2227
2228
2229 /* initialize window, bit buffer */
2230 wp = 0;
2231 bk = 0;
2232 bb = 0;
2233
2234
2235 /* decompress until the last block */
2236 h = 0;
2237 do {
2238 hufts = 0;
2239 if ((r = inflate_block(&e)) != 0)
2240 return r;
2241 if (hufts > h)
2242 h = hufts;
2243 } while (!e);
2244
2245 /* Undo too much lookahead. The next read will be byte aligned so we
2246 * can discard unused bits in the last meaningful byte.
2247 */
2248 while (bk >= 8) {
2249 bk -= 8;
2250 inptr--;
2251 }
2252
2253 /* flush out slide */
2254 flush_output(wp);
2255
2256
2257 /* return success */
2258#ifdef DEBUG
2259 fprintf(stderr, "<%u> ", h);
2260#endif /* DEBUG */
2261 return 0;
2262}