mirror of
https://repo.or.cz/socat.git
synced 2025-07-08 13:36:32 +00:00
Socat option -r,-R path specifications allow use of variables
This commit is contained in:
parent
9faf068949
commit
2af6089436
9 changed files with 378 additions and 65 deletions
205
sysutils.c
205
sysutils.c
|
@ -941,3 +941,208 @@ double Strtod(const char *nptr, char **endptr, const char *txt) {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* This function gets a string with possible references to environment
|
||||
variables and expands them. Variables must be prefixed with '$' and their
|
||||
names consist only of A-Z, a-z, 0-9, and '_'.
|
||||
The name may be enclosed with { }.
|
||||
To pass a literal "$" us "\$".
|
||||
There are special variables supported whose values do not comr from
|
||||
environment:
|
||||
$$ expands to the process's pid
|
||||
$PROGNAME expands to the executables basename or the value of option -lp
|
||||
$TIMESTAMP expands to the actual time in format %Y%m%dT%H%M%S
|
||||
$MICROS expands to the actual microseconds (decimal)
|
||||
The dst output is a copy of src but with the variables expanded.
|
||||
Returns 0 on success;
|
||||
returns -1 when the output buffer was too short (overflow);
|
||||
returns 1 on syntax error.
|
||||
*/
|
||||
int expandenv(
|
||||
char *dst, /* prealloc'd output buff, will be \0 termd */
|
||||
const char *src, /* input string to generate expansion from */
|
||||
size_t n, /* length of dst */
|
||||
struct timeval *tv) /* in/out timestamp for sync */
|
||||
{
|
||||
char c; /* char currently being lex'd/parsed */
|
||||
bool esc = false; /* just got '\' */
|
||||
bool bra = false; /* within ${ } */
|
||||
char *nam = NULL; /* points to temp.allocated rw copy of src */
|
||||
const char *e; /* pointer to isolated var name in tmp[] */
|
||||
size_t s=0, d=0; /* counters in src, dst */
|
||||
size_t v; /* variable name begin */
|
||||
bool ofl = false; /* dst overflow, output truncated */
|
||||
char tmp[18]; /* buffer for timestamp, micros */
|
||||
|
||||
while (c = src[s++]) {
|
||||
if (esc) {
|
||||
if (c == '\0') {
|
||||
if (d+2 > n) { ofl = true; break; }
|
||||
dst[d++] = '\\';
|
||||
dst[d++] = c;
|
||||
break;
|
||||
}
|
||||
if (c != '$') {
|
||||
if (d+3 > n) { ofl = true; break; }
|
||||
dst[d++] = '\\';
|
||||
} else {
|
||||
if (d+2 > n) { ofl = true; break; }
|
||||
}
|
||||
dst[d++] = c;
|
||||
esc = false;
|
||||
continue;
|
||||
}
|
||||
if (c == '\0') {
|
||||
dst[d++] = c;
|
||||
break;
|
||||
}
|
||||
if (c == '\\') {
|
||||
esc = true;
|
||||
continue;
|
||||
}
|
||||
if (c != '$') {
|
||||
if (d+2 > n) { ofl = true; break; }
|
||||
dst[d++] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* c == '$': Expecting env var to expand */
|
||||
c = src[s];
|
||||
if (c == '\0') {
|
||||
if (d+2 > n) { ofl = true; break; }
|
||||
++s;
|
||||
dst[d++] = '$';
|
||||
break;
|
||||
}
|
||||
if (c == '$') {
|
||||
int wr;
|
||||
/* Special case: pid */
|
||||
++s;
|
||||
wr = snprintf(&dst[d], n-d, F_pid, getpid());
|
||||
if (wr >= n-d || wr < 0) { ofl = true; break; }
|
||||
d += wr;
|
||||
continue;
|
||||
}
|
||||
if (c == '{') {
|
||||
++s;
|
||||
bra = true;
|
||||
}
|
||||
if (!isalpha(c) && c != '_') {
|
||||
/* Special case no var name, just keep '$' */
|
||||
if (d+3 > n) { ofl = true; break; }
|
||||
++s;
|
||||
dst[d++] = '$';
|
||||
dst[d++] = c;
|
||||
continue;
|
||||
}
|
||||
v = 0; /* seems we found valid variable name */
|
||||
if (nam == NULL) {
|
||||
nam = strdup(src+s);
|
||||
if (nam == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while (c = src[s]) {
|
||||
if (!isalnum(c) && c != '_') {
|
||||
break;
|
||||
}
|
||||
nam[v++] = c;
|
||||
++s;
|
||||
}
|
||||
if (bra && c != '}') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
nam[v] = '\0';
|
||||
/* Var name is complete */
|
||||
/* Check hardcoded var names */
|
||||
if (strcmp(nam, "PROGNAME") == 0) {
|
||||
e = diag_get_string('p');
|
||||
} else if (strcmp(nam, "TIMESTAMP") == 0) {
|
||||
if (tv->tv_sec == 0) {
|
||||
gettimeofday(tv, NULL);
|
||||
}
|
||||
struct tm tm;
|
||||
localtime_r(&tv->tv_sec, &tm);
|
||||
strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S", &tm);
|
||||
e = tmp;
|
||||
} else if (strcmp(nam, "MICROS") == 0) {
|
||||
if (tv->tv_sec == 0) {
|
||||
gettimeofday(tv, NULL);
|
||||
}
|
||||
sprintf(tmp, F_tv_usec, tv->tv_usec);
|
||||
e = tmp;
|
||||
} else {
|
||||
e = getenv(nam);
|
||||
}
|
||||
if (e == NULL) {
|
||||
/* Var not found, skip it */
|
||||
continue;
|
||||
}
|
||||
/* Var found, copy it to output buffer */
|
||||
if (d+strlen(e)+1 > n) { ofl = true; break; }
|
||||
strcpy(&dst[d], e);
|
||||
d += strlen(&dst[d]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nam != NULL) {
|
||||
free(nam);
|
||||
}
|
||||
|
||||
if (ofl) {
|
||||
dst[d] = '\0';
|
||||
return -1;
|
||||
}
|
||||
dst[d] = '\0';
|
||||
if (src[s-1] != '\0') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xio_opensnifffile(
|
||||
const char *a,
|
||||
struct timeval *tv)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int flags;
|
||||
int rc;
|
||||
int fd;
|
||||
|
||||
rc = expandenv(path, a, sizeof(path), tv);
|
||||
if (rc < 0) {
|
||||
Error2("expandenv(source=\"%s\", n="F_Zu"): Out of memory", a, sizeof(path));
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
} else if (rc > 0) {
|
||||
Error1("expandenv(source=\"%s\"): Syntax error", a);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
flags = O_CREAT|O_WRONLY|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
O_CLOEXEC|
|
||||
#endif
|
||||
O_NONBLOCK;
|
||||
if ((fd = Open(path, flags, 0664)) < 0) {
|
||||
if (errno == ENXIO) {
|
||||
/* try to open pipe rdwr */
|
||||
if ((fd = Open(path, flags, 0664)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef O_CLOEXEC
|
||||
if (Fcntl_l(fd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", fd, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue