diff options
author | Oliver Kiddle <opk@zsh.org> | 2015-07-24 12:36:35 +0200 |
---|---|---|
committer | Oliver Kiddle <opk@zsh.org> | 2015-07-24 12:36:35 +0200 |
commit | 0f02b27ab03772516a9ebb716f26e8b5b2c96ccc (patch) | |
tree | 27426e875983280681f57c98ff92e40181273d0c | |
parent | acf1fa60345bb48eaca1559408cad141a87e2870 (diff) | |
download | zsh-0f02b27ab03772516a9ebb716f26e8b5b2c96ccc.tar.gz zsh-0f02b27ab03772516a9ebb716f26e8b5b2c96ccc.tar.xz zsh-0f02b27ab03772516a9ebb716f26e8b5b2c96ccc.zip |
35864: add sysopen, sysseek and systell to system module
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | Doc/Zsh/mod_system.yo | 58 | ||||
-rw-r--r-- | Src/Modules/system.c | 184 | ||||
-rw-r--r-- | Src/Modules/system.mdd | 2 |
4 files changed, 246 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog index 2ff240c9b..ecfb21c80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2015-07-24 Oliver Kiddle <opk@zsh.org> + * 35864: Doc/Zsh/mod_system.yo, Src/Modules/system.c, + Src/Modules/system.mdd: add sysopen, sysseek and systell to + system module + * 35879: Eric Cook: Completion/Linux/Command/_btrfs: fix for subcommands that don't have a second subcommand diff --git a/Doc/Zsh/mod_system.yo b/Doc/Zsh/mod_system.yo index 7f9c011a7..e4d4c31f7 100644 --- a/Doc/Zsh/mod_system.yo +++ b/Doc/Zsh/mod_system.yo @@ -28,6 +28,47 @@ system's range), a return status of 1 indicates an error in the parameters, and a return status of 2 indicates the error name was not recognised (no message is printed for this). ) +findex(sysopen) +redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi( ))) +xitem(tt(sysopen) [ tt(-arw) ] [ tt(-m) var(permissions) ] [ tt(-o) var(options) ]) +item(SPACES()[ tt(-u) var(fd) ] var(file))( +This command opens a file. The tt(-r), tt(-w) and tt(-a) flags indicate +whether the file should be opened for reading, writing and appending, +respectively. The tt(-m) option allows the initial permissions to use when +creating a file to be specified in octal form. The file descriptor is +specified with -u. Either an explicit file descriptor in the range 0 to 9 can +be specified or a variable name can be given to which the file descriptor +number will be assigned. + +The tt(-o) option allows various system specific options to be +specified as a comma-separated list. The following is a list of possible +options. Note that, depending on the system, some may not be available. +startitem() +item(tt(cloexec))( +mark file to be closed when other programs are executed +) +xitem(tt(create)) +item(tt(creat))( +create file if it does not exist +) +item(tt(excl))( +create file, error if it already exists +) +item(tt(noatime))( +suppress updating of the file atime +) +item(tt(nofollow))( +fail if var(file) is a symbolic link +) +item(tt(sync))( +request that writes wait until data has been physically written +) +xitem(tt(truncate)) +item(tt(trunc))( +truncate file to size 0 +) +enditem() +) findex(sysread) redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi( ))) xitem(tt(sysread )[ tt(-c) var(countvar) ] [ tt(-i) var(infd) ] [ tt(-o) var(outfd) ]) @@ -89,6 +130,14 @@ usual rules; no write to var(outfd) is attempted. ) enditem() ) +item(tt(sysseek) [ tt(-u) var(fd) ] [ tt(-w) tt(start)|tt(end)|tt(current) ] var(offset))( +The current file position at which future reads and writes will take place is +adjusted to the specified byte offset. The var(offset) is evaluated as a math +expression. The tt(-u) option allows the file descriptor to be specified. By +default the offset is specified relative to the start or the file but, with the +tt(-w) option, it is possible to specify that the offset should be relative to +the current position or the end of the file. +) item(tt(syswrite) [ tt(-c) var(countvar) ] [ tt(-o) var(outfd) ] var(data))( The data (a single string of bytes) are written to the file descriptor var(outfd), or 1 if that is not given, using the tt(write) system call. @@ -161,6 +210,15 @@ version of the shell before it was implemented). ) enditem() +subsect(Math Functions) + +startitem() +item(tt(systell+LPAR()var(fd)RPAR()))( +The systell math function returns the current file position for the file +descriptor passed as an argument. +) +enditem() + subsect(Parameters) startitem() diff --git a/Src/Modules/system.c b/Src/Modules/system.c index f6a21d160..a1ed33a96 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -279,6 +279,183 @@ bin_syswrite(char *nam, char **args, Options ops, UNUSED(int func)) } +static struct { char *name; int oflag; } openopts[] = { +#ifdef O_CLOEXEC + { "cloexec", O_CLOEXEC }, +#else +# ifdef FD_CLOEXEC + { "cloexec", 0 }, /* this needs to be first in the table */ +# endif +#endif +#ifdef O_NOFOLLOW + { "nofollow", O_NOFOLLOW }, +#endif +#ifdef O_SYNC + { "sync", O_SYNC }, +#endif +#ifdef O_NOATIME + { "noatime", O_NOATIME }, +#endif + { "excl", O_EXCL | O_CREAT }, + { "creat", O_CREAT }, + { "create", O_CREAT }, + { "truncate", O_TRUNC }, + { "trunc", O_TRUNC } +}; + +/**/ +static int +bin_sysopen(char *nam, char **args, Options ops, UNUSED(int func)) +{ + int read = OPT_ISSET(ops, 'r'); + int write = OPT_ISSET(ops, 'w'); + int append = OPT_ISSET(ops, 'a') ? O_APPEND : 0; + int flags = O_NOCTTY | append | ((append || write) ? + (read ? O_RDWR : O_WRONLY) : + (!append || read) ? O_RDONLY : O_WRONLY); + char *opt, *ptr, *nextopt, *fdvar; + int o, fd, explicit = -1; + mode_t perms = 0666; +#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) + int fdflags; +#endif + + if (!OPT_ISSET(ops, 'u')) { + zwarnnam(nam, "file descriptor not specified"); + return 1; + } + + /* file descriptor, either 0-9 or a variable name */ + fdvar = OPT_ARG(ops, 'u'); + if (idigit(*fdvar) && !fdvar[1]) { + explicit = atoi(fdvar); + } else if (!isident(fdvar)) { + zwarnnam(nam, "not an identifier: %s", fdvar); + return 1; + } + + /* open options */ + if (OPT_ISSET(ops, 'o')) { + opt = OPT_ARG(ops, 'o'); + while (opt) { + if (!strncasecmp(opt, "O_", 2)) /* ignore initial O_ */ + opt += 2; + if ((nextopt = strchr(opt, ','))) + *nextopt++ = '\0'; + for (o = sizeof(openopts)/sizeof(*openopts) - 1; o >= 0 && + strcasecmp(openopts[o].name, opt); o--) {} + if (o < 0) { + zwarnnam(nam, "unsupported option: %s\n", opt); + return 1; + } +#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) + if (!openopts[o].oflag) + fdflags = FD_CLOEXEC; +#endif + flags |= openopts[o].oflag; + opt = nextopt; + } + } + + /* -m: permissions or mode for created files */ + if (OPT_ISSET(ops, 'm')) { + ptr = opt = OPT_ARG(ops, 'm'); + while (*ptr >= '0' && *ptr <= '7') ptr++; + if (*ptr || ptr - opt < 3) { + zwarnnam(nam, "invalid mode %s", opt); + return 1; + } + perms = zstrtol(opt, 0, 8); /* octal number */ + } + + if (flags & O_CREAT) + fd = open(*args, flags, perms); + else + fd = open(*args, flags); + + if (fd == -1) { + zwarnnam(nam, "can't open file %s: %e", *args, errno); + return 1; + } + fd = (explicit > -1) ? redup(fd, explicit) : movefd(fd); + if (fd == -1) { + zwarnnam(nam, "can't open file %s", *args); + return 1; + } + +#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) + if (fdflags) + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif + if (explicit == -1) { + fdtable[fd] = FDT_EXTERNAL; + setiparam(fdvar, fd); + /* if setting the variable failed, close fd to avoid leak */ + if (errflag) + zclose(fd); + } + + return 0; +} + + +/* + * Return values of bin_sysseek: + * 0 Success + * 1 Error in parameters to command + * 2 Error on seek, ERRNO set by system + */ + +/**/ +static int +bin_sysseek(char *nam, char **args, Options ops, UNUSED(int func)) +{ + int w = SEEK_SET, fd = 0; + char *whence; + off_t pos; + + /* -u: file descriptor if not stdin */ + if (OPT_ISSET(ops, 'u')) { + fd = getposint(OPT_ARG(ops, 'u'), nam); + if (fd < 0) + return 1; + } + + /* -w: whence - starting point of seek */ + if (OPT_ISSET(ops, 'w')) { + whence = OPT_ARG(ops, 'w'); + if (!(strcasecmp(whence, "current") && strcmp(whence, "1"))) + w = SEEK_CUR; + else if (!(strcasecmp(whence, "end") && strcmp(whence, "2"))) + w = SEEK_END; + else if (strcasecmp(whence, "start") && strcmp(whence, "0")) { + zwarnnam(nam, "unknown argument to -w: %s", whence); + return 1; + } + } + + pos = (off_t)mathevali(*args); + return (lseek(fd, pos, w) == -1) ? 2 : 0; +} + +/**/ +static mnumber +math_systell(UNUSED(char *name), int argc, mnumber *argv, UNUSED(int id)) +{ + int fd = (argv->type == MN_INTEGER) ? argv->u.l : (int)argv->u.d; + mnumber ret; + ret.type = MN_INTEGER; + ret.u.l = 0; + + if (fd < 0) { + zerr("file descriptor out of range"); + return ret; + } + ret.u.l = lseek(fd, 0, SEEK_CUR); + return ret; +} + + /* * Return values of bin_syserror: * 0 Successfully processed error @@ -542,6 +719,8 @@ static struct builtin bintab[] = { BUILTIN("syserror", 0, bin_syserror, 0, 1, 0, "e:p:", NULL), BUILTIN("sysread", 0, bin_sysread, 0, 1, 0, "c:i:o:s:t:", NULL), BUILTIN("syswrite", 0, bin_syswrite, 1, 1, 0, "c:o:", NULL), + BUILTIN("sysopen", 0, bin_sysopen, 1, 1, 0, "rwau:o:m:", NULL), + BUILTIN("sysseek", 0, bin_sysseek, 1, 1, 0, "u:w:", NULL), BUILTIN("zsystem", 0, bin_zsystem, 1, -1, 0, NULL, NULL) }; @@ -611,6 +790,9 @@ scanpmsysparams(UNUSED(HashTable ht), ScanFunc func, int flags) func(&spm.node, flags); } +static struct mathfunc mftab[] = { + NUMMATHFUNC("systell", math_systell, 1, 1, 0) +}; static struct paramdef partab[] = { SPECIALPMDEF("errnos", PM_ARRAY|PM_READONLY, @@ -622,7 +804,7 @@ static struct paramdef partab[] = { static struct features module_features = { bintab, sizeof(bintab)/sizeof(*bintab), NULL, 0, - NULL, 0, + mftab, sizeof(mftab)/sizeof(*mftab), partab, sizeof(partab)/sizeof(*partab), 0 }; diff --git a/Src/Modules/system.mdd b/Src/Modules/system.mdd index 46f02d166..eed0c1b9d 100644 --- a/Src/Modules/system.mdd +++ b/Src/Modules/system.mdd @@ -2,7 +2,7 @@ name=zsh/system link=dynamic load=no -autofeatures="b:sysread b:syswrite b:syserror p:errnos" +autofeatures="b:sysread b:syswrite b:sysopen b:sysseek b:syserror p:errnos f:systell" objects="system.o errnames.o" |