[PROPOSED 0/3] zic options -D, -m, and -u from FreeBSD
This thread contains proposed patches to add support for the zic options -D, -m, and -u, which have been in FreeBSD zic for many years. The implementation differs from that of FreeBSD, to fix some unlikely security races. I installed these patches in the development repository on GitHub. Paul Eggert (3): New zic option -D, inspired by FreeBSD New zic option -m, inspired by FreeBSD New zic option -u, inspired by FreeBSD Makefile | 8 ++ NEWS | 2 + zic.8 | 32 +++++++ zic.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 293 insertions(+), 8 deletions(-) -- 2.48.1
* NEWS, zic.8, zic.c (usage): Mention it. * zic.c (skip_mkdir): New static var. (main): Set it. (mkdirs): Use it. --- NEWS | 2 ++ zic.8 | 6 ++++++ zic.c | 16 +++++++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index c605a1fb..e777c6a7 100644 --- a/NEWS +++ b/NEWS @@ -105,6 +105,8 @@ Unreleased, experimental changes exceedingly long TZ strings no longer fail merely because they exceed an arbitrary file name length limit imposed by tzcode. + zic has a new option -D, inspired by FreeBSD. + zic now uses the fdopen function, which was standardized by POSIX.1-1988 and is now safe to use in portable code. This replaces its use of the older umask function, which diff --git a/zic.8 b/zic.8 index 62ebfcc9..45318020 100644 --- a/zic.8 +++ b/zic.8 @@ -77,6 +77,12 @@ Also see the .B \-r option for another way to alter output size. .TP +.BI \-D +Do not create ancestor directories of output files, +For example, for a zone named America/Los_Angeles +the directory America should already exist. +By default, the directory and its ancestors are created +if they do not already exist. .BI "\-d " directory Create time conversion information files in the named directory rather than in the standard directory named below. diff --git a/zic.c b/zic.c index 9a2c0624..d8408abf 100644 --- a/zic.c +++ b/zic.c @@ -247,6 +247,7 @@ static int max_format_len; static zic_t max_year; static zic_t min_year; static bool noise; +static bool skip_mkdir; static int rfilenum; static lineno rlinenum; static const char * progname; @@ -704,8 +705,8 @@ usage(FILE *stream, int status) { fprintf(stream, _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" - "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" - " [ -L leapseconds ] \\\n" + "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n" + "\t[ -l localtime ] [ -L leapseconds ] \\\n" "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n" "\t[ -t localtime-link ] \\\n" "\t[ filename ... ]\n\n" @@ -1037,7 +1038,7 @@ main(int argc, char **argv) } else if (strcmp(argv[k], "--help") == 0) { usage(stdout, EXIT_SUCCESS); } - while ((c = getopt(argc, argv, "b:d:l:L:p:r:R:st:vy:")) != -1) + while ((c = getopt(argc, argv, "b:d:Dl:L:p:r:R:st:vy:")) != -1) switch (c) { default: usage(stderr, EXIT_FAILURE); @@ -1058,6 +1059,9 @@ main(int argc, char **argv) duplicate_options("-d"); directory = optarg; break; + case 'D': + skip_mkdir = true; + break; case 'l': if (lcltime) duplicate_options("-l"); @@ -3951,6 +3955,11 @@ mp = _("time zone abbreviation differs from POSIX standard"); static void mkdirs(char const *argname, bool ancestors) { + /* If -D was specified, do not create directories. + If a file operation's parent directory is missing, + the operation will fail and be diagnosed. */ + if (!skip_mkdir) { + char *name = xstrdup(argname); char *cp = name; @@ -3997,4 +4006,5 @@ mkdirs(char const *argname, bool ancestors) *cp++ = '/'; } free(name); + } } -- 2.48.1
* Makefile, NEWS, zic.8: Mention this. * zic.c (arg2num, mode_option, chmetadata): New functions. (mode_t) [!HAVE_SYS_STAT_H]: New macro if not already defined. (MODE_T_MAX, MODE_OPTION): New macros. (HAVE_FCHMOD): New macro, defaulting to 1. (fchmod): Default to returning 0. (HAVE_SETMODE): New macro, defaulting to 1 on BSDish platforms. (no_mode): New static constant. (output_mode): New static var. (close_file): Change metadata of temp files before closing, and fflush before changing metadata as this may work around OS bugs. (main): Support -m. --- Makefile | 5 +++ NEWS | 2 +- zic.8 | 13 ++++++++ zic.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 8f85fcfd..224f250a 100644 --- a/Makefile +++ b/Makefile @@ -244,6 +244,7 @@ LDLIBS= # -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ' # -DHAVE_DECL_TIMEGM=0 if <time.h> does not declare timegm # -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows) +# -DHAVE_FCHMOD=0 if your system lacks the fchmod function # -DHAVE__GENERIC=0 if _Generic does not work* # -DHAVE_GETAUXVAL=1 if getauxval works, 0 otherwise (default is guessed) # -DHAVE_GETEUID=0 if gete?[ug]id do not work @@ -267,6 +268,8 @@ LDLIBS= # -DHAVE_POSIX_DECLS=0 if your system's include files do not declare # variables like 'tzname' required by POSIX # -DHAVE_SETENV=0 if your system lacks the setenv function +# -DHAVE_SETMODE=[01] if your system lacks or has the setmode and getmode +# functions (default is guessed) # -DHAVE_SNPRINTF=0 if your system lacks the snprintf function+ # -DHAVE_STDCKDINT_H=0 if neither <stdckdint.h> nor substitutes like # __builtin_add_overflow work* @@ -279,6 +282,8 @@ LDLIBS= # -DHAVE_STRUCT_TIMESPEC=0 if your system lacks struct timespec+ # -DHAVE_SYMLINK=0 if your system lacks the symlink function # -DHAVE_SYS_STAT_H=0 if <sys/stat.h> does not work* +# The following additional option may be needed: +# -Dmode_t=T to define mode_t to be type T (default int) # -DHAVE_TZSET=0 if your system lacks a tzset function # -DHAVE_UNISTD_H=0 if <unistd.h> does not work* # -DHAVE_UTMPX_H=0 if <utmpx.h> does not work* diff --git a/NEWS b/NEWS index e777c6a7..8f48a7bd 100644 --- a/NEWS +++ b/NEWS @@ -105,7 +105,7 @@ Unreleased, experimental changes exceedingly long TZ strings no longer fail merely because they exceed an arbitrary file name length limit imposed by tzcode. - zic has a new option -D, inspired by FreeBSD. + zic has new options -D and -m, inspired by FreeBSD. zic now uses the fdopen function, which was standardized by POSIX.1-1988 and is now safe to use in portable code. diff --git a/zic.8 b/zic.8 index 45318020..761b204c 100644 --- a/zic.8 +++ b/zic.8 @@ -137,6 +137,19 @@ if .IR timezone 's transitions are at standard time or Universal Time (UT) instead of local time. .TP +.BI "\-m " mode +Create TZif files with the given file mode bits. +By default the files are created with mode 644 as modified by the umask. +With this option they are created with the given mode instead. +For portability the mode should be an unsigned octal integer, +typically 644 or 444; +some platforms also support +.BR chmod (1)-style +symbolic modes. +This option does not affect created ancestor directories, +which have mode 755 as modified by the umask. +The option is ignored on platforms lacking the notion of file mode bits. +.TP .BR "\-r " "[\fB@\fP\fIlo\fP][\fB/@\fP\fIhi\fP]" Limit the applicability of output files to timestamps in the range from diff --git a/zic.c b/zic.c index d8408abf..fc03c32d 100644 --- a/zic.c +++ b/zic.c @@ -67,6 +67,10 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 }; #if HAVE_SYS_STAT_H # include <sys/stat.h> +#else +# ifndef mode_t +# define mode_t int +# endif #endif #ifndef S_IRWXU @@ -672,14 +676,91 @@ warning(const char *const string, ...) warnings = true; } -/* Close STREAM. If it had an I/O error, report it against DIR/NAME, - remove TEMPNAME if nonnull, and then exit. */ +/* Convert ARG, a string in base BASE, to an unsigned long value no + greater than MAXVAL. On failure, diagnose with MSGID and exit. */ +static unsigned long +arg2num(char const *arg, int base, unsigned long maxval, char const *msgid) +{ + unsigned long n; + char *ep; + errno = 0; + n = strtoul(arg, &ep, base); + if (ep == arg || *ep || maxval < n || errno) { + fprintf(stderr, _(msgid), progname, arg); + exit(EXIT_FAILURE); + } + return n; +} + +#ifndef MODE_T_MAX +# define MODE_T_MAX_NO_PADDING MAXVAL(mode_t, TYPE_BIT(mode_t)) +# if HAVE__GENERIC +# define MODE_T_MAX \ + (TYPE_SIGNED(mode_t) \ + ? _Generic((mode_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: MODE_T_MAX_NO_PADDING) \ + : (mode_t) -1) +# else +# define MODE_T_MAX MODE_T_MAX_NO_PADDING +# endif +#endif + +#ifndef HAVE_FCHMOD +# define HAVE_FCHMOD 1 +#endif +#if !HAVE_FCHMOD +# define fchmod(fd, mode) 0 +#endif + +#ifndef HAVE_SETMODE +# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__)) +# define HAVE_SETMODE 1 +# else +# define HAVE_SETMODE 0 +# endif +#endif + +static mode_t const no_mode = -1; +static mode_t output_mode = -1; + +static mode_t +mode_option(char const *arg) +{ +#if HAVE_SETMODE + void *set = setmode(arg); + if (set) { + mode_t mode = getmode(set, CREAT_PERMS); + free(set); + return mode; + } +#endif + return arg2num(arg, 8, min(MODE_T_MAX, ULONG_MAX), + "%s: -m '%s': invalid mode\n"); +} + +static int +chmetadata(FILE *stream) +{ + return output_mode == no_mode ? 0 : fchmod(fileno(stream), output_mode); +} + +/* Close STREAM. + If it had an I/O error, report it against DIR/NAME, + remove TEMPNAME if nonnull, and then exit. + If TEMPNAME is nonnull, and if requested, + change the stream's metadata before closing. */ static void close_file(FILE *stream, char const *dir, char const *name, char const *tempname) { char const *e = (ferror(stream) ? _("I/O error") - : fclose(stream) != 0 ? strerror(errno) : NULL); + : (fflush(stream) < 0 + || (tempname && chmetadata(stream) < 0) + || fclose(stream) < 0) + ? strerror(errno) : NULL); if (e) { if (name && *name == '/') dir = NULL; @@ -706,7 +787,7 @@ usage(FILE *stream, int status) fprintf(stream, _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n" - "\t[ -l localtime ] [ -L leapseconds ] \\\n" + "\t[ -l localtime ] [ -L leapseconds ] [ -m mode ] \\\n" "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n" "\t[ -t localtime-link ] \\\n" "\t[ filename ... ]\n\n" @@ -1038,7 +1119,7 @@ main(int argc, char **argv) } else if (strcmp(argv[k], "--help") == 0) { usage(stdout, EXIT_SUCCESS); } - while ((c = getopt(argc, argv, "b:d:Dl:L:p:r:R:st:vy:")) != -1) + while ((c = getopt(argc, argv, "b:d:Dl:L:m:p:r:R:st:vy:")) != -1) switch (c) { default: usage(stderr, EXIT_FAILURE); @@ -1067,6 +1148,11 @@ main(int argc, char **argv) duplicate_options("-l"); lcltime = optarg; break; + case 'm': + if (output_mode != no_mode) + duplicate_options("-m"); + output_mode = mode_option(optarg); + break; case 'p': if (psxrules) duplicate_options("-p"); -- 2.48.1
* Makefile, NEWS, zic.8: Mention this. * private.h (_): Parenthesize result, for compatibility with N_. (N_): New macro, for strings translated later. * zic.c (creat_perms): New static var. (HAVE_PWD_H): Provide a default, typically 1. [HAVE_PWD_H]: Include pwd.h and grp.h. (gid_t, uid_t, struct group, struct passwd, getgrnam, getpwnam, fchown): New fallback types and macros if !HAVE_PWD_H. (no_gid, no_uid): New static constants, so that we can avoid casts. (output_group, output_owner): New static vars. (GID_T_MAX, UID_T_MAX): New macros. (chmetadata): fchown output if requested. (usage): Mention -u. (group_option, owner_option, use_safe_permissions): New static functions. (main): Support -u (and -g, but this is undocumented). (open_outfile): Use creat_perms instead of CREAT_PERMS. --- Makefile | 3 ++ NEWS | 2 +- zic.8 | 13 +++++ zic.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 168 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 224f250a..b3ceb997 100644 --- a/Makefile +++ b/Makefile @@ -267,6 +267,9 @@ LDLIBS= # -DHAVE_MEMPCPY=1 if your system has mempcpy, 0 if not (default is guessed) # -DHAVE_POSIX_DECLS=0 if your system's include files do not declare # variables like 'tzname' required by POSIX +# -DHAVE_PWD_H=0 if your system lacks pwd.h, grp.h and corresponding functions +# The following additional options may be needed: +# -Dgid_t=T, -Duid_t=T to define gid_t, uid_t to be type T (default int) # -DHAVE_SETENV=0 if your system lacks the setenv function # -DHAVE_SETMODE=[01] if your system lacks or has the setmode and getmode # functions (default is guessed) diff --git a/NEWS b/NEWS index 8f48a7bd..9764cf0c 100644 --- a/NEWS +++ b/NEWS @@ -105,7 +105,7 @@ Unreleased, experimental changes exceedingly long TZ strings no longer fail merely because they exceed an arbitrary file name length limit imposed by tzcode. - zic has new options -D and -m, inspired by FreeBSD. + zic has new options -D, -m, and -u, inspired by FreeBSD. zic now uses the fdopen function, which was standardized by POSIX.1-1988 and is now safe to use in portable code. diff --git a/zic.8 b/zic.8 index 761b204c..75ca288e 100644 --- a/zic.8 +++ b/zic.8 @@ -203,6 +203,19 @@ it increases the size of the altered output files. When creating local time information, put the configuration link in the named file rather than in the standard location. .TP +.BI "\-u " owner\fR[:\fPgroup\fR]\fP +Change the output regular files' owner and group to those specified. +The +.I owner +is either a user name, or an unsigned decimal integer user ID, +or an empty string meaning no change to the owner. +The +.I group +is similar for group names and IDs. +This option does not affect directories or hard or symbolic links. +It typically needs special privileges to change ownership, +and is ignored on platforms that lack the notions of owners and groups. +.TP .B \-v Be more verbose, and complain about the following situations: .RS diff --git a/zic.c b/zic.c index fc03c32d..d6bf8b60 100644 --- a/zic.c +++ b/zic.c @@ -101,7 +101,68 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 }; /* File permission bits for making regular files. The umask modifies these bits. */ #define CREAT_PERMS (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH)) +static mode_t creat_perms = CREAT_PERMS; +#ifndef HAVE_PWD_H +# ifdef __has_include +# if __has_include(<pwd.h>) && __has_include(<grp.h>) +# define HAVE_PWD_H 1 +# else +# define HAVE_PWD_H 0 +# endif +# endif +#endif +#ifndef HAVE_PWD_H +# define HAVE_PWD_H 1 +#endif +#if HAVE_PWD_H +# include <grp.h> +# include <pwd.h> +#else +# ifndef gid_t +# define gid_t int +# endif +# ifndef uid_t +# define uid_t int +# endif +struct group { gid_t gr_gid; }; +struct passwd { uid_t pw_uid; }; +# define getgrnam(arg) NULL +# define getpwnam(arg) NULL +# define fchown(fd, owner, group) ((fd) < 0 ? -1 : 0) +#endif +static gid_t const no_gid = -1; +static uid_t const no_uid = -1; +static gid_t output_group = -1; +static uid_t output_owner = -1; +#ifndef GID_T_MAX +# define GID_T_MAX_NO_PADDING MAXVAL(gid_t, TYPE_BIT(gid_t)) +# if HAVE__GENERIC +# define GID_T_MAX \ + (TYPE_SIGNED(gid_t) \ + ? _Generic((gid_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: GID_T_MAX_NO_PADDING) \ + : (gid_t) -1) +# else +# define GID_T_MAX GID_T_MAX_NO_PADDING +# endif +#endif +#ifndef UID_T_MAX +# define UID_T_MAX_NO_PADDING MAXVAL(uid_t, TYPE_BIT(uid_t)) +# if HAVE__GENERIC +# define UID_T_MAX \ + (TYPE_SIGNED(uid_t) \ + ? _Generic((uid_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: UID_T_MAX_NO_PADDING) \ + : (uid_t) -1) +# else +# define UID_T_MAX UID_T_MAX_NO_PADDING +# endif +#endif /* The minimum alignment of a type, for pre-C23 platforms. The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks @@ -738,12 +799,17 @@ mode_option(char const *arg) } #endif return arg2num(arg, 8, min(MODE_T_MAX, ULONG_MAX), - "%s: -m '%s': invalid mode\n"); + N_("%s: -m '%s': invalid mode\n")); } static int chmetadata(FILE *stream) { + if (output_owner != no_uid || output_group != no_gid) { + int r = fchown(fileno(stream), output_owner, output_group); + if (r < 0) + return r; + } return output_mode == no_mode ? 0 : fchmod(fileno(stream), output_mode); } @@ -789,7 +855,7 @@ usage(FILE *stream, int status) "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n" "\t[ -l localtime ] [ -L leapseconds ] [ -m mode ] \\\n" "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n" - "\t[ -t localtime-link ] \\\n" + "\t[ -t localtime-link ] [ -u 'owner[:group]' ] \\\n" "\t[ filename ... ]\n\n" "Report bugs to %s.\n"), progname, progname, REPORT_BUGS_TO); @@ -798,6 +864,71 @@ usage(FILE *stream, int status) exit(status); } +static void +group_option(char const *arg) +{ + if (*arg) { + if (output_group != no_gid) { + fprintf(stderr, _("multiple groups specified")); + exit(EXIT_FAILURE); + } else { + struct group *gr = getgrnam(arg); + output_group = (gr ? gr->gr_gid + : arg2num(arg, 10, min(GID_T_MAX, ULONG_MAX), + N_("%s: invalid group: %s\n"))); + } + } +} + +static void +owner_option(char const *arg) +{ + if (*arg) { + if (output_owner != no_uid) { + fprintf(stderr, _("multiple owners specified")); + exit(EXIT_FAILURE); + } else { + struct passwd *pw = getpwnam(arg); + output_owner = (pw ? pw->pw_uid + : arg2num(arg, 10, min(UID_T_MAX, ULONG_MAX), + N_("%s: invalid owner: %s\n"))); + } + } +} + +/* If setting owner or group, use temp file permissions that avoid + security races before the fchmod at the end. */ +static void +use_safe_temp_permissions(void) +{ + if (output_owner != no_uid || output_group != no_gid) { + + /* The mode when done with the file. */ + mode_t omode; + if (output_mode == no_mode) { + mode_t cmask = umask(0); + umask(cmask); + omode = CREAT_PERMS & ~cmask; + } else + omode = output_mode; + + /* The mode passed to open+O_CREAT. Do not bother with executable + permissions, as they should not be used and this mode is merely + a nicety (even a mode of 0 still work). */ + creat_perms = ((((omode & (S_IRUSR | S_IRGRP | S_IROTH)) + == (S_IRUSR | S_IRGRP | S_IROTH)) + ? S_IRUSR | S_IRGRP | S_IROTH : 0) + | (((omode & (S_IWUSR | S_IWGRP | S_IWOTH)) + == (S_IWUSR | S_IWGRP | S_IWOTH)) + ? S_IWUSR | S_IWGRP | S_IWOTH : 0)); + + /* If creat_perms is not the final mode, arrange to run + fchmod later, even if -m was not used. */ + if (creat_perms != omode) + output_mode = omode; + } +} + /* Change the working directory to DIR, possibly creating DIR and its ancestors. After this is done, all files are accessed with names relative to DIR. */ @@ -1119,7 +1250,7 @@ main(int argc, char **argv) } else if (strcmp(argv[k], "--help") == 0) { usage(stdout, EXIT_SUCCESS); } - while ((c = getopt(argc, argv, "b:d:Dl:L:m:p:r:R:st:vy:")) != -1) + while ((c = getopt(argc, argv, "b:d:Dg:l:L:m:p:r:R:st:u:vy:")) != -1) switch (c) { default: usage(stderr, EXIT_FAILURE); @@ -1143,6 +1274,11 @@ main(int argc, char **argv) case 'D': skip_mkdir = true; break; + case 'g': + /* This undocumented option is present for + compatibility with FreeBSD 14. */ + group_option(optarg); + break; case 'l': if (lcltime) duplicate_options("-l"); @@ -1163,6 +1299,16 @@ main(int argc, char **argv) duplicate_options("-t"); tzdefault = optarg; break; + case 'u': + { + char *colon = strchr(optarg, ':'); + if (colon) + *colon = '\0'; + owner_option(optarg); + if (colon) + group_option(colon + 1); + } + break; case 'y': warning(_("-y ignored")); break; @@ -1228,6 +1374,7 @@ main(int argc, char **argv) if (errors) return EXIT_FAILURE; associate(); + use_safe_temp_permissions(); change_directory(directory); directory_ends_in_slash = directory[strlen(directory) - 1] == '/'; catch_signals(); @@ -1460,7 +1607,7 @@ open_outfile(char const **outname, char **tempname) while (true) { int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL; - int fd = open(*outname, oflags, CREAT_PERMS); + int fd = open(*outname, oflags, creat_perms); int err; if (fd < 0) err = errno; -- 2.48.1
On 2025-10-24 01:44, Paul Eggert via tz wrote:
This thread contains proposed patches to add support for the zic options -D, -m, and -u, which have been in FreeBSD zic for many years. The implementation differs from that of FreeBSD, to fix some unlikely security races. I installed these patches in the development repository on GitHub.
Paul Eggert (3): New zic option -D, inspired by FreeBSD New zic option -m, inspired by FreeBSD New zic option -u, inspired by FreeBSD
Makefile | 8 ++ NEWS | 2 + zic.8 | 32 +++++++ zic.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 293 insertions(+), 8 deletions(-)
-- 2.48.1
Please summarize the new options' functions where mentioned in NEWS, for non-FreeBSD users and those unfamiliar with these non-standard options, for example: New zic options, -D, -m mode, -u owner[:group], inspired by FreeBSD: -D Do not create ancestor directories of output files -m mode Create TZif files with the given file mode bits -u owner[:group] Change the output regular files' owner and group to those specified although wording could be more consistent between -m and -u, perhaps also saying TZif files rather than "regular"? files, and more consistent with or referring to chgrp(3/1)/chmod(3/1)/chown(3/1)/open(3), perhaps only in the option details? -- Take care. Thanks, Brian Inglis Calgary, Alberta, Canada La perfection est atteinte Perfection is achieved non pas lorsqu'il n'y a plus rien à ajouter not when there is no more to add mais lorsqu'il n'y a plus rien à retrancher but when there is no more to cut -- Antoine de Saint-Exupéry
participants (2)
-
Brian Inglis -
Paul Eggert