WARNING: While resolving call to function 'help' arguments were dropped!
If I compile using gcc -O3 codice -o out/codice I get this pesky warning. It finishes compiling, so I am just wondering why this is happening.
I'm on a mac on lion with xcode 4.3 installed. The compiler it is using is i686-apple-darwin11-llvm-gcc-4.2
Note that if I switch the -O3 to -O2/-O1/-O then it continues to give the same warning
The code is as follows....
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <math.h>
void help();
char *codice_encrypt(char *in);
char *codice_decrypt(char *in);
void sigint_handler(int signal) {
exit(2);
}
int main (int argc, char **argv) {
if (argc != 3) {
help();
}
signal(SIGINT, sigint_handler);
char *ret, *status;
int tmpret;
if (strcmp(argv[1], "e") == 0 || strcmp(argv[1], "encrypt") == 0) {
status = "Encrypting...\n";
tmpret = write(STDOUT_FILENO, status, strlen((const char *)status));
ret = codice_encrypt(argv[2]);
} else if (strcmp(argv[1], "d") == 0 || strcmp(argv[1], "decrypt") == 0) {
status = "Decrypting...\n";
tmpret = write(STDOUT_FILENO, status, strlen((const char *)status));
ret = codice_decrypt(argv[2]);
} else {
status = "Could not understand command line arguments O.o\n";
tmpret = write(STDOUT_FILENO, status, strlen((const char *)status));
help(STDOUT_FILENO);
}
status = "Success!\nRetval:\n\n";
tmpret = write(STDOUT_FILENO, status, strlen((const char *)status));
tmpret = write(STDOUT_FILENO, ret, strlen((const char *)ret));
tmpret = write(STDOUT_FILENO, "\n\n", 2);
return 0;
}
void help() {
int tmpret;
const char *logo = "\n\n\t\tooooooo__oo______________________\n"
"\t\t_____oo______oo_oo_oo__oo_oo_oo__\n"
"\t\t____oo___oo__ooo_oo__o_ooo_oo__o_\n"
"\t\t___o_____oo__oo__oo__o_oo__oo__o_\n"
"\t\t_oo______oo__oo__oo__o_oo__oo__o_\n"
"\t\tooooooo_oooo_oo______o_oo______o_\n"
"\t\t_________________________________\n\n\n";
tmpret = write(STDOUT_FILENO, logo, strlen(logo));
const char *help = "Help\n"
"Is\n"
"Still\n"
"Being\n"
"Written :)\n\n";
tmpret = write(STDOUT_FILENO, help, strlen(help));
exit(1);
}
char *codice_encrypt(char *in) {
unsigned int i;
char ya = 0x55;
write(STDOUT_FILENO, "0x", 2);
char itret[50];
sprintf(itret,"%#hhx",ya);
write(STDOUT_FILENO, itret, strlen(itret));
write(STDOUT_FILENO, "\n", 1);
ya = ya & 0x0F;
ya = ya >> 1;
sprintf(itret,"%#hhx",ya);
write(STDOUT_FILENO, itret, strlen(itret));
write(STDOUT_FILENO, "\n", 1);
ya = 0x55;
ya = ya & 0xF0;
ya = ya << 1;
sprintf(itret,"%#hhx",ya);
write(STDOUT_FILENO, itret, strlen(itret));
write(STDOUT_FILENO, "\n", 1);
return in;
}
char *codice_decrypt(char *in) {
return in;
}
Thanks!
Here help() has variable number of arguments (I assume we're talking about C code). However, no arguments were passed and no arguments were read. One of optimization passes realized this and issued such a warning. Defining help() as help(void) will fix the problem.
Related
I am trying to use the write protection feature of Linux's userfaultfd, but it does not appear to be enabled in my kernel even though I am using version 5.13 (write protection should be fully supported in 5.10+).
When I run
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/userfaultfd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
static int has_bit(uint64_t val, uint64_t bit) {
return (val & bit) == bit;
}
int main() {
long uffd; /* userfaultfd file descriptor */
struct uffdio_api uffdio_api;
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
errExit("userfaultfd");
uffdio_api.api = UFFD_API;
uffdio_api.features = UFFD_FEATURE_PAGEFAULT_FLAG_WP;
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
errExit("ioctl-UFFDIO_API");
printf("UFFDIO_API: %d\n", has_bit(uffdio_api.ioctls, 1UL << _UFFDIO_API));
printf("UFFDIO_REGISTER: %d\n", has_bit(uffdio_api.ioctls, 1UL << _UFFDIO_REGISTER));
printf("UFFDIO_UNREGISTER: %d\n", has_bit(uffdio_api.ioctls, 1UL << _UFFDIO_UNREGISTER));
printf("UFFDIO_WRITEPROTECT: %d\n", has_bit(uffdio_api.ioctls, 1UL << _UFFDIO_WRITEPROTECT));
printf("UFFD_FEATURE_PAGEFAULT_FLAG_WP: %d\n", has_bit(uffdio_api.features, UFFD_FEATURE_PAGEFAULT_FLAG_WP));
}
The output is
UFFDIO_API: 1
UFFDIO_REGISTER: 1
UFFDIO_UNREGISTER: 1
UFFDIO_WRITEPROTECT: 0
UFFD_FEATURE_PAGEFAULT_FLAG_WP: 1
The UFFD_FEATURE_PAGEFAULT_FLAG_WP feature is enabled, but the UFFDIO_WRITEPROTECT ioctl is marked as not supported, which is necessary to enable write protection.
What might lead to this feature being disabled, and how can I enable it?
I am using Ubuntu MATE 21.10 with Linux kernel version 5.13.0-30-generic.
EDIT:
It seems like despite the man page section on the UFFD_API ioctl (https://man7.org/linux/man-pages/man2/ioctl_userfaultfd.2.html), this might be the intended behavior for a system where write protection is enabled. However, when I run a full program that spawns a poller thread and writes to the protected memory, the poller thread does not receive any notification.
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
static int page_size;
static void* fault_handler_thread(void* arg) {
long uffd; /* userfaultfd file descriptor */
uffd = (long) arg;
/* Loop, handling incoming events on the userfaultfd
file descriptor. */
for (;;) {
/* See what poll() tells us about the userfaultfd. */
struct pollfd pollfd;
int nready;
pollfd.fd = uffd;
pollfd.events = POLLIN;
nready = poll(&pollfd, 1, -1);
if (nready == -1)
errExit("poll");
printf("\nfault_handler_thread():\n");
printf(
" poll() returns: nready = %d; "
"POLLIN = %d; POLLERR = %d\n",
nready, (pollfd.revents & POLLIN) != 0,
(pollfd.revents & POLLERR) != 0);
// received fault, exit the program
exit(EXIT_FAILURE);
}
}
int main() {
long uffd; /* userfaultfd file descriptor */
char* addr; /* Start of region handled by userfaultfd */
uint64_t len; /* Length of region handled by userfaultfd */
pthread_t thr; /* ID of thread that handles page faults */
struct uffdio_api uffdio_api;
struct uffdio_register uffdio_register;
struct uffdio_writeprotect uffdio_wp;
int s;
page_size = sysconf(_SC_PAGE_SIZE);
len = page_size;
/* Create and enable userfaultfd object. */
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
errExit("userfaultfd");
uffdio_api.api = UFFD_API;
uffdio_api.features = UFFD_FEATURE_PAGEFAULT_FLAG_WP;
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
errExit("ioctl-UFFDIO_API");
addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
errExit("mmap");
printf("Address returned by mmap() = %p\n", addr);
/* Register the memory range of the mapping we just created for
handling by the userfaultfd object. */
uffdio_register.range.start = (unsigned long) addr;
uffdio_register.range.len = len;
uffdio_register.mode = UFFDIO_REGISTER_MODE_WP;
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
errExit("ioctl-UFFDIO_REGISTER");
printf("uffdio_register.ioctls = 0x%llx\n", uffdio_register.ioctls);
printf("Have _UFFDIO_WRITEPROTECT? %s\n", (uffdio_register.ioctls & _UFFDIO_WRITEPROTECT) ? "YES" : "NO");
uffdio_wp.range.start = (unsigned long) addr;
uffdio_wp.range.len = len;
uffdio_wp.mode = UFFDIO_WRITEPROTECT_MODE_WP;
if (ioctl(uffd, UFFDIO_WRITEPROTECT, &uffdio_wp) == -1)
errExit("ioctl-UFFDIO_WRITEPROTECT");
/* Create a thread that will process the userfaultfd events. */
s = pthread_create(&thr, NULL, fault_handler_thread, (void*) uffd);
if (s != 0) {
errno = s;
errExit("pthread_create");
}
/* Main thread now touches memory in the mapping, touching
locations 1024 bytes apart. This will trigger userfaultfd
events for all pages in the region. */
usleep(100000);
size_t l;
l = 0xf; /* Ensure that faulting address is not on a page
boundary, in order to test that we correctly
handle that case in fault_handling_thread(). */
char i = 0;
while (l < len) {
printf("Write address %p in main(): ", addr + l);
addr[l] = i++;
printf("%d\n", addr[l]);
l += 1024;
usleep(100000); /* Slow things down a little */
}
exit(EXIT_SUCCESS);
}
The UFFD_API ioctl does not seem to ever report _UFFD_WRITEPROTECT as can be seen here in the kernel source code (1, 2). I assume that this is because whether this operation is supported or not depends on the kind of underlying mapping.
The feature is in fact reporeted on a per-registered-range basis. You will have to set the API with ioctl(uffd, UFFDIO_API, ...) first, then register a range with ioctl(uffd, UFFDIO_REGISTER, ...) and then check the uffdio_register.ioctls field.
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/userfaultfd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
int main(void) {
long uffd;
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
errExit("userfaultfd");
struct uffdio_api uffdio_api = { .api = UFFD_API };
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
errExit("ioctl(UFFDIO_API)");
const size_t region_sz = 0x4000;
void *region = mmap(NULL, region_sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
if (region == MAP_FAILED)
errExit("mmap");
if (posix_memalign((void **)region, sysconf(_SC_PAGESIZE), region_sz))
errExit("posix_memalign");
printf("Region mapped at %p - %p\n", region, region + region_sz);
struct uffdio_register uffdio_register = {
.range = { .start = (unsigned long)region, .len = region_sz },
.mode = UFFDIO_REGISTER_MODE_WP
};
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
errExit("ioctl(UFFDIO_REGISTER)");
printf("uffdio_register.ioctls = 0x%llx\n", uffdio_register.ioctls);
printf("Have _UFFDIO_WRITEPROTECT? %s\n", (uffdio_register.ioctls & _UFFDIO_WRITEPROTECT) ? "YES" : "NO");
if ((uffdio_register.ioctls & UFFD_API_RANGE_IOCTLS) != UFFD_API_RANGE_IOCTLS)
errExit("bad ioctl set");
struct uffdio_writeprotect wp = {
.range = { .start = (unsigned long)region, .len = region_sz },
.mode = UFFDIO_WRITEPROTECT_MODE_WP
};
if (ioctl(uffd, UFFDIO_WRITEPROTECT, &wp) == -1)
errExit("ioctl(UFFDIO_WRITEPROTECT)");
puts("ioctl(UFFDIO_WRITEPROTECT) successful.");
return EXIT_SUCCESS;
}
Output:
Region mapped at 0x7f45c48fe000 - 0x7f45c4902000
uffdio_register.ioctls = 0x5c
Have _UFFDIO_WRITEPROTECT? YES
ioctl(UFFDIO_WRITEPROTECT) successful.
I found the solution. The write-protected pages must be touched after registering but before marking them as write-protected. This is an undocumented requirement, from what I can tell.
In other words, add
for (size_t i = 0; i < len; i += page_size) {
addr[i] = 0;
}
between registering and write-protecting.
It works if I change the full example to
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
static int page_size;
static void* fault_handler_thread(void* arg) {
long uffd; /* userfaultfd file descriptor */
uffd = (long) arg;
/* Loop, handling incoming events on the userfaultfd
file descriptor. */
for (;;) {
/* See what poll() tells us about the userfaultfd. */
struct pollfd pollfd;
int nready;
pollfd.fd = uffd;
pollfd.events = POLLIN;
nready = poll(&pollfd, 1, -1);
if (nready == -1)
errExit("poll");
printf("\nfault_handler_thread():\n");
printf(
" poll() returns: nready = %d; "
"POLLIN = %d; POLLERR = %d\n",
nready, (pollfd.revents & POLLIN) != 0,
(pollfd.revents & POLLERR) != 0);
// received fault, exit the program
exit(EXIT_FAILURE);
}
}
int main() {
long uffd; /* userfaultfd file descriptor */
char* addr; /* Start of region handled by userfaultfd */
uint64_t len; /* Length of region handled by userfaultfd */
pthread_t thr; /* ID of thread that handles page faults */
struct uffdio_api uffdio_api;
struct uffdio_register uffdio_register;
struct uffdio_writeprotect uffdio_wp;
int s;
page_size = sysconf(_SC_PAGE_SIZE);
len = page_size;
/* Create and enable userfaultfd object. */
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
errExit("userfaultfd");
uffdio_api.api = UFFD_API;
uffdio_api.features = UFFD_FEATURE_PAGEFAULT_FLAG_WP;
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
errExit("ioctl-UFFDIO_API");
addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
errExit("mmap");
printf("Address returned by mmap() = %p\n", addr);
/* Register the memory range of the mapping we just created for
handling by the userfaultfd object. */
uffdio_register.range.start = (unsigned long) addr;
uffdio_register.range.len = len;
uffdio_register.mode = UFFDIO_REGISTER_MODE_WP;
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
errExit("ioctl-UFFDIO_REGISTER");
printf("uffdio_register.ioctls = 0x%llx\n", uffdio_register.ioctls);
printf("Have _UFFDIO_WRITEPROTECT? %s\n", (uffdio_register.ioctls & _UFFDIO_WRITEPROTECT) ? "YES" : "NO");
for (size_t i = 0; i < len; i += page_size) {
addr[i] = 0;
}
uffdio_wp.range.start = (unsigned long) addr;
uffdio_wp.range.len = len;
uffdio_wp.mode = UFFDIO_WRITEPROTECT_MODE_WP;
if (ioctl(uffd, UFFDIO_WRITEPROTECT, &uffdio_wp) == -1)
errExit("ioctl-UFFDIO_WRITEPROTECT");
/* Create a thread that will process the userfaultfd events. */
s = pthread_create(&thr, NULL, fault_handler_thread, (void*) uffd);
if (s != 0) {
errno = s;
errExit("pthread_create");
}
/* Main thread now touches memory in the mapping, touching
locations 1024 bytes apart. This will trigger userfaultfd
events for all pages in the region. */
usleep(100000);
size_t l;
l = 0xf; /* Ensure that faulting address is not on a page
boundary, in order to test that we correctly
handle that case in fault_handling_thread(). */
char i = 0;
while (l < len) {
printf("Write address %p in main(): ", addr + l);
addr[l] = i++;
printf("%d\n", addr[l]);
l += 1024;
usleep(100000); /* Slow things down a little */
}
exit(EXIT_SUCCESS);
}
There seem to be loads of questions about converting 'Codepoints' to utf8, but I can't find an answer anywhere to do it the other way around.
I want to run a script which will convert a string such as My📔 to MyU+1F4D4.
I have tried something like this: DECODEDSTRING=$(echo "My📔" | iconv -f utf-8 -t ASCII//TRANSLIT) but I can't seem to figure out what is needed.
Thanks in advance.
Using perl, works in any shell as long as the arguments are encoded in UTF-8:
$ perl -CA -E 'for my $arg (#ARGV) { say map { my $cp = ord; $cp > 127 ? sprintf "U+%04X", $cp : $_ } split //, $arg }' "My📔"
MyU+1F4D4
Non-ASCII codepoints are printed as U+XXXX (0-padded, more hex digits if needed), ASCII ones as human-readable letters.
Or for maximum speed, a C program that does the same:
// Compile with: gcc -o print_unicode -std=c11 -O -Wall -Wextra print_unicode.c
#include <assert.h>
#include <inttypes.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uchar.h>
#if __STDC_VERSION__ < 201112L
#error "Need C11 or newer"
#endif
#ifndef __STDC_UTF_32__
#error "Not using Unicode"
#endif
int main(int argc, char **argv) {
// arguments should be encoded according to locale's character set
setlocale(LC_CTYPE, "");
for (int i = 1; i < argc; i++) {
char *s = argv[i];
size_t len = strlen(argv[i]);
mbstate_t state;
memset(&state, 0, sizeof state);
while (len > 0) {
char32_t c;
size_t rc = mbrtoc32(&c, s, len, &state);
assert(rc != (size_t)-3);
if (rc == (size_t)-1) {
perror("mbrtoc32");
return EXIT_FAILURE;
} else if (rc == (size_t)-2) {
fprintf(stderr, "Argument %d is incomplete!\n", i);
return EXIT_FAILURE;
} else if (rc > 0) {
if (c > 127) {
printf("U+%04" PRIXLEAST32, c);
} else {
putchar((char)c);
}
s += rc;
len -= rc;
}
putchar('\n');
}
return 0;
}
$ ./print_unicode "My📔"
MyU+1F4D4
Many times I have typical ETL code that looks like this
./call_some_api.py | ./extract_transform | ./load_to_some_sql
What if either of the first two scripts stop sending bytes because of some internal error that causes them to stall. I wish there was another program I could put before ./load_to_some_sql that will detect that 0 bytes has been sent in 5 minutes, and throw an exit code.
Curl has --speed-limit and --speed-time which do exactly this, but it's not generalized for other cli apps.
Is there a way to do this? Have a way to crash if the throughput hits a certain level on a pipe?
I know state machines and other orchestration tools can do this, but in general if there's a way to do it from bash it would be helpful!
If you are interested in inactivity timeout, these can do it.
One liner (mentioned in comments). Adjust $t for inactivity seconds:
perl -e'$t=300;$SIG{ALRM}=sub{die"Timeout\n"};alarm$t;while(<>){print;alarm$t}'
More robust:
#include <sys/epoll.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
long secs = 300;
int stdin_mode, stdout_mode;
void my_exit(int code) {
fcntl(STDIN_FILENO, F_SETFL, stdin_mode);
fcntl(STDOUT_FILENO, F_SETFL, stdout_mode);
exit(code);
}
char* progname = "";
void perror_die(char* msg) {
dprintf(STDERR_FILENO, "%s: %s: %m\n", progname, msg);
my_exit(EXIT_FAILURE);
}
int check(int ret, char *msg) {
if (ret == -1) perror_die(msg);
return ret;
}
void usage() {
dprintf(STDERR_FILENO, "Usage:\n-s <secs> inactivity timeout in seconds (default: %ld seconds)\n", secs);
exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
progname = argv[0];
signal(SIGHUP, SIG_IGN);
stdin_mode = fcntl(STDIN_FILENO, F_GETFL);
stdout_mode = fcntl(STDOUT_FILENO, F_GETFL);
int opt;
while((opt = getopt(argc, argv, "s:h")) != -1)
switch(opt) {
case 's':
secs = strtol(optarg, NULL, 10);
break;
case 'h':
case '?':
usage();
};
if (optind < argc) usage();
int epfd = check(epoll_create(3), "epoll_create");
struct epoll_event ev = {
.events = EPOLLIN | EPOLLET,
.data.fd = STDIN_FILENO
};
check(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev), "epoll_ctl");
check(fcntl(STDIN_FILENO, F_SETFL, stdin_mode | O_NONBLOCK), "fcntl stdin");
ev.events = 0;
ev.data.fd = STDOUT_FILENO;
int epout = !epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev);
if (epout)
check(fcntl(STDOUT_FILENO, F_SETFL, stdout_mode | O_NONBLOCK), "fcntl stdout");
char buf[4096];
ssize_t b_read = 0, b_wrote = 0, bytes = 0;
secs *= 1000;
int epres;
while((epres = epoll_wait(epfd, &ev, 1, secs)) == 1) {
if (ev.events & EPOLLERR) {
errno = EPIPE;
break;
}
for(;;) {
if (b_read == 0) {
b_read = read(STDIN_FILENO, buf, sizeof(buf));
if (b_read > 0) bytes += b_read;
else if (b_read == -1) {
if (errno == EAGAIN) {
b_read = 0;
break;
} else perror_die("read");
} else my_exit(EXIT_SUCCESS);
}
if (b_read) {
int w = write(STDOUT_FILENO, buf + b_wrote, b_read - b_wrote);
if (w != -1) b_wrote += w;
else {
if (errno == EAGAIN && epout) {
ev.events = EPOLLOUT | EPOLLONESHOT;
ev.data.fd = STDOUT_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_MOD, STDOUT_FILENO, &ev), "epoll_ctl");
break;
} else perror_die("write");
}
if (b_wrote == b_read) b_read = b_wrote = 0;
}
}
}
if (epres) perror_die("event loop");
dprintf(STDERR_FILENO, "%s: Timeout reached\n", progname);
my_exit(EXIT_FAILURE);
}
If you are interested in measuring bytes/secs this can do it, on an interval: (calculation could be improved to keep last n secs bandwidth instead of an interval)
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
ssize_t min_bw = 1000;
long secs = 5;
int stdin_mode, stdout_mode;
void my_exit(int code) {
fcntl(STDIN_FILENO, F_SETFL, stdin_mode);
fcntl(STDOUT_FILENO, F_SETFL, stdout_mode);
exit(code);
}
char* progname = "";
void perror_die(char* msg) {
dprintf(STDERR_FILENO, "%s: %s: %m\n", progname, msg);
my_exit(EXIT_FAILURE);
}
int check(int ret, char *msg) {
if (ret == -1) perror_die(msg);
return ret;
}
void usage() {
dprintf(STDERR_FILENO, "Usage:\n-b <bytes> minimum bytes per (default: %ld bytes)\n-s <secs> seconds (default: %ld seconds)\n", min_bw, secs);
exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
progname = argv[0];
signal(SIGHUP, SIG_IGN);
stdin_mode = fcntl(STDIN_FILENO, F_GETFL);
stdout_mode = fcntl(STDOUT_FILENO, F_GETFL);
int opt;
while((opt = getopt(argc, argv, "b:s:h")) != -1)
switch(opt) {
case 'b':
min_bw = strtol(optarg, NULL, 10);
break;
case 's':
secs = strtol(optarg, NULL, 10);
break;
case 'h':
case '?':
usage();
};
if (optind < argc) usage();
int epfd = check(epoll_create(3), "epoll_create");
int tmfd = check(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK), "timerfd_create");
struct itimerspec when = {{secs, 0}, {secs, 0}};
check(timerfd_settime(tmfd, 0, &when, NULL), "timerfd_settime");
struct epoll_event ev = {
.events = EPOLLIN | EPOLLET,
.data.fd = tmfd
};
check(epoll_ctl(epfd, EPOLL_CTL_ADD, tmfd, &ev), "epoll_ctl");
ev.data.fd = STDIN_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev), "epoll_ctl");
check(fcntl(STDIN_FILENO, F_SETFL, stdin_mode | O_NONBLOCK), "fcntl stdin");
ev.events = 0;
ev.data.fd = STDOUT_FILENO;
int epout = !epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev);
if (epout)
check(fcntl(STDOUT_FILENO, F_SETFL, stdout_mode | O_NONBLOCK), "fcntl stdout");
char tmbuf[64];
char buf[4096];
ssize_t b_read = 0, b_wrote = 0, bytes = 0;
int epres;
while((epres = epoll_wait(epfd, &ev, 1, -1)) == 1) {
if (ev.events & EPOLLERR) {
errno = EPIPE;
break;
}
if (ev.data.fd == tmfd) {
if (bytes < min_bw) {
dprintf(STDERR_FILENO, "Too slow\n");
my_exit(EXIT_FAILURE);
}
check(read(tmfd, tmbuf, sizeof(tmbuf)), "read timerfd");
bytes = 0;
continue;
}
for(;;) {
if (b_read == 0) {
b_read = read(STDIN_FILENO, buf, sizeof(buf));
if (b_read > 0) bytes += b_read;
else if (b_read == -1) {
if (errno == EAGAIN) {
b_read = 0;
break;
} else perror_die("read");
} else my_exit(EXIT_SUCCESS);
}
if (b_read) {
int w = write(STDOUT_FILENO, buf + b_wrote, b_read - b_wrote);
if (w != -1) b_wrote += w;
else {
if (errno == EAGAIN && epout) {
ev.events = EPOLLOUT | EPOLLONESHOT;
ev.data.fd = STDOUT_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_MOD, STDOUT_FILENO, &ev), "epoll_ctl");
break;
} else perror_die("write");
}
if (b_wrote == b_read) b_read = b_wrote = 0;
}
}
}
perror_die("event loop");
}
Both programs are for linux only.
Provided you have a newish version of Bash, the read builtin can optionally enforce a timeout [docs], which means that it's actually not hard to write a bit of pure Bash code that does exactly what you describe:
... upstream command ... \
| {
while true ; do
read -r -N 1 -t 300 char
result=$?
if (( result > 128 )) ; then
echo 'Read timed out.' >&2
exit 1
elif (( result > 0 )) ; then
exit 0
elif [[ "$char" == '' ]] ; then
printf '\0'
else
printf %s "$char"
fi
done
} \
| ... downstream command ...
(Note: the above reads one character at a time for simplicity's sake; if you expect a high volume of data to pass through this, then you may need to adjust it for better performance.)
But even though the above does exactly what you describe, I'm not sure whether it will really accomplish your goal, because the upstream command won't actually die until it tries to write something and gets SIGPIPE. So even after the above prints Read timed out, Bash will just keep hanging indefinitely, probably until the user hits Ctrl-C. (The same goes for niry's answer, of course.) That's a bit harder to fix; I guess when your command detects a timeout, it will need to find the process-IDs of the upstream commands, and use kill to proactively send them SIGPIPE (or some other signal of your choosing)?
I'm trying to get the original destination of UDP packet using IP_ORIGDSTADDR. On older kernel that mine, it seems to work (I'm running the currently debian testing kernel, 4.7.0-1-amd64).
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define DEFAULT_ADDR "127.0.0.1"
#define DEFAULT_PORT 6666
int main(int ac, char **av)
{
int sock;
struct sockaddr_in sin;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
if (inet_aton(ac >= 2 ? av[1] : DEFAULT_ADDR, &sin.sin_addr) < 0) {
fprintf(stderr, "Invalid address\n");
goto err;
}
sin.sin_port = htons(ac >= 3 ? atoi(av[2]) : DEFAULT_PORT);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
goto err;
}
if (bind(sock, (struct sockaddr *) &sin, sizeof sin) < 0) {
perror("bind");
goto close_err;
}
#define SOCK_OPT(l, n, v) do { \
int _v = v; \
socklen_t _s; \
if (setsockopt(sock, l, n, &_v, sizeof _v) < 0) { \
perror("setsockopt "# l "/" # n); \
goto close_err; \
} \
\
_s = sizeof (_v); \
if (getsockopt(sock, l, n, &_v, &_s) < 0) { \
perror("getsockopt "# l "/" # n); \
goto close_err; \
} \
\
if (_v != v) { \
fprintf(stderr, "Unexpected sockopt (expected %d, found %d)\n", v, _v); \
goto close_err; \
} \
\
printf(#l "/" #n " is set to %d\n", _v); \
\
} while (0)
SOCK_OPT(SOL_IP, IP_RECVORIGDSTADDR, 1);
SOCK_OPT(SOL_IP, IP_RECVOPTS, 1);
SOCK_OPT(SOL_IP, IP_PKTINFO, 1);
#undef SOCK_OPT
printf("Reading on %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
for (;;) {
ssize_t n;
char buf[1024];
char tmp[80];
struct iovec iovec[] = {
{
.iov_base = buf,
.iov_len = sizeof buf - 1,
}
};
struct msghdr msghdr;
struct cmsghdr *cmsg_ptr;
struct sockaddr_storage from = { 0 };
int port;
union cmsg_data {
struct sockaddr_in sin;
struct in_pktinfo pktinfo;
};
char msg_control[CMSG_SPACE(sizeof(union cmsg_data)) * 10] = { 0 };
int found;
memset(&msghdr, 0, sizeof msghdr);
msghdr.msg_name = &from;
msghdr.msg_namelen = sizeof from;
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = sizeof iovec / sizeof iovec[0];
msghdr.msg_control = msg_control;
msghdr.msg_controllen = sizeof msg_control;
msghdr.msg_flags = MSG_EOR | MSG_TRUNC | MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE;
n = recvmsg(sock, &msghdr, MSG_OOB);
if (n < 0) {
perror("recvmsg");
continue;
}
if (buf[n - 1] == '\n')
n--;
buf[n] = 0;
switch (from.ss_family) {
default:
tmp[0] = 0;
break;
case AF_INET:
inet_ntop(AF_INET, &((struct sockaddr_in *) &from)->sin_addr, tmp, sizeof tmp);
port = htons(((struct sockaddr_in *) &from)->sin_port);
break;
case AF_INET6:
inet_ntop(AF_INET6, &((struct sockaddr_in6 *) &from)->sin6_addr, tmp, sizeof tmp);
port = htons(((struct sockaddr_in6 *) &from)->sin6_port);
break;
}
printf("%s:%d Rx %ldb: %.*s, msg_control = %zdb\n", tmp, port, n, (int) n, buf, sizeof msg_control);
found = 0;
for (cmsg_ptr = CMSG_FIRSTHDR(&msghdr); cmsg_ptr != NULL; cmsg_ptr = CMSG_NXTHDR(&msghdr, cmsg_ptr)) {
union cmsg_data *cmsg_data = (union cmsg_data *) CMSG_DATA(cmsg_ptr);
switch (cmsg_ptr->cmsg_level) {
default:
fprintf(stderr, "Unexecpted level : %d\n", cmsg_ptr->cmsg_level);
break;
case SOL_IP:
switch (cmsg_ptr->cmsg_type) {
default:
fprintf(stderr, "Unexecpted type : %d\n", cmsg_ptr->cmsg_type);
break;
case IP_ORIGDSTADDR:
printf("IP_ORIGDSTADDR: sin_addr = %s, sin_port = %d\n", inet_ntoa(cmsg_data->sin.sin_addr), htons(cmsg_data->sin.sin_port));
found++;
break;
case IP_PKTINFO:
snprintf(tmp, sizeof tmp, "%s", inet_ntoa(cmsg_data->pktinfo.ipi_spec_dst));
printf("IP_PKTINFO: ifindex = %u, spec_dst = %s, addr = %s\n", cmsg_data->pktinfo.ipi_ifindex, tmp, inet_ntoa(cmsg_data->pktinfo.ipi_addr));
break;
}
}
}
if (found != 1)
fprintf(stderr, "*** Warning: No SOL_IP / IP_ORIGDSTADDR found\n");
}
close_err:
close(sock);
err:
return 1;
}
When trying this bunch of code (eg. sending packets using netcat), I dont have any IP_ORIGDSTADDR, but only IP_PKTINFO : I need to have UDP port, only IP_ORIGDSTADDR can provide it.
Does anyone have met this strange behaviour ?
Segmentation fault: On the line where regcomp is used it is throwing segmentation fault.
I have used gdb for running the program.
I am trying:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <regex.h>
#define LINE_LENGTH 256
main()
{
char *c_char;
char *cp;
char *temp;
regex_t regex;
int reg = 0;
char f_input[] = {"path/path/.pc"};
FILE *input;
input = fopen(f_input, "r");
while (fgets(temp, LINE_LENGTH, input) != NULL)
{
temp = (char*)malloc(sizeof(char)*LINE_LENGTH);
if((cp = strstr(temp, "#define")) != NULL)
{
temp +=7;
memset(c_char, '\0', sizeof(char)*50);
c_char = strtok(temp, " ");
reg = regcomp(®ex, "^[A-Z]", 0);
reg = regexec(®ex, c_char, 0, NULL, 0);
if (reg == REG_NOMATCH)
{
fprintf("%s should be in upper case.", c_char);
}
}
}
}
After coming to the line: "reg = regcomp(®ex, "^[A-Z]", 0);" i tried to print regex value...
"p regex".
It prints:
"{buffer = 0x0, allocated = 0, used = 0, syntax = 0, fastmap = 0x0.........}"
I think the crash can be caused by this code:
memset(c_char, '\0', sizeof(char)*50);
when you program starts c_char is uninitialized:
main()
{
char *c_char;
Then in the while loop when you first call memset() 'c_char' is still uninitialized. As a result you pass an invalid pointer to memset()