Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/std/shar.sh
1808 views
1
########################################################################
2
# #
3
# This software is part of the ast package #
4
# Copyright (c) 1989-2011 AT&T Intellectual Property #
5
# and is licensed under the #
6
# Eclipse Public License, Version 1.0 #
7
# by AT&T Intellectual Property #
8
# #
9
# A copy of the License is available at #
10
# http://www.eclipse.org/org/documents/epl-v10.html #
11
# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
12
# #
13
# Information and Software Systems Research #
14
# AT&T Research #
15
# Florham Park NJ #
16
# #
17
# Glenn Fowler <[email protected]> #
18
# #
19
########################################################################
20
21
# Make a shell archive
22
23
function logmsg
24
{
25
print -ru2 $command: "$@"
26
}
27
28
function err_exit
29
{
30
logmsg "$@"
31
exit 1
32
}
33
34
trap 'rm -rf /tmp/shar$$*' EXIT
35
trap 'err_exit qutting early' HUP INT QUIT TERM
36
37
case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in
38
0123) usage=$'
39
[-?
40
@(#)$Id: shar (AT&T Labs Research) 1999-04-20 $
41
]
42
'$USAGE_LICENSE$'
43
[+NAME? shar - create a shell archive]
44
[+DESCRIPTION?\bshar\b reads one or more input files and creates a
45
shell script which when executed will restore the contents
46
of these files. This is called a shell archive or \ashar\a.
47
The resulting archive is sent to standard output unless the
48
\b-o\b option is specified.]
49
[a:net-headers?Automatic generation of headers. The \b-n\b option
50
must also be specified. If the archive name does not
51
contain a \b/\b, then \b/part\b will be append to the
52
given archive name when constructing the header.]
53
[b:bits-per-code]:[bits?When doing compression, use \b-b \b\abits\a
54
as a parameter to \bcompress\b(1). The \b-b\b option turns on
55
\b-Z\b.]
56
[c:cut-mark?Start the shar with a cut line.]
57
[d:here-delimiter]:[string?Use \astring\a to delimit the files
58
in the shar instead of \bSHAR_EOF\b.]
59
[f:basenames?Use the basenames for the files.]
60
[g:level-for-gzip]:[level?When doing compression, use \b-\b\alevel\a
61
as a parameter to \bgzip\b(1). The \b-g\b option turns on
62
\b-z\b.]
63
[l:whole-size-limit]#[size?Limit the output file size to \asize\a
64
bytes. A suffix of \bb\b, \bk\b, or \bm\b can be specified
65
to indicate 512-byte blocks, kilobytes, or megabytes
66
respectively.]
67
[n:archive-name:name]:[name?Override automatically determined name
68
for the archive with \aname\a.]
69
[o:output-prefix]:[prefix?Save the archive files \aprefix\a\b.01\b
70
through \aprefix\a\b.\b\ann\a instead of standard output. This
71
option must be used when \b-l\b or the \b-L\b is specified.]
72
[p:intermix-type?Allow positional parameter options. The options
73
\b-B\b, \b-T\b, \b-z\b and \b-Z\b may be embedded, and files
74
to the right of the option will be processed in the specified
75
mode.]
76
[q:quit|silent?Do not output verbose messages locally when producing
77
the archive.]
78
[s:submitter]:[user?Override automatically determined submitter name
79
with \auser\a which is of the form \awho\a\b@\b\awhere\a.]
80
[t:tty?Write errors and the name of each file to \b/dev/tty\b as it is
81
archived.]
82
[w:no-character-count?Do NOT check each file with \bwc -c\b after
83
unpack.]
84
[z:gzip?\bgzip\b(1) and \buuencode\b(1) all files prior to packing.]
85
[B:uuencode,binary-files-files?Treat all files as binary and
86
\buuencode\b(1) prior to packing.]
87
[D:no-md5-digest?Do NOT use \bcksum md5sum\b digest to verify
88
the unpacked files. The default is to check.]
89
[L:split-size-limit]#[size?Limit the output file size to \asize\a
90
bytes as with \b-l\b, but split the archive into multiple
91
files.]
92
[Q:quiet-unshar?Verbose OFF. Disables the inclusion of comments to
93
be output when the archive is unpacked.]
94
[M:mixed-uuencode?Mixed mode. Determine if the files are text or
95
binary and archive correctly. Files found to be binary
96
are uuencoded prior to packing. This is the default.]
97
[S:stdin-file-list?Read list of files to be packed from the standard
98
input rather than from the command line in the format
99
generated by \bfind\b(1) and \btw\b(1). If \b-p\b is specified,
100
the options \b-B\b, \b-T\b, \b-z\b and \b-Z\b must be
101
included in the standard input.]
102
[T:text-files?Treat all files as text.]
103
[X:query-user?When unpacking, ask the user if files should be
104
overwritten.]
105
[Z:compress?\bcompress\b(1) and \buuencode\b(1) all files prior to
106
packing.]
107
108
[files ...]
109
110
[+SEE ALSO?\bcksum\b(1), \bcompress\b(1), \bfind\b(1), \bgzip\b(1),
111
\bpax\b(1), \btw\b(1), \buuencode\b(1), \bwc\b(1)]
112
'
113
;;
114
*)
115
usage='ab:[bits]cd:[delim]fg:[level]l#[size]n:[name]o:[prefix]pqs:[who]tzBDL#[size]MQSXTZ files ...'
116
;;
117
esac
118
119
IFS=$'\n'
120
command=${0##*/}
121
user=${USER:-${LOGNAME:-$(whoami 2>/dev/null || who am i | sed $'s/[ \t].*//')}}@$(hostname)
122
integer size=0
123
flags= prefix= mode=M arg=
124
separator=SHAR_EOF
125
# some strings that should be internationalized some day
126
skipping=$"echo 'x -' SKIPPING"
127
exists=$"'(file already exists)'"
128
extract=$"echo 'x -' extracting"
129
mkdir=$"creating directory"
130
uncomp=$"uncompressing file"
131
132
while getopts "$usage" c
133
do
134
case $c in
135
[acfpqwDSQX])
136
flags=$flags$c;;
137
b) mode=Z;arg=-"b $OPTARG";;
138
g) mode=z;arg=-$OPTARG;;
139
l) size=OPTARG;;
140
L) split=1 size=OPTARG;;
141
d) separator=$OPTARG;;
142
n) aname=$OPTARG;;
143
o) prefix=$OPTARG
144
exec > /tmp/shar$$.1;;
145
s) user=$OPTARG;;
146
q) verbose=;;
147
t) verbose=1; exec 2> /dev/tty;;
148
v) verbose=1;;
149
[zZBMT])
150
mode=$c;;
151
esac
152
done
153
154
# Check remaining arguments, which should be just a list of files:
155
shift $((OPTIND-1))
156
if (( $# ==0 )) && [[ $flags != *S* ]]
157
then err_exit "no arguments left!"
158
fi
159
160
contents='' # no files so far.
161
contdirs='' # no directories so far.
162
163
function preprocess_files
164
{
165
typeset file=$1
166
if [[ $flags == *p* && $file == -[zBTZ] ]]
167
then mode=${file#-}
168
elif [[ -f $file ]]
169
then if [[ $flags == *f* ]]
170
then contents="$contents$IFS${file##*/}"
171
else contents="$contents$IFS$file"
172
fi
173
elif [[ -d $file ]]
174
then if [[ $flags == *f* ]]
175
then err_exit "cannot archive directory $file with -b option."
176
fi
177
contdirs="$contdirs$IFS$file/ "
178
179
else err_exit "cannot archive $file"
180
fi
181
}
182
183
if [[ $flags == *S* ]]
184
then while read -r file
185
do preprocess_files "$file"
186
print -r -- "$file"
187
done > /tmp/shar$$.3
188
else for file
189
do preprocess_files "$file"
190
done
191
fi
192
193
194
if [[ $flags == *a* ]]
195
then if [[ $aname ]]
196
then if [[ $aname != */* ]]
197
then aname=$aname/part
198
fi
199
cat <<- !!!
200
Submitted-by: $user
201
Archive-name: ${aname}01
202
203
!!!
204
else err_exit "Cannot use -a without -n"
205
fi
206
fi
207
208
# Generate the prologue
209
# (The leading newline is for those who type csh instead of sh.)
210
211
if [[ $flags == *c* ]]
212
then print -r -- '#---- Cut Here and feed the following to sh ----'
213
fi
214
cat <<!!!
215
216
# This is a shell archive (produced by a ksh93 script).
217
# Remove anything before this line, then unpack it by saving
218
# it in a file and typing "sh file".
219
#
220
# Wrapped by on $(date) by $user
221
# Source directory was \`$(pwd)'.
222
#
223
# This shar contains:
224
# length mode name
225
# ------ ---------- ------------------------------------------
226
!!!
227
ls -df "#%8(size)d %(mode)s %(name)s" $contdirs $contents
228
print '\n#\nnocheck=$1'
229
230
if [[ $flags == *Q* ]]
231
then print quiet=:
232
else print quiet=false
233
fi
234
235
if [[ $flags == *x* ]]
236
then print nocheck=-c
237
fi
238
239
if [[ $flags != *D* ]]
240
then cat <<- \!!!
241
if uncompress < /dev/null > /dev/null 2>&1
242
then uncompress='uncompress -f'
243
elif gunzip < /dev/null > /dev/null 2>&1
244
then uncompress='gunzip -f'
245
fi
246
247
if md5sum /dev/null > /dev/null 2>&1
248
then md5=md5sum
249
elif cksum -x md5 /dev/null > /dev/null 2>&1
250
then md5='cksum -x md5'
251
fi
252
253
if touch -am 123456789 shar$$.3 > /dev/null 2>&1 && test -f shar$$.3
254
then touch=touch
255
else touch=:
256
echo 'WARNING: not restoring timestamps.'
257
fi
258
rm -f 123456789 shar$$.3
259
260
!!!
261
fi
262
263
if [[ $flags == *X* ]]
264
then cat <<- \!!!
265
#
266
# The unshar will be interactively queried
267
#
268
if test ! -t 2
269
then exec < /dev/tty
270
fi
271
if test "`echo -n | wc -c`" -gt 0
272
then nflag= cflag='\c'
273
else nflag=-n cflag=
274
fi
275
!!!
276
fi
277
278
279
function isbinary #file
280
{
281
[[ $(file -m /dev/null -M "$1") == @(*/ebcdic*|*/octet-stream|*system*/*) ]]
282
}
283
284
function emit_guard # file type
285
{
286
cat <<- !!!
287
echo \$nflag '? -' overwrite "$name" '[no, yes, all, quit] (no)?' \$cflag
288
read check
289
case \$check in
290
[Aa]*) nocheck=-c;;
291
[Qq]*) echo 'extraction aborted';exit 1;;
292
[Yy]*) ;;
293
*) skip=1;;
294
esac
295
fi
296
if test "\$skip" = 1
297
then
298
!!!
299
}
300
301
function makedirs # file
302
{
303
typeset file=$1
304
file=$(dirname "$file")
305
if [[ $file == @(.|/|//) ]]
306
then return
307
fi
308
makedirs "$file"
309
cat <<- !!!
310
if test ! -d '$file'
311
then test X"\$quiet" != X && echo 'x -' '$mkdir' '$file'
312
mkdir '$file'
313
fi
314
!!!
315
}
316
317
# Emit the files and their separators:
318
function pack_file
319
{
320
typeset file=$1
321
filetype=text binary=
322
if [[ -d $file ]]
323
then filteype=directory
324
else case $mode in
325
B) filetype=binary;;
326
z) filetype=gzipped;;
327
Z) filetype=compressed;;
328
M) if isbinary "$file"
329
then filetype=binary
330
binary=1
331
fi
332
esac
333
fi
334
# Decide which name to archive under.
335
if [[ $flags == *f* ]]
336
then name=${file##*/}
337
[[ $flags != *q* ]] && logmsg "a - $name [from $file] ($filetype)"
338
else name="$file"
339
[[ $flags != *q* ]] && logmsg "a - $file ($filetype)"
340
fi
341
342
print -r "# ============= $file =============="
343
if [[ $file == */* ]]
344
then makedirs "$file"
345
fi
346
# Emit either a mkdir or a cat/sed to extract the file.
347
if [[ -d $file ]]
348
then print "mkdir $file"
349
[[ flags != *Q* ]] && print "echo mkdir -- $file"
350
else filetype=text binary=
351
print 'skip='
352
printf "if\ttest -f %q && test \"X\$nocheck\" != X-c\nthen\t" "$file"
353
if [[ $flags == *X* ]]
354
then emit_guard
355
fi
356
printf "\$quiet || $skipping %q $exists\nelse \$quiet || $extract %q '(%s)'\n" "$file" "$file" "$filetype"
357
if [[ $mode == [BZz] || $binary ]]
358
then if [[ $mode == Z ]]
359
then compress $arg < $file > /tmp/shar$$.2
360
cname=$name.Z
361
dname=/tmp/shar$$.2
362
elif [[ $mode == z ]]
363
then gzip $arg < $file > /tmp/shar$$.2
364
dname=/tmp/shar$$.2
365
cname=$name.gz
366
else dname=$file
367
cname=$name
368
fi
369
print -r 'uudecode << \!!!!'
370
uuencode "$cname" < $dname
371
print "!!!!"
372
if [[ $mode == Z && flags != *Q* ]]
373
then printf "echo '$uncomp' %s\n\$uncompress %q\n" "$file" "$cname"
374
elif [[ $mode == z && flags != *Q* ]]
375
then printf "echo '$uncomp' %s\ngunzip %q\n" "$file" "$cname"
376
fi
377
else print -r "sed 's/^@//' > \"$name\" <<'$separator'"
378
sed -e 's/^[.~@]/@&/' -e 's/^From/@&/' "$file"
379
print -r $separator
380
fi
381
fi
382
383
# Emit chmod to set permissions on the extracted file;
384
# this keels over if the filename contains "?".
385
fmode=$(ls -df "%(mode)s" "$file")
386
fmode=${fmode/?@(???)@(???)@(???)/u=\1,g=\2,o=\3}
387
mtime=$(date -m -f %# "$file")
388
printf "chmod ${fmode//-} %q&&\n\t\$touch -am $mtime %q\n" "$name" "$name"
389
print "fi"
390
}
391
392
if [[ $flags == *S* ]]
393
then while read -r file
394
do pack_file "$file"
395
done < /tmp/shar$$.3
396
else for file
397
do pack_file "$file"
398
done
399
fi
400
401
# If the -c option was given, emit the checking epilogue:
402
# If the receiving machine has cksum, it will be used instead of wc
403
404
files=$(printf "%q " $contents)
405
if [[ $flags != *w* && $flags != *D* ]]
406
then cat <<- __END__
407
\$quiet || echo 'Inspecting for damage in transit...'
408
temp=/tmp/shar\$\$; dtemp=/tmp/.shar\$\$
409
trap "rm -f \$temp \$dtemp; exit" EXIT HUP INT QUIT TERM
410
if [ X"\$md5" != X ]
411
then cat > \$temp <<\!!!
412
$(
413
if [[ $flags == *b* ]]
414
then cksum -x md5 "$@" | sed 's=[^ ]*/=='
415
else cksum -x md5 $contents | sed 's=[^ ]*/=='
416
fi
417
)
418
!!!
419
cksum='cksum -x md5'
420
else cat > \$temp <<\!!!
421
$(
422
IFS=$'\n' # this line should not be needed
423
if [[ $flags == *b* ]]
424
then wc "$@" | sed 's=[^ ]*/=='
425
else wc $contents | sed 's=[^ ]*/=='
426
fi
427
)
428
!!!
429
cksum=wc
430
fi
431
\$cksum $files | sed 's=[^ ]*/==' | diff -b \$temp - >\$dtemp
432
if [ -s \$dtemp ]
433
then echo "Ouch [diff of \$cksum output]:" ; cat \$dtemp
434
else \$quiet || echo "No problems found."
435
fi
436
__END__
437
fi
438
439
# split or limit size
440
if [[ $prefix ]]
441
then if [[ $split ]]
442
then split -b $size -f "$prefix" /tmp/shar$$.1
443
elif (( $size && $(wc -c < /tmp/shar$$.1) > $size ))
444
then head -c $size /tmp/shar$$.1 > $prefix.01
445
else cp /tmp/shar$$.1 "$prefix.01"
446
fi
447
fi
448
449
print 'exit 0' # exit even if more input
450
451