@@ -110,82 +110,73 @@ int main(int argc, char **argv) {
110110#endif
111111
112112 // all command line arguments
113- // clang-format off
114- options.add_options ()(" i,host" ,
115- " host to listen for incoming connections" ,
116- cxxopts::value<std::string>()->default_value (" any" ))
117- (" p,service" ,
113+ options.add_options ()(
114+ " i,host" , " host to listen for incoming connections" , cxxopts::value<std::string>()->default_value (" any" ));
115+ options.add_options ()(" p,service" ,
118116 " service or port to listen for incoming connections" ,
119- cxxopts::value<std::string>()->default_value (" 502" ))
120- (" n,name-prefix" ,
121- " shared memory name prefix" ,
122- cxxopts::value<std::string>()->default_value (" modbus_" ))
123- (" do-registers" ,
117+ cxxopts::value<std::string>()->default_value (" 502" ));
118+ options.add_options ()(
119+ " n,name-prefix" , " shared memory name prefix" , cxxopts::value<std::string>()->default_value (" modbus_" ));
120+ options.add_options ()(" do-registers" ,
124121 " number of digital output registers" ,
125- cxxopts::value<std::size_t >()->default_value (" 65536" ))
126- (" di-registers" ,
127- " number of digital input registers" ,
128- cxxopts::value<std::size_t >()->default_value (" 65536" ))
129- (" ao-registers" ,
130- " number of analog output registers" ,
131- cxxopts::value<std::size_t >()->default_value (" 65536" ))
132- (" ai-registers" ,
133- " number of analog input registers" ,
134- cxxopts::value<std::size_t >()->default_value (" 65536" ))
135- (" m,monitor" ,
136- " output all incoming and outgoing packets to stdout" )
137- (" c,connections" ,
122+ cxxopts::value<std::size_t >()->default_value (" 65536" ));
123+ options.add_options ()(
124+ " di-registers" , " number of digital input registers" , cxxopts::value<std::size_t >()->default_value (" 65536" ));
125+ options.add_options ()(
126+ " ao-registers" , " number of analog output registers" , cxxopts::value<std::size_t >()->default_value (" 65536" ));
127+ options.add_options ()(
128+ " ai-registers" , " number of analog input registers" , cxxopts::value<std::size_t >()->default_value (" 65536" ));
129+ options.add_options ()(" m,monitor" , " output all incoming and outgoing packets to stdout" );
130+ options.add_options ()(" c,connections" ,
138131 " number of allowed simultaneous Modbus Server connections." ,
139- cxxopts::value<std::size_t >()->default_value (" 1" ))
140- (" r,reconnect" ,
141- " do not terminate if no Modbus Server is connected anymore." )
142- (" byte-timeout" ,
132+ cxxopts::value<std::size_t >()->default_value (" 1" ));
133+ options.add_options ()(" r,reconnect" , " do not terminate if no Modbus Server is connected anymore." );
134+ options.add_options ()(" byte-timeout" ,
143135 " timeout interval in seconds between two consecutive bytes of the same message. "
144- " In most cases it is sufficient to set the response timeout. "
145- " Fractional values are possible." ,
146- cxxopts::value<double >())
147- (" response-timeout" ,
136+ " In most cases it is sufficient to set the response timeout. "
137+ " Fractional values are possible." ,
138+ cxxopts::value<double >());
139+ options. add_options () (" response-timeout" ,
148140 " set the timeout interval in seconds used to wait for a response. "
149141 " When a byte timeout is set, if the elapsed time for the first byte of response is longer "
150142 " than the given timeout, a timeout is detected. "
151143 " When byte timeout is disabled, the full confirmation response must be received before "
152144 " expiration of the response timeout. "
153145 " Fractional values are possible." ,
154- cxxopts::value<double >())
146+ cxxopts::value<double >());
155147#ifdef OS_LINUX
156- (" t,tcp-timeout" ,
148+ options. add_options () (" t,tcp-timeout" ,
157149 " tcp timeout in seconds. Set to 0 to use the system defaults (not recommended)." ,
158- cxxopts::value<std::size_t >()->default_value (" 5" ))
150+ cxxopts::value<std::size_t >()->default_value (" 5" ));
159151#endif
160- (" force" ,
152+ options. add_options () (" force" ,
161153 " Force the use of the shared memory even if it already exists. "
162154 " Do not use this option per default! "
163155 " It should only be used if the shared memory of an improperly terminated instance continues "
164- " to exist as an orphan and is no longer used." )
165- (" s,separate" ,
156+ " to exist as an orphan and is no longer used." );
157+ options. add_options () (" s,separate" ,
166158 " Use a separate shared memory for requests with the specified client id. "
167159 " The client id (as hex value) is appended to the shared memory prefix (e.g. modbus_fc_DO)"
168160 " . You can specify multiple client ids by separating them with ','. "
169161 " Use --separate-all to generate separate shared memories for all possible client ids." ,
170- cxxopts::value<std::vector<std::uint8_t >>())
171- (" separate-all" ,
162+ cxxopts::value<std::vector<std::uint8_t >>());
163+ options. add_options () (" separate-all" ,
172164 " like --separate, but for all client ids (creates 1028 shared memory files! "
173- " check/set 'ulimit -n' before using this option.)" )
174- (" semaphore" ,
165+ " check/set 'ulimit -n' before using this option.)" );
166+ options. add_options () (" semaphore" ,
175167 " protect the shared memory with a named semaphore against simultaneous access" ,
176- cxxopts::value<std::string>())
177- (" semaphore-force" ,
168+ cxxopts::value<std::string>());
169+ options. add_options () (" semaphore-force" ,
178170 " Force the use of the semaphore even if it already exists. "
179171 " Do not use this option per default! "
180172 " It should only be used if the semaphore of an improperly terminated instance continues "
181- " to exist as an orphan and is no longer used." )
182- (" h,help" ,
183- " print usage" )
184- (" version" ,
185- " print version information" )
186- (" license" ,
187- " show licences" );
188- // clang-format on
173+ " to exist as an orphan and is no longer used." );
174+ options.add_options ()(" b,permissions" ,
175+ " permission bits that are applied when creating a shared memory." ,
176+ cxxopts::value<std::string>()->default_value (" 0640" ));
177+ options.add_options ()(" h,help" , " print usage" );
178+ options.add_options ()(" version" , " print version information" );
179+ options.add_options ()(" license" , " show licences" );
189180
190181 // parse arguments
191182 cxxopts::ParseResult args;
@@ -213,6 +204,7 @@ int main(int argc, char **argv) {
213204 std::cout << " - cxxopts by jarro2783 (https://github.com/jarro2783/cxxopts)" << std::endl;
214205 std::cout << " - libmodbus by Stéphane Raimbault (https://github.com/stephane/libmodbus)" << std::endl;
215206 std::cout << " - cxxshm (https://github.com/NikolasK-source/cxxshm)" << std::endl;
207+ std::cout << " - cxxsemaphore (https://github.com/NikolasK-source/cxxsemaphore)" << std::endl;
216208 return EX_OK;
217209 }
218210
@@ -274,6 +266,23 @@ int main(int argc, char **argv) {
274266
275267 const auto FORCE_SHM = args.count (" force" ) > 0 ;
276268
269+ mode_t shm_permissions = 0660 ;
270+ {
271+ const auto shm_permissions_str = args[" permissions" ].as <std::string>();
272+ bool fail = false ;
273+ std::size_t idx = 0 ;
274+ try {
275+ shm_permissions = std::stoul (shm_permissions_str, &idx, 0 );
276+ } catch (const std::exception &) { fail = true ; }
277+ fail = fail || idx != shm_permissions_str.size ();
278+
279+ if (fail || (~static_cast <mode_t >(0x1FF ) & shm_permissions) != 0 ) {
280+ std::cerr << Print_Time::iso << " ERROR: Invalid file permissions \" " << shm_permissions_str << ' "'
281+ << std::endl;
282+ return EX_USAGE;
283+ }
284+ }
285+
277286 // check ulimit
278287 std::size_t min_files =
279288 CONNECTIONS + 5 ; // number of connections + stderr + stdout + stdin + signal_fd + server socket
@@ -303,7 +312,8 @@ int main(int argc, char **argv) {
303312 args[" ao-registers" ].as <std::size_t >(),
304313 args[" ai-registers" ].as <std::size_t >(),
305314 args[" name-prefix" ].as <std::string>(),
306- FORCE_SHM);
315+ FORCE_SHM,
316+ shm_permissions);
307317 } catch (const std::system_error &e) {
308318 std::cerr << Print_Time::iso << " ERROR: " << e.what () << std::endl;
309319 return EX_OSERR;
@@ -325,7 +335,8 @@ int main(int argc, char **argv) {
325335 args[" ao-registers" ].as <std::size_t >(),
326336 args[" ai-registers" ].as <std::size_t >(),
327337 sstr.str (),
328- FORCE_SHM));
338+ FORCE_SHM,
339+ shm_permissions));
329340 mb_mappings[i] = separate_mappings.back ()->get_mapping ();
330341 } catch (const std::system_error &e) {
331342 std::cerr << Print_Time::iso << " ERROR: " << e.what () << std::endl;
@@ -352,7 +363,8 @@ int main(int argc, char **argv) {
352363 args[" ao-registers" ].as <std::size_t >(),
353364 args[" ai-registers" ].as <std::size_t >(),
354365 sstr.str (),
355- FORCE_SHM));
366+ FORCE_SHM,
367+ shm_permissions));
356368 mb_mappings[a] = separate_mappings.back ()->get_mapping ();
357369 } catch (const std::system_error &e) {
358370 std::cerr << Print_Time::iso << " ERROR: " << e.what () << std::endl;
0 commit comments