forked from zfsnap/zfsnap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPORTABILITY
120 lines (102 loc) · 5.32 KB
/
PORTABILITY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
zfsnap is written assuming a POSIX compliant shell with additional support for
the keyword `local` for variable scoping. It also requires a few POSIX
compliant utilities (uname, head, etc). This short list of requirements allows
zfsnap to remain very portable. All OSs known to run ZFS have at least one
compatible shell available in the base install. It will run on either 32-bit or
64-bit systems.
== Shells Known To Work
- sh (some modern variants. e.g. FreeBSD's sh)
- ash (including busybox's)
- bash
- dash
- ksh88
- lksh
- mksh
- pdksh
- posh
- zsh
== Bourne Shells Known To Not Work
- sh (the original AT&T sh)
- does not have support for the `local` keyword
- ksh93
- does not have support for the `local` keyword. It /does/ support `typeset`,
but typeset does not scope variables locally unless functions are written as
"function foo { }" rather than "foo() { }". The former syntax is non-POSIX
and causes dash (and I assume other shells too) to choke. Thus, adjusting
the function declaration and a simple "alias local=typeset" will not work.
== Shells Which Will Never Be Supported
This should go without saying, but given that zfsnap is written using Bourne
shell syntax, it will never be able to run in non-Bourne shells. This includes
the C shell family (csh, tcsh) and any "exotic" shells like fish.
== Operating System Notes
Not sure which shell to use? Chances are good on a modern system that the
default (/bin/sh) will point to a sane and compatible shell. Try it; it likely
works.
Solaris 10:
- /bin/ksh (which is ksh88) and /bin/bash will work
Solaris 11:
- /bin/bash (or ksh88 if installed, though it isn't available by default)
Other SunOS (Illumos, OmniOS, etc)
- /bin/bash or many others available via the package manager
*BSD and Linux
- the default /bin/sh nearly always works
- dash is quite fast; if you have a choice, use it
- otherwise, there are many others available via the package manager
OS X
- /bin/sh points to bash
tools/mod_shebang.sh can help you change all zfsnap scripts to your shell of
choice. For example:
cd /tmp/zfsnap
find ./ -type d \( -name tools -o -name vagrant \) -prune -o -type f \
-exec tools/mod_shebang.sh -s '#!/bin/bash' {} \;
== Man Page
zfsnap's man page is written using mdoc (which is largely based off of roff).
All target OSs, with the exception of Solaris, have support to correctly display
mdoc man pages.
== Just Simply: Why?
If you're curious about some of the design limitations or decisions, this is a
brief discussion of some selected points. Otherwise, the mailing list is the
best place to ask.
=== Why `local`?
The use of `local` is the least portable aspect of zfsnap. However, programming
zfsnap with every variable global in scope would be horrifying; the variable
names would be complex and make the code more difficult to understand. A wide
range of shells --- old and new --- support local, and the readability and
elimination of an entire class of bugs is well worth the cost.
=== Why limit to 32-bit math?
zfsnap aims to run everywhere ZFS can, so it is important to support both 32-bit
and 64-bit platforms. Most of the time, a machine's architecture is irrelevant
to zfsnap; however, zfsnap does provide estimates of the amount of data to be
deleted. This requires math, and exceeding 32-bit integers is trivial (2GB)
when operating in Bytes.
POSIX states that shell integers must be a signed long. So on 64-bit systems
it's 64-bit and on 32-bit systems it's 32-bit.
The situation is complicated because overflows are undefined behavior, and thus
the result is up to the implementation and/or compiler. For this reason
(according to the lksh man page), mksh breaks from POSIX and limits shell math
to 32-bit integers on both 32-bit and 64-bit systems. mksh provides lksh
(Legacy Korn Shell) for POSIX compliant behavior (among other things).
About half of the shells support 64-bit math on 32-bit systems.
awk, bc, and expr are possible alternatives. AFAICT, POSIX doesn't define the
integer length for any of them, and I have yet to test across them across all
target systems. Furthermore:
awk - likely to be present on all systems. But there are many variants of
awk, and I am concerned about syntax portability and 64-bit support.
bc - best suited to the task, but is not ubiquitous. For example,
Debian-based systems don't have bc installed by default.
expr - quite primitive and unlikely to have 64-bit support. Also, it is
limited to integer math.
=== Why Shell?
Portability is the chief reason but also accessibility for sysadmins. Any
sysadmin worth his/her salt knows shell. Thus it's easy for others to audit,
extend, and contribute to the project. Accessibility influences other design
decisions as well: all needed information is in the snapshot name, thus there's
no config file to parse or database to query. It keeps things easy to use and
understand --- and easy to fix if anything should go wrong.
=== Why mdoc?
roff/groff/troff/lmnop-roff is a pretty ugly language. mdoc inherits that
unfortunate legacy, but takes a more streamlined approach that focuses on doing
man pages well rather than attempting to be a full typesetting language. As a
result, mdoc is (comparatively) easy to write in, is reasonably well supported,
and can be exported /much/ more easily (and correctly) to other formats such as
HTML.