@@ -110,82 +110,73 @@ int main(int argc, char **argv) {
110
110
#endif
111
111
112
112
// 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" ,
118
116
" 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" ,
124
121
" 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" ,
138
131
" 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" ,
143
135
" 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" ,
148
140
" set the timeout interval in seconds used to wait for a response. "
149
141
" When a byte timeout is set, if the elapsed time for the first byte of response is longer "
150
142
" than the given timeout, a timeout is detected. "
151
143
" When byte timeout is disabled, the full confirmation response must be received before "
152
144
" expiration of the response timeout. "
153
145
" Fractional values are possible." ,
154
- cxxopts::value<double >())
146
+ cxxopts::value<double >());
155
147
#ifdef OS_LINUX
156
- (" t,tcp-timeout" ,
148
+ options. add_options () (" t,tcp-timeout" ,
157
149
" 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" ));
159
151
#endif
160
- (" force" ,
152
+ options. add_options () (" force" ,
161
153
" Force the use of the shared memory even if it already exists. "
162
154
" Do not use this option per default! "
163
155
" 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" ,
166
158
" Use a separate shared memory for requests with the specified client id. "
167
159
" The client id (as hex value) is appended to the shared memory prefix (e.g. modbus_fc_DO)"
168
160
" . You can specify multiple client ids by separating them with ','. "
169
161
" 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" ,
172
164
" 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" ,
175
167
" 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" ,
178
170
" Force the use of the semaphore even if it already exists. "
179
171
" Do not use this option per default! "
180
172
" 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" );
189
180
190
181
// parse arguments
191
182
cxxopts::ParseResult args;
@@ -213,6 +204,7 @@ int main(int argc, char **argv) {
213
204
std::cout << " - cxxopts by jarro2783 (https://github.com/jarro2783/cxxopts)" << std::endl;
214
205
std::cout << " - libmodbus by Stéphane Raimbault (https://github.com/stephane/libmodbus)" << std::endl;
215
206
std::cout << " - cxxshm (https://github.com/NikolasK-source/cxxshm)" << std::endl;
207
+ std::cout << " - cxxsemaphore (https://github.com/NikolasK-source/cxxsemaphore)" << std::endl;
216
208
return EX_OK;
217
209
}
218
210
@@ -274,6 +266,23 @@ int main(int argc, char **argv) {
274
266
275
267
const auto FORCE_SHM = args.count (" force" ) > 0 ;
276
268
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
+
277
286
// check ulimit
278
287
std::size_t min_files =
279
288
CONNECTIONS + 5 ; // number of connections + stderr + stdout + stdin + signal_fd + server socket
@@ -303,7 +312,8 @@ int main(int argc, char **argv) {
303
312
args[" ao-registers" ].as <std::size_t >(),
304
313
args[" ai-registers" ].as <std::size_t >(),
305
314
args[" name-prefix" ].as <std::string>(),
306
- FORCE_SHM);
315
+ FORCE_SHM,
316
+ shm_permissions);
307
317
} catch (const std::system_error &e) {
308
318
std::cerr << Print_Time::iso << " ERROR: " << e.what () << std::endl;
309
319
return EX_OSERR;
@@ -325,7 +335,8 @@ int main(int argc, char **argv) {
325
335
args[" ao-registers" ].as <std::size_t >(),
326
336
args[" ai-registers" ].as <std::size_t >(),
327
337
sstr.str (),
328
- FORCE_SHM));
338
+ FORCE_SHM,
339
+ shm_permissions));
329
340
mb_mappings[i] = separate_mappings.back ()->get_mapping ();
330
341
} catch (const std::system_error &e) {
331
342
std::cerr << Print_Time::iso << " ERROR: " << e.what () << std::endl;
@@ -352,7 +363,8 @@ int main(int argc, char **argv) {
352
363
args[" ao-registers" ].as <std::size_t >(),
353
364
args[" ai-registers" ].as <std::size_t >(),
354
365
sstr.str (),
355
- FORCE_SHM));
366
+ FORCE_SHM,
367
+ shm_permissions));
356
368
mb_mappings[a] = separate_mappings.back ()->get_mapping ();
357
369
} catch (const std::system_error &e) {
358
370
std::cerr << Print_Time::iso << " ERROR: " << e.what () << std::endl;
0 commit comments