1 #include <fcntl.h>
2 #include <signal.h>
3 #include <sys/epoll.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7
8 #include <sdeventplus/event.hpp>
9 #include <sdeventplus/source/event.hpp>
10 #include <sdeventplus/source/io.hpp>
11 #include <sdeventplus/source/signal.hpp>
12
13 #include <cerrno>
14 #include <cstdio>
15 #include <cstring>
16 #include <exception>
17 #include <functional>
18
reader(const char * fifo,sdeventplus::source::IO & source,int fd,uint32_t)19 void reader(const char* fifo, sdeventplus::source::IO& source, int fd, uint32_t)
20 {
21 char buf[4096];
22 ssize_t r = read(fd, buf, sizeof(buf));
23 if (r == 0)
24 {
25 int newfd = open(fifo, O_NONBLOCK | O_RDONLY);
26 if (newfd < 0)
27 {
28 fprintf(stderr, "Failed to open %s: %s\n", fifo, strerror(errno));
29 source.get_event().exit(1);
30 return;
31 }
32 source.set_fd(newfd);
33 if (close(fd))
34 {
35 fprintf(stderr, "Failed to close fd\n");
36 source.get_event().exit(1);
37 return;
38 }
39 return;
40 }
41 if (r < 0)
42 {
43 fprintf(stderr, "Reader error: %s\n", strerror(errno));
44 source.get_event().exit(1);
45 return;
46 }
47 printf("%.*s", static_cast<int>(r), buf);
48 }
49
remover(const char * fifo,sdeventplus::source::EventBase & source)50 void remover(const char* fifo, sdeventplus::source::EventBase& source)
51 {
52 int r = unlink(fifo);
53 if (r)
54 {
55 fprintf(stderr, "Failed to remove fifo %s: %s\n", fifo,
56 strerror(errno));
57 source.get_event().exit(1);
58 }
59 }
60
clean_exit(sdeventplus::source::Signal & source,const struct signalfd_siginfo *)61 void clean_exit(sdeventplus::source::Signal& source,
62 const struct signalfd_siginfo*)
63 {
64 source.get_event().exit(0);
65 }
66
main(int argc,char * argv[])67 int main(int argc, char* argv[])
68 {
69 if (argc != 2)
70 {
71 fprintf(stderr, "Usage: %s [named pipe to create]\n", argv[0]);
72 return 1;
73 }
74 const char* fifo = argv[1];
75
76 // Block all signals before changing system state so we guarantee our clean
77 // up routines are in place
78 sigset_t signals;
79 if (sigfillset(&signals))
80 {
81 fprintf(stderr, "Failed to populate signals: %s\n", strerror(errno));
82 return 1;
83 }
84 if (sigprocmask(SIG_BLOCK, &signals, nullptr))
85 {
86 fprintf(stderr, "Failed to mask signals: %s\n", strerror(errno));
87 return 1;
88 }
89
90 if (mkfifo(fifo, 0622))
91 {
92 fprintf(stderr, "Failed to mkfifo %s: %s\n", fifo, strerror(errno));
93 return 1;
94 }
95
96 int fd = open(fifo, O_NONBLOCK | O_RDONLY);
97 if (fd < 0)
98 {
99 fprintf(stderr, "Failed to open %s: %s\n", fifo, strerror(errno));
100 return 1;
101 }
102
103 try
104 {
105 sdeventplus::Event event = sdeventplus::Event::get_default();
106 sdeventplus::source::Exit remover_source(
107 event, std::bind(remover, fifo, std::placeholders::_1));
108 sdeventplus::source::Signal sigint(event, SIGINT, clean_exit);
109 sdeventplus::source::IO reader_source(
110 event, fd, EPOLLIN,
111 std::bind(reader, fifo, std::placeholders::_1,
112 std::placeholders::_2, std::placeholders::_3));
113 return event.loop();
114 }
115 catch (const std::exception& e)
116 {
117 fprintf(stderr, "%s\n", e.what());
118 return 1;
119 }
120 }
121