blob: 1ccfd21bd48626c250dde864e54991b2b035592a [file] [log] [blame]
Patrick Venture33569752018-03-12 18:56:14 -07001/**
2 * Copyright 2017 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Ventureb5754fd2018-09-10 13:13:58 -070017#include "lpcsnoop/snoop.hpp"
18
William A. Kennington III6dac4c52019-12-13 15:05:00 -080019#include <endian.h>
Patrick Venture33569752018-03-12 18:56:14 -070020#include <fcntl.h>
Benjamin Faire7b07f02018-07-02 09:51:37 -070021#include <getopt.h>
Patrick Ventureb5754fd2018-09-10 13:13:58 -070022#include <sys/epoll.h>
23#include <systemd/sd-event.h>
Patrick Venture33569752018-03-12 18:56:14 -070024#include <unistd.h>
25
Patrick Venture33569752018-03-12 18:56:14 -070026#include <cstdint>
Kun Yi1c16ad82018-09-12 10:01:49 -070027#include <exception>
Patrick Venture33569752018-03-12 18:56:14 -070028#include <iostream>
William A. Kennington IIIb3baa682021-12-19 20:47:05 -080029#include <optional>
Kun Yi1c16ad82018-09-12 10:01:49 -070030#include <sdeventplus/event.hpp>
31#include <sdeventplus/source/event.hpp>
32#include <sdeventplus/source/io.hpp>
William A. Kennington III6a5e0a12021-12-19 20:47:34 -080033#include <sdeventplus/source/signal.hpp>
34#include <stdplus/signal.hpp>
Patrick Venture33569752018-03-12 18:56:14 -070035#include <thread>
36
Benjamin Fairf69ad7e2018-07-13 13:41:10 -070037static size_t codeSize = 1; /* Size of each POST code in bytes */
Benjamin Faire7b07f02018-07-02 09:51:37 -070038
Benjamin Faire7b07f02018-07-02 09:51:37 -070039static void usage(const char* name)
40{
41 fprintf(stderr,
42 "Usage: %s [-d <DEVICE>]\n"
Benjamin Fairf69ad7e2018-07-13 13:41:10 -070043 " -b, --bytes <SIZE> set POST code length to <SIZE> bytes. "
44 "Default is %zu\n"
Manojkiran Edaaade4ad2021-02-19 11:20:33 +053045 " -d, --device <DEVICE> use <DEVICE> file.\n"
William A. Kennington III66efa632020-04-16 18:46:20 -070046 " -v, --verbose Prints verbose information while running\n\n",
Manojkiran Edaaade4ad2021-02-19 11:20:33 +053047 name, codeSize);
Benjamin Fairf69ad7e2018-07-13 13:41:10 -070048}
49
Patrick Venture33569752018-03-12 18:56:14 -070050/*
Kun Yieb312312018-06-13 09:20:50 -070051 * Callback handling IO event from the POST code fd. i.e. there is new
52 * POST code available to read.
53 */
Kun Yicce09622020-04-06 14:01:55 -070054void PostCodeEventHandler(sdeventplus::source::IO& s, int postFd, uint32_t,
55 PostReporter* reporter, bool verbose)
Kun Yieb312312018-06-13 09:20:50 -070056{
William A. Kennington III6dac4c52019-12-13 15:05:00 -080057 uint64_t code = 0;
William A. Kennington III0f964b42020-04-16 18:46:03 -070058 ssize_t readb;
59 while ((readb = read(postFd, &code, codeSize)) > 0)
Kun Yi1c16ad82018-09-12 10:01:49 -070060 {
William A. Kennington IIIf21475a2019-12-13 17:21:24 -080061 code = le64toh(code);
William A. Kennington III66efa632020-04-16 18:46:20 -070062 if (verbose)
63 {
64 fprintf(stderr, "Code: 0x%" PRIx64 "\n", code);
65 }
William A. Kennington IIIf21475a2019-12-13 17:21:24 -080066 // HACK: Always send property changed signal even for the same code
67 // since we are single threaded, external users will never see the
68 // first value.
Manojkiran Edaba5258f2021-02-25 13:23:33 +053069 reporter->value(std::make_tuple(~code, secondary_post_code_t{}), true);
70 reporter->value(std::make_tuple(code, secondary_post_code_t{}));
William A. Kennington III0f964b42020-04-16 18:46:03 -070071
72 // read depends on old data being cleared since it doens't always read
73 // the full code size
74 code = 0;
Kun Yi1c16ad82018-09-12 10:01:49 -070075 }
William A. Kennington III0f964b42020-04-16 18:46:03 -070076
77 if (readb < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
78 {
79 return;
80 }
81
82 /* Read failure. */
83 if (readb == 0)
84 {
85 fprintf(stderr, "Unexpected EOF reading postcode\n");
86 }
87 else
88 {
89 fprintf(stderr, "Failed to read postcode: %s\n", strerror(errno));
90 }
91 s.get_event().exit(1);
Kun Yieb312312018-06-13 09:20:50 -070092}
93
94/*
Patrick Venture33569752018-03-12 18:56:14 -070095 * TODO(venture): this only listens one of the possible snoop ports, but
96 * doesn't share the namespace.
97 *
98 * This polls() the lpc snoop character device and it owns the dbus object
99 * whose value is the latest port 80h value.
100 */
101int main(int argc, char* argv[])
102{
103 int rc = 0;
Benjamin Faire7b07f02018-07-02 09:51:37 -0700104 int opt;
Patrick Venture33569752018-03-12 18:56:14 -0700105 int postFd = -1;
Patrick Venture33569752018-03-12 18:56:14 -0700106
107 /*
108 * These string constants are only used in this method within this object
109 * and this object is the only object feeding into the final binary.
110 *
111 * If however, another object is added to this binary it would be proper
112 * to move these declarations to be global and extern to the other object.
113 */
114 const char* snoopObject = SNOOP_OBJECTPATH;
115 const char* snoopDbus = SNOOP_BUSNAME;
Benjamin Faire7b07f02018-07-02 09:51:37 -0700116
Patrick Venture33569752018-03-12 18:56:14 -0700117 bool deferSignals = true;
William A. Kennington III66efa632020-04-16 18:46:20 -0700118 bool verbose = false;
Patrick Venture33569752018-03-12 18:56:14 -0700119
Patrick Venture1ceb21b2018-08-08 11:29:36 -0700120 // clang-format off
Benjamin Faire7b07f02018-07-02 09:51:37 -0700121 static const struct option long_options[] = {
Patrick Venture1ceb21b2018-08-08 11:29:36 -0700122 {"bytes", required_argument, NULL, 'b'},
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530123 {"device", optional_argument, NULL, 'd'},
William A. Kennington III66efa632020-04-16 18:46:20 -0700124 {"verbose", no_argument, NULL, 'v'},
Patrick Venture1ceb21b2018-08-08 11:29:36 -0700125 {0, 0, 0, 0}
126 };
127 // clang-format on
Benjamin Faire7b07f02018-07-02 09:51:37 -0700128
William A. Kennington III66efa632020-04-16 18:46:20 -0700129 while ((opt = getopt_long(argc, argv, "b:d:v", long_options, NULL)) != -1)
Benjamin Faire7b07f02018-07-02 09:51:37 -0700130 {
131 switch (opt)
132 {
133 case 0:
134 break;
Benjamin Fairf69ad7e2018-07-13 13:41:10 -0700135 case 'b':
136 codeSize = atoi(optarg);
137
138 if (codeSize < 1 || codeSize > 8)
139 {
140 fprintf(stderr,
141 "Invalid POST code size '%s'. Must be "
142 "an integer from 1 to 8.\n",
143 optarg);
144 exit(EXIT_FAILURE);
145 }
146 break;
Benjamin Faire7b07f02018-07-02 09:51:37 -0700147 case 'd':
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530148 postFd = open(optarg, O_NONBLOCK);
149 if (postFd < 0)
150 {
151 fprintf(stderr, "Unable to open: %s\n", optarg);
152 return -1;
153 }
154
Benjamin Faire7b07f02018-07-02 09:51:37 -0700155 break;
William A. Kennington III66efa632020-04-16 18:46:20 -0700156 case 'v':
157 verbose = true;
158 break;
Benjamin Faire7b07f02018-07-02 09:51:37 -0700159 default:
160 usage(argv[0]);
161 exit(EXIT_FAILURE);
162 }
163 }
164
Patrick Venture33569752018-03-12 18:56:14 -0700165 auto bus = sdbusplus::bus::new_default();
166
167 // Add systemd object manager.
Willy Tua396c852021-12-09 22:23:14 -0800168 sdbusplus::server::manager::manager snoopdManager(bus, snoopObject);
Patrick Venture33569752018-03-12 18:56:14 -0700169
170 PostReporter reporter(bus, snoopObject, deferSignals);
Kun Yieb312312018-06-13 09:20:50 -0700171 reporter.emit_object_added();
172 bus.request_name(snoopDbus);
Kun Yieb312312018-06-13 09:20:50 -0700173
Kun Yi1c16ad82018-09-12 10:01:49 -0700174 // Create sdevent and add IO source
175 try
176 {
William A. Kennington IIIb3baa682021-12-19 20:47:05 -0800177 auto event = sdeventplus::Event::get_default();
178 std::optional<sdeventplus::source::IO> reporterSource;
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530179 if (postFd > 0)
180 {
William A. Kennington IIIb3baa682021-12-19 20:47:05 -0800181 reporterSource.emplace(
Manojkiran Edaaade4ad2021-02-19 11:20:33 +0530182 event, postFd, EPOLLIN | EPOLLET,
183 std::bind(PostCodeEventHandler, std::placeholders::_1,
184 std::placeholders::_2, std::placeholders::_3,
185 &reporter, verbose));
186 }
Kun Yi1c16ad82018-09-12 10:01:49 -0700187 // Enable bus to handle incoming IO and bus events
188 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
William A. Kennington III6a5e0a12021-12-19 20:47:34 -0800189 auto intCb = [](sdeventplus::source::Signal& source,
190 const struct signalfd_siginfo*) {
191 source.get_event().exit(0);
192 };
193 stdplus::signal::block(SIGINT);
194 sdeventplus::source::Signal(event, SIGINT, intCb).set_floating(true);
195 stdplus::signal::block(SIGTERM);
196 sdeventplus::source::Signal(event, SIGTERM, std::move(intCb))
197 .set_floating(true);
Kun Yi1c16ad82018-09-12 10:01:49 -0700198 rc = event.loop();
199 }
200 catch (const std::exception& e)
201 {
202 fprintf(stderr, "%s\n", e.what());
203 }
Kun Yieb312312018-06-13 09:20:50 -0700204
Patrick Venture33569752018-03-12 18:56:14 -0700205 if (postFd > -1)
206 {
207 close(postFd);
208 }
209
Patrick Venture33569752018-03-12 18:56:14 -0700210 return rc;
211}