X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=userv.git;a=blobdiff_plain;f=client.c;h=5f60d0e5cb0d2458b43c80871540812fe5f9dad5;hp=c6b259bbd899c73046766ab8a1e33a572efe5ba5;hb=59fb8163fff0941358976353d6f98a7156e593f2;hpb=9c66781b8a9dd60bb3e23f9813700897e3bf8200 diff --git a/client.c b/client.c index c6b259b..5f60d0e 100644 --- a/client.c +++ b/client.c @@ -2,7 +2,7 @@ * userv - client.c * client code * - * Copyright (C)1996-1997,1999 Ian Jackson + * Copyright (C)1996-1997,1999-2001,2003 Ian Jackson * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -497,43 +497,99 @@ static const struct fdmodifierinfo fdmodifierinfos[]= { { 0 } }; -static void addfdmodifier(int fd, const char *key) { +static void addfdmodifier(int fd, const char *key, size_t key_len) { const struct fdmodifierinfo *fdmip; if (!*key) return; - for (fdmip= fdmodifierinfos; fdmip->string && strcmp(fdmip->string,key); fdmip++); - if (!fdmip->string) usageerror("unknown fdmodifer `%s' for fd %d",key,fd); + for (fdmip= fdmodifierinfos; + fdmip->string && + !(strlen(fdmip->string) == key_len && + !memcmp(fdmip->string,key,key_len)); + fdmip++); + if (!fdmip->string) usageerror("unknown fdmodifer `%.*s' for fd %d", + (int)key_len,key,fd); if (fdmip->conflicts & fdsetup[fd].mods) - usageerror("fdmodifier `%s' conflicts with another for fd %d",key,fd); + usageerror("fdmodifier `%.*s' conflicts with another for fd %d", + (int)key_len,key,fd); fdsetup[fd].mods |= fdmip->implies; fdsetup[fd].oflags |= fdmip->oflags; } -static int fdstdnumber(const char *string) { - if (!strcmp(string,"stdin")) return 0; - else if (!strcmp(string,"stdout")) return 1; - else if (!strcmp(string,"stderr")) return 2; - else return -1; +static void addfdmodifier_fixed(int fd, const char *key) { + addfdmodifier(fd, key, strlen(key)); } +static int fdstdnumber(const char *string, const char **delim_r) { +#define FN(v,s) do{ \ + if (!memcmp(string,s,sizeof(s)-1)) { \ + *delim_r= string+sizeof(s)-1; \ + return v; \ + } \ + }while(0) + + FN(0,"stdin"); + FN(1,"stdout"); + FN(2,"stderr"); + + return -1; +} + +static int strtofd(const char *string, + const char **mods_r /* 0: no modifiers, must go to end */, + const char *what) { + int fd; + unsigned long ul; + char *delim_v; + const char *mods; + + fd= fdstdnumber(string,&mods); + if (fd>=0) { + if (*mods && *mods != ',') + usageerror("%s, when it is `stdin', `stdout' or `stderr'," + " must be delimited with a comma from any following" + " modifiers - `%s' is not permitted", + what, mods); + goto parsed; + } + + errno= 0; + ul= strtoul(string,&delim_v,10); + if (errno || delim_v == string || ul > INT_MAX) + usageerror("%s must be must be numeric file descriptor" + " or `stdin', `stdout' or `stderr'" + " - `%s' is not recognized", + what, string); + mods= delim_v; + fd= ul; + + parsed: + if (*mods==',') + mods++; + + if (mods_r) + *mods_r= mods; + else if (*mods) + usageerror("%s must be must be only file descriptor" + " - trailing portion or modifiers `%s' not permitted", + what, mods); + + if (fd > MAX_ALLOW_FD) + usageerror("%s file descriptor specified (%d)" + " is larger than maximum allowed (%d)", + what, fd, MAX_ALLOW_FD); + + return fd; +} + static void of_file(const struct optioninfo *oip, const char *value, char *key) { unsigned long fd, copyfd; struct stat stab; int oldarraysize, r; - char *delim; - - fd= strtoul(key,&delim,10); - if (delim == key) { - delim= strchr(key,','); - if (delim) *delim++= 0; - fd= fdstdnumber(key); - if (fd<0) usageerror("first part of argument to -f or --file must be numeric " - "file descriptor or `stdin', `stdout' or `stderr' - `%s' " - "is not recognized",key); - } - if (fd > MAX_ALLOW_FD) - usageerror("file descriptor specified (%lu) is larger than maximum allowed (%d)", - fd,MAX_ALLOW_FD); + size_t mod_len; + const char *mods, *delim; + + fd= strtofd(key,&mods,"first part of argument to -f or --file"); + if (fd >= fdsetupsize) { oldarraysize= fdsetupsize; fdsetupsize+=2; fdsetupsize<<=1; @@ -554,33 +610,24 @@ static void of_file(const struct optioninfo *oip, const char *value, char *key) fdsetup[fd].oflags= 0; fdsetup[fd].mods= 0; fdsetup[fd].copyfd= -1; - while (delim && *delim) { - key= delim; - delim= strchr(key,','); - if (delim) *delim++= 0; - addfdmodifier(fd,key); + while (mods && *mods) { + delim= strchr(mods,','); + mod_len= delim ? delim-mods : strlen(mods); + addfdmodifier(fd,mods,mod_len); + mods= delim ? delim+1 : 0; } if (!(fdsetup[fd].mods & (fdm_read|fdm_write))) { if (fd == 0) { - addfdmodifier(fd,"read"); + addfdmodifier_fixed(fd,"read"); } else if (fdsetup[fd].mods & fdm_fd) { - addfdmodifier(fd,"write"); + addfdmodifier_fixed(fd,"write"); } else { - addfdmodifier(fd,"overwrite"); + addfdmodifier_fixed(fd,"overwrite"); } } if (fdsetup[fd].mods & fdm_fd) { - copyfd= fdstdnumber(value); - if (copyfd<0) { - copyfd= strtoul(value,&delim,0); - if (*delim) - usageerror("value part of argument to --file with fd modifier must be " - "numeric or fd name - `%s' is not recognised",value); - else if (copyfd > MAX_ALLOW_FD) - usageerror("file descriptor %lu named as target of file descriptor redirection" - " (for file descriptor %lu) is larger than maximum allowed (%d)", - copyfd,fd,MAX_ALLOW_FD); - } + copyfd= strtofd(value,0, + "value part of argument to --file with fd modifier"); r= fstat(copyfd,&stab); if (r) { if (oip) fsyscallerror("check filedescriptor %lu (named as target of file " @@ -593,18 +640,9 @@ static void of_file(const struct optioninfo *oip, const char *value, char *key) static void of_fdwait(const struct optioninfo *oip, const char *value, char *key) { const struct fdmodifierinfo *fdmip; - unsigned long ul; int fd; - char *delim; - fd= fdstdnumber(key); - if (fd<0) { - ul= strtoul(key,&delim,0); - if (*delim) usageerror("first part of argument to --fdwait must be " - "numeric or fd name - `%s' is not recognised",key); - if (ul>MAX_ALLOW_FD) usageerror("first part of argument to --fdwait is too large"); - fd= ul; - } + fd= strtofd(key,0,"first part of argument to --fdwait"); if (fd >= fdsetupsize || !fdsetup[fd].filename) usageerror("file descriptor %d specified in --fdwait option is not open",fd); for (fdmip= fdmodifierinfos; fdmip->string && strcmp(fdmip->string,value); fdmip++); @@ -637,9 +675,11 @@ static void of_defvar(const struct optioninfo *oip, const char *value, char *key static void of_timeout(const struct optioninfo *oip, const char *value, char *key) { char *endp; unsigned long ul; - - ul= strtoul(value,&endp,0); - if (*endp) usageerror("timeout value `%s' must be a plain decimal string",value); + + errno= 0; + ul= strtoul(value,&endp,10); + if (errno || *endp) + usageerror("timeout value `%s' must be a plain decimal string",value); if (ul>INT_MAX) usageerror("timeout value %lu too large",ul); timeout= ul; } @@ -647,9 +687,10 @@ static void of_timeout(const struct optioninfo *oip, const char *value, char *ke static void of_signals(const struct optioninfo *oip, const char *value, char *key) { unsigned long numvalue; char *endp; - - numvalue= strtoul(value,&endp,0); - if (*endp) { + + errno= 0; + numvalue= strtoul(value,&endp,10); + if (errno || *endp) { if (!strcmp(value,"number")) signalsexit= se_number; else if (!strcmp(value,"number-nocore")) signalsexit= se_numbernocore; else if (!strcmp(value,"highbit")) signalsexit= se_highbit; @@ -1122,6 +1163,21 @@ static void prepare_asynchsignals(void) { if (alarm(timeout)<0) syscallerror("set up timeout alarm"); } + +static void close_unwanted_pipes(void) { + int fd; + + for (fd=0; fd2) + if (close(fdsetup[fd].copyfd)) + if (errno != EBADF) + /* EBADF can be induced if cmd line specifies same fd twice */ + fsyscallerror("close real fd for %d",fd); + } +} + static void catdup(const char *which, int from, int to) { if (dup2(from,to)<0) { blocksignals(SIG_BLOCK); @@ -1164,14 +1220,13 @@ static void connect_pipes(void) { reading= fdsetup[fd].mods & fdm_read; catdup(catnamebuf, fdsetup[fd].copyfd, reading ? 0 : 1); catdup(catnamebuf, fdsetup[fd].pipefd, reading ? 1 : 0); + close_unwanted_pipes(); execl("/bin/cat",catnamebuf,(char*)0); fprintf(stderr,"userv: %s: cannot exec `cat': %s\n",catnamebuf,strerror(errno)); exit(-1); } - if (fdsetup[fd].copyfd>2) - if (close(fdsetup[fd].copyfd)) fsyscallerror("close real fd for %d",fd); - if (close(fdsetup[fd].pipefd)) fsyscallerror("close pipe fd for %d",fd); } + close_unwanted_pipes(); } static void server_sendconfirm(void) {