1 /*
2 OWFS -- One-Wire filesystem
3 OWHTTPD -- One-Wire Web Server
4 Written 2003 Paul H Alfille
5 email: paul.alfille@gmail.com
6 Released under the GPL
7 See the header file: ow.h for full attribution
8 1wire/iButton system from Dallas Semiconductor
9 */
10
11 // regex
12
13 #include <config.h>
14 #include "owfs_config.h"
15 #include "ow_devices.h"
16 #include "ow_counters.h"
17 #include "ow_connection.h"
18 #include "ow_dirblob.h"
19 #include "ow.h"
20 #include "ow_external.h"
21
22 static enum search_status PossiblyLockedBusCall( enum search_status (* first_next)(struct device_search *, const struct parsedname *), struct device_search * ds, const struct parsedname * pn ) ;
23
24 static ZERO_OR_ERROR FS_dir_both(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_directory, uint32_t * flags);
25 static ZERO_OR_ERROR FS_dir_all_connections(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_directory, uint32_t * flags);
26 static ZERO_OR_ERROR FS_devdir(void (*dirfunc) (void *, const struct parsedname * const), void *v, const struct parsedname *pn2);
27 static ZERO_OR_ERROR FS_structdevdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_device_directory);
28 static ZERO_OR_ERROR FS_alarmdir(void (*dirfunc) (void *, const struct parsedname * const), void *v, const struct parsedname *pn2);
29 static ZERO_OR_ERROR FS_typedir(void (*dirfunc) (void *, const struct parsedname * const), void *v, const struct parsedname *pn_type_directory);
30 static ZERO_OR_ERROR FS_realdir(void (*dirfunc) (void *, const struct parsedname * const), void *v, const struct parsedname *pn2, uint32_t * flags);
31 static ZERO_OR_ERROR FS_cache_or_real(void (*dirfunc) (void *, const struct parsedname * const), void *v, const struct parsedname *pn2, uint32_t * flags);
32 static ZERO_OR_ERROR FS_busdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_directory);
33
34 static void FS_stype_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory);
35 static ZERO_OR_ERROR FS_externaldir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_external_directory);
36 static void FS_interface_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory);
37 static void FS_alarm_entry(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory);
38 static void FS_simultaneous_entry(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory);
39 static void FS_uncached_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory);
40 static ZERO_OR_ERROR FS_dir_plus(void (*dirfunc) (void *, const struct parsedname *), void *v, uint32_t * flags, const struct parsedname *pn_directory, const char *file) ;
41
42 /* Calls dirfunc() for each element in directory */
43 /* void * data is arbitrary user data passed along -- e.g. output file descriptor */
44 /* pn_directory -- input:
45 pn_directory->selected_device == NO_DEVICE -- root directory, give list of all devices
46 pn_directory->selected_device non-null, -- device directory, give all properties
47 branch aware
48 cache aware
49
50 pn_directory -- output (with each call to dirfunc)
51 ROOT
52 pn_directory->selected_device set
53 pn_directory->sn set appropriately
54 pn_directory->selected_filetype not set
55
56 DEVICE
57 pn_directory->selected_device and pn_directory->sn still set
58 pn_directory->selected_filetype loops through
59 */
60
61 /* FS_dir produces the "invariant" portion of the directory, passing on to
62 FS_dir_all_connections the variable part */
FS_dir(void (* dirfunc)(void *,const struct parsedname *),void * v,struct parsedname * pn_directory)63 ZERO_OR_ERROR FS_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, struct parsedname *pn_directory)
64 {
65 /* applies 'dirfunc' to each directory element of pn_directory */
66 /* void * v is extra information passed along */
67
68 uint32_t flags;
69 LEVEL_DEBUG("path=%s", pn_directory->path);
70 pn_directory->control_flags |= ALIAS_REQUEST ; // All local directory queries want alias translation
71
72 return FS_dir_both(dirfunc, v, pn_directory, &flags);
73 }
74
75 /* path is the path which "pn_directory" parses */
76 /* FS_dir_remote is the entry into FS_dir_all_connections from ServerDir */
77 /* More checking is done, and the flags are returned */
FS_dir_remote(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_directory,uint32_t * flags)78 ZERO_OR_ERROR FS_dir_remote(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_directory, uint32_t * flags)
79 {
80 LEVEL_DEBUG("path=%s", pn_directory->path);
81 return FS_dir_both(dirfunc, v, pn_directory, flags);
82 }
83
84
FS_dir_both(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_raw_directory,uint32_t * flags)85 static ZERO_OR_ERROR FS_dir_both(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_raw_directory, uint32_t * flags)
86 {
87 ZERO_OR_ERROR ret = 0;
88
89 /* initialize flags */
90 flags[0] = 0;
91
92 /* pn_raw_directory->selected_connection Could be NULL here...
93 * It will then return a root-directory containing
94 * /uncached,/settings,/system,/statistics,/structure
95 * instead of an empty directory.
96 */
97 if (pn_raw_directory == NO_PARSEDNAME) {
98 LEVEL_CALL("return ENODEV pn_raw_directory=%p selected_connection=%p",
99 pn_raw_directory,
100 (pn_raw_directory ? pn_raw_directory->selected_connection : NO_CONNECTION));
101 return -ENODEV;
102 }
103
104 LEVEL_CALL("path=%s", SAFESTRING(pn_raw_directory->path));
105
106 STATLOCK;
107 AVERAGE_IN(&dir_avg);
108 AVERAGE_IN(&all_avg);
109 STATUNLOCK;
110
111 FSTATLOCK;
112 StateInfo.dir_time = NOW_TIME; // protected by mutex
113 FSTATUNLOCK;
114
115 if (pn_raw_directory->selected_filetype != NO_FILETYPE) {
116 // File, not directory
117 ret = -ENOTDIR;
118
119 } else if (SpecifiedVeryRemoteBus(pn_raw_directory)) {
120 //printf("SPECIFIED_BUS BUS_IS_SERVER (very remote)\n");
121 // Send remotely only (all evaluation done there)
122 ret = ServerDir(dirfunc, v, pn_raw_directory, flags);
123
124 } else if (SpecifiedRemoteBus(pn_raw_directory)) {
125 //printf("SPECIFIED_BUS BUS_IS_SERVER (just remote)\n");
126 //printf("Add extra INTERFACE\n");
127 FS_interface_dir(dirfunc, v, pn_raw_directory);
128 // Send remotely only (all evaluation done there)
129 ret = ServerDir(dirfunc, v, pn_raw_directory, flags);
130
131 } else if (pn_raw_directory->selected_device != NO_DEVICE) {
132 //printf("YES SELECTED_DEVICE\n");
133 // device directory -- not bus-specific
134 if ( IsInterfaceDir(pn_raw_directory) ) {
135 ret = FS_devdir(dirfunc, v, pn_raw_directory);
136 } else if ( BusIsServer( pn_raw_directory->selected_connection) ) {
137 ret = ServerDir(dirfunc, v, pn_raw_directory, flags);
138 } else if ( IsStructureDir( pn_raw_directory ) ) {
139 ret = FS_structdevdir( dirfunc, v, pn_raw_directory ) ;
140 } else {
141 ret = FS_devdir(dirfunc, v, pn_raw_directory);
142 }
143
144 } else if (NotRealDir(pn_raw_directory)) {
145 //printf("NOT_REAL_DIR\n");
146 // structure, statistics, system or settings dir -- not bus-specific
147 ret = FS_typedir(dirfunc, v, pn_raw_directory);
148
149 } else if (SpecifiedLocalBus(pn_raw_directory)) {
150 if (IsAlarmDir(pn_raw_directory)) { /* root or branch directory -- alarm state */
151 ret = FS_alarmdir(dirfunc, v, pn_raw_directory);
152 } else {
153 if (pn_raw_directory->ds2409_depth == 0) {
154 // only add funny directories for non-micro hub (DS2409) branches
155 FS_interface_dir(dirfunc, v, pn_raw_directory);
156 }
157 /* Now get the actual devices */
158 ret = FS_cache_or_real(dirfunc, v, pn_raw_directory, flags);
159 /* simultaneous directory */
160 if (flags[0] & (DEV_temp | DEV_volt)) {
161 FS_simultaneous_entry(dirfunc, v, pn_raw_directory);
162 }
163 if (flags[0] & DEV_alarm) {
164 FS_alarm_entry(dirfunc, v, pn_raw_directory);
165 }
166 }
167
168 } else if ( IsAlarmDir(pn_raw_directory)) { // alarm for all busses
169 // Not specified bus, so scan through all and print union
170 ret = FS_dir_all_connections(dirfunc, v, pn_raw_directory, flags);
171 // add no chaff to alarm directory -- no "uncached", "bus.x" etc
172 } else { // standard directory search -- all busses
173 // Not specified bus, so scan through all and print union
174 int server_type = Globals.program_type==program_type_server || Globals.program_type==program_type_external ;
175 ret = FS_dir_all_connections(dirfunc, v, pn_raw_directory, flags);
176 if ( !server_type || ShouldReturnBusList(pn_raw_directory)) {
177 if (pn_raw_directory->ds2409_depth == 0) {
178 // only add funny directories for non-micro hub (DS2409) branches
179 FS_busdir(dirfunc, v, pn_raw_directory);
180 FS_uncached_dir(dirfunc, v, pn_raw_directory);
181 FS_stype_dir(dirfunc, v, pn_raw_directory);
182 }
183 /* simultaneous directory */
184 if (flags[0] & (DEV_temp | DEV_volt)) {
185 FS_simultaneous_entry(dirfunc, v, pn_raw_directory);
186 }
187 if (flags[0] & DEV_alarm) {
188 FS_alarm_entry(dirfunc, v, pn_raw_directory);
189 }
190 }
191
192 }
193
194 STATLOCK;
195 AVERAGE_OUT(&dir_avg);
196 AVERAGE_OUT(&all_avg);
197 STATUNLOCK;
198
199 LEVEL_DEBUG("ret=%d", ret);
200 return ret;
201 }
202
203 /* directories about the internal pogram state and configuration rather than device data */
FS_stype_dir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_root_directory)204 static void FS_stype_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory)
205 {
206 uint32_t ignoreflag = 0;
207 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, ePN_name[ePN_settings]);
208 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, ePN_name[ePN_system]);
209 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, ePN_name[ePN_statistics]);
210 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, ePN_name[ePN_structure]);
211 }
212
213 /* interface (only for bus directories) -- actually generated by the layer ABOVE that bus. */
FS_interface_dir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_root_directory)214 static void FS_interface_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory)
215 {
216 uint32_t ignoreflag = 0;
217 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, ePN_name[ePN_interface]);
218 }
219
220 /* Some devices have a special state when certain events are found called the ALARM state */
FS_alarm_entry(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_root_directory)221 static void FS_alarm_entry(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory)
222 {
223 uint32_t ignoreflag = 0 ;
224 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, "alarm");
225 }
226
227 /* Add the "uncached" directory as a mnenomic aid to top level directory listings. */
FS_uncached_dir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_root_directory)228 static void FS_uncached_dir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory)
229 {
230 uint32_t ignoreflag = 0 ;
231
232 if (IsUncachedDir(pn_root_directory)) { /* already uncached */
233 return;
234 }
235
236 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, "uncached");
237 }
238
239 /* Some temperature and voltage measurements can be triggered globally for considerable speed improvements */
FS_simultaneous_entry(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_root_directory)240 static void FS_simultaneous_entry(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_root_directory)
241 {
242 uint32_t ignoreflag = 0 ;
243 FS_dir_plus(dirfunc, v, &ignoreflag, pn_root_directory, "simultaneous");
244 }
245
246 /* path is the path which "pn_directory" parses */
247 /* FS_dir_all_connections produces the data that can vary: device lists, etc. */
248
249 struct dir_all_connections_struct {
250 struct port_in * pin ;
251 struct connection_in * cin ;
252 struct parsedname pn_directory;
253 void (*dirfunc) (void *, const struct parsedname *);
254 void *v;
255 uint32_t flags;
256 ZERO_OR_ERROR ret;
257 };
258
259 /* Embedded function */
260 /* Directory on a particular port's channel */
FS_dir_all_connections_callback_conn(struct dir_all_connections_struct * dacs)261 static void FS_dir_all_connections_callback_conn( struct dir_all_connections_struct * dacs )
262 {
263 if ( dacs->cin == NO_CONNECTION ) {
264 return ;
265 }
266
267 SetKnownBus(dacs->cin->index, &(dacs->pn_directory) );
268
269 if ( BAD(TestConnection( &(dacs->pn_directory) )) ) { // reconnect ok?
270 dacs->ret = -ECONNABORTED;
271 } else if (BusIsServer(dacs->pn_directory.selected_connection)) { /* is this a remote bus? */
272 //printf("FS_dir_all_connections: Call ServerDir %s\n", dacs->pn_directory->path);
273 dacs->ret = ServerDir(dacs->dirfunc, dacs->v, &(dacs->pn_directory), &(dacs->flags));
274 } else if (IsAlarmDir( &(dacs->pn_directory) ) ) { /* root or branch directory -- alarm state */
275 //printf("FS_dir_all_connections: Call FS_alarmdir %s\n", dacs->pn_directory->path);
276 dacs->ret = FS_alarmdir(dacs->dirfunc, dacs->v, &(dacs->pn_directory) );
277 } else {
278 dacs->ret = FS_cache_or_real(dacs->dirfunc, dacs->v, &(dacs->pn_directory), &(dacs->flags));
279 }
280
281 // next channel
282 dacs->cin = dacs->cin->next ;
283 FS_dir_all_connections_callback_conn( dacs ) ;
284 }
285
286 /* Callback (thread) once per port */
287 /* Will need to probe each connection (channel) on this port */
FS_dir_all_connections_callback_port(void * v)288 static void *FS_dir_all_connections_callback_port(void *v)
289 {
290 struct dir_all_connections_struct *dacs = v;
291 struct dir_all_connections_struct dacs_next ;
292 pthread_t thread;
293 int threadbad = 0;
294
295 if ( dacs->pin == NULL ) {
296 return VOID_RETURN;
297 }
298
299 // set up structure
300 dacs_next.pin = dacs->pin->next ;
301
302 if ( dacs_next.pin == NULL ) {
303 threadbad = 1 ;
304 } else {
305 dacs_next.dirfunc = dacs->dirfunc ;
306 memcpy( &(dacs_next.pn_directory), &(dacs->pn_directory), sizeof(struct parsedname)); // shallow copy
307 dacs_next.v = dacs->v ;
308 dacs_next.flags = dacs->flags ;
309 dacs_next.ret = dacs->ret ;
310 threadbad = pthread_create(&thread, DEFAULT_THREAD_ATTR, FS_dir_all_connections_callback_port, (void *) (&dacs_next));
311 }
312
313 // First channel
314 dacs->cin = dacs->pin->first ;
315 FS_dir_all_connections_callback_conn( v ) ;
316
317 //printf("FS_dir_all_connections4 pid=%ld adapter=%d ret=%d\n",pthread_self(), dacs->pn_directory->selected_connection->index,ret);
318 /* See if next bus was also queried */
319 if (threadbad == 0) { /* was a thread created? */
320 if (pthread_join(thread, NULL)!= 0) {
321 return VOID_RETURN ; /* cannot join, so return only this result */
322 }
323 if (dacs_next.ret >= 0) {
324 dacs->ret = dacs_next.ret; /* is it an error return? Then return this one */
325 } else {
326 dacs->flags |= dacs_next.flags ;
327 }
328 }
329 return VOID_RETURN;
330 }
331
332 static ZERO_OR_ERROR
FS_dir_all_connections(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_directory,uint32_t * flags)333 FS_dir_all_connections(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_directory, uint32_t * flags)
334 {
335 struct dir_all_connections_struct dacs ;
336
337 // set up structure
338 dacs.pin = Inbound_Control.head_port ;
339 dacs.dirfunc = dirfunc ;
340 memcpy( &(dacs.pn_directory), pn_directory, sizeof(struct parsedname)); // shallow copy
341 dacs.v = v ;
342 dacs.flags = 0 ;
343 dacs.ret = 0 ;
344
345 // Start iterating through buses
346 FS_dir_all_connections_callback_port( (void *) (& dacs) ) ;
347
348 *flags = dacs.flags ;
349 return dacs.ret ;
350 }
351
352 /* Device directory (i.e. show the properties) -- all from memory */
353 /* Respect the Visibility status and also show only the correct subdir level */
FS_devdir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_device_directory)354 static ZERO_OR_ERROR FS_devdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_device_directory)
355 {
356 struct device * dev = pn_device_directory->selected_device ;
357 struct filetype *lastft = &(dev->filetype_array[dev->count_of_filetypes]); /* last filetype struct */
358 struct filetype *ft_pointer; /* first filetype struct */
359 char subdir_name[OW_FULLNAME_MAX + 1];
360 size_t subdir_len;
361 uint32_t ignoreflag = 0;
362
363 STAT_ADD1(dir_dev.calls);
364
365 // Add subdir to name (SubDirectory is within a device, but an extra layer of grouping of properties)
366 if (pn_device_directory->subdir == NO_SUBDIR) {
367 // not sub directory
368 subdir_name[0] = '\0' ;
369 subdir_len = 0;
370 ft_pointer = dev->filetype_array;
371 } else {
372 // device subdirectory -- so use the sorted list to find all entries with the same prefix
373 strncpy(subdir_name, pn_device_directory->subdir->name, OW_FULLNAME_MAX);
374 strcat(subdir_name, "/");
375 subdir_len = strlen(subdir_name);
376 ft_pointer = pn_device_directory->subdir + 1; // next element (first one truly in the subdir)
377 }
378
379 for (; ft_pointer < lastft; ++ft_pointer) { /* loop through filetypes */
380 char *namepart ;
381
382 /* test that start of name matches directory name */
383 if (strncmp(ft_pointer->name, subdir_name, subdir_len) != 0) {
384 // end of subdir
385 break;
386 }
387
388 namepart = &ft_pointer->name[subdir_len]; // point after subdir name
389 if ( strchr( namepart, '/') != NULL) {
390 // subdir elements (and we're not in this subdir!)
391 continue;
392 }
393
394 if (ft_pointer->ag==NON_AGGREGATE) {
395 FS_dir_plus(dirfunc, v, &ignoreflag, pn_device_directory, namepart);
396 STAT_ADD1(dir_dev.entries);
397 } else if (ft_pointer->ag->combined==ag_sparse) {
398 struct parsedname s_pn_file_entry;
399 struct parsedname *pn_file_entry = &s_pn_file_entry;
400
401
402 if (ft_pointer->ag->letters==ag_letters) {
403 if (FS_ParsedNamePlusText(pn_device_directory->path, namepart, "xxx", pn_file_entry) == 0) {
404 pn_file_entry->extension = EXTENSION_UNKNOWN ; // unspecified (for owhttpd)
405 switch ( FS_visible(pn_file_entry) ) { // hide hidden properties
406 case visible_now :
407 case visible_always:
408 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
409 STAT_ADD1(dir_dev.entries);
410 break ;
411 default:
412 break ;
413 }
414 FS_ParsedName_destroy(pn_file_entry);
415 }
416 } else {
417 if (FS_ParsedNamePlusText(pn_device_directory->path, namepart, "000", pn_file_entry) == 0) {
418 pn_file_entry->extension = EXTENSION_UNKNOWN ; // unspecified (for owhttpd)
419 switch ( FS_visible(pn_file_entry) ) { // hide hidden properties
420 case visible_now :
421 case visible_always:
422 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
423 STAT_ADD1(dir_dev.entries);
424 break ;
425 default:
426 break ;
427 }
428 FS_ParsedName_destroy(pn_file_entry);
429 }
430 }
431 } else {
432 int extension;
433 int first_extension = (ft_pointer->format == ft_bitfield) ? EXTENSION_BYTE : EXTENSION_ALL;
434 struct parsedname s_pn_file_entry;
435 struct parsedname *pn_file_entry = &s_pn_file_entry;
436 for (extension = first_extension; extension < ft_pointer->ag->elements; ++extension) {
437 if (FS_ParsedNamePlusExt(pn_device_directory->path, namepart, extension, ft_pointer->ag->letters, pn_file_entry) == 0) {
438 switch ( FS_visible(pn_file_entry) ) { // hide hidden properties
439 case visible_now :
440 case visible_always:
441 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
442 STAT_ADD1(dir_dev.entries);
443 break ;
444 default:
445 break ;
446 }
447 FS_ParsedName_destroy(pn_file_entry);
448 }
449 }
450 }
451 }
452 return 0;
453 }
454
455 /* Device directory -- all from memory -- for structure */
FS_structdevdir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_device_directory)456 static ZERO_OR_ERROR FS_structdevdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_device_directory)
457 {
458 struct filetype *lastft = &(pn_device_directory->selected_device->filetype_array[pn_device_directory->selected_device->count_of_filetypes]); /* last filetype struct */
459 struct filetype *ft_pointer; /* first filetype struct */
460 char subdir_name[OW_FULLNAME_MAX + 1];
461 size_t subdir_len;
462
463 // Add subdir to name (SubDirectory is within a device, but an extra layer of grouping of properties)
464 if (pn_device_directory->subdir == NO_SUBDIR) {
465 // not sub directory
466 subdir_name[0] = '\0' ;
467 subdir_len = 0;
468 ft_pointer = pn_device_directory->selected_device->filetype_array;
469 } else {
470 // device subdirectory -- so use the sorted list to find all entries with the same prefix
471 strncpy(subdir_name, pn_device_directory->subdir->name, OW_FULLNAME_MAX);
472 strcat(subdir_name, "/");
473 subdir_len = strlen(subdir_name);
474 ft_pointer = pn_device_directory->subdir + 1; // next element (first one truly in the subdir)
475 }
476
477
478 for (; ft_pointer < lastft; ++ft_pointer) { /* loop through filetypes */
479 char *namepart ;
480
481 if ( ft_pointer->visible == INVISIBLE ) { // hide always invisible
482 // done without actually calling the visibility function since
483 // the device is generic for structure listings and may not
484 // be an actual device.
485 continue ;
486 }
487
488 /* test that start of name matches directory name */
489 if (strncmp(ft_pointer->name, subdir_name, subdir_len) != 0) {
490 // end of subdir
491 break;
492 }
493
494 namepart = &ft_pointer->name[subdir_len]; // point after subdir name
495 if ( strchr( namepart, '/') != NULL) {
496 // subdir elements (and we're not in this subdir!)
497 continue;
498 }
499
500 if (ft_pointer->ag==NON_AGGREGATE) {
501 struct parsedname s_pn_file_entry;
502 struct parsedname *pn_file_entry = &s_pn_file_entry;
503 if (FS_ParsedNamePlus(pn_device_directory->path, namepart, pn_file_entry) == 0) {
504 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
505 FS_ParsedName_destroy(pn_file_entry);
506 }
507 } else if (ft_pointer->ag->combined==ag_sparse) {
508 // Aggregate property
509 struct parsedname s_pn_file_entry;
510 struct parsedname *pn_file_entry = &s_pn_file_entry;
511
512 if ( ft_pointer->ag->letters == ag_letters ) {
513 if (FS_ParsedNamePlusText(pn_device_directory->path, namepart, "xxx", pn_file_entry) == 0) {
514 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
515 FS_ParsedName_destroy(pn_file_entry);
516 }
517 } else {
518 if (FS_ParsedNamePlusText(pn_device_directory->path, namepart, "000", pn_file_entry) == 0) {
519 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
520 FS_ParsedName_destroy(pn_file_entry);
521 }
522 }
523 } else {
524 // Aggregate property
525 struct parsedname s_pn_file_entry;
526 struct parsedname *pn_file_entry = &s_pn_file_entry;
527
528 if ( ft_pointer->format == ft_bitfield ) {
529 if (FS_ParsedNamePlusExt(pn_device_directory->path, namepart, EXTENSION_BYTE, ft_pointer->ag->letters, pn_file_entry) == 0) {
530 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
531 FS_ParsedName_destroy(pn_file_entry);
532 }
533 }
534 if (FS_ParsedNamePlusExt(pn_device_directory->path, namepart, EXTENSION_ALL, ft_pointer->ag->letters, pn_file_entry) == 0) {
535 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
536 FS_ParsedName_destroy(pn_file_entry);
537 }
538 // unlike real directory, only show the first array element since the data is redundant
539 if (FS_ParsedNamePlusExt(pn_device_directory->path, namepart, 0, ft_pointer->ag->letters, pn_file_entry) == 0) {
540 FS_dir_entry_aliased( dirfunc, v, pn_file_entry) ;
541 FS_ParsedName_destroy(pn_file_entry);
542 }
543 }
544 }
545 return 0;
546 }
547
548 /* Note -- alarm directory is smaller, no adapters or stats or uncached */
FS_alarmdir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_alarm_directory)549 static ZERO_OR_ERROR FS_alarmdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_alarm_directory)
550 {
551 enum search_status ret;
552 struct device_search ds; // holds search state
553 uint32_t ignoreflag = 0;
554
555 /* Special handling for External directory -- no alarm */
556 if ( get_busmode(pn_alarm_directory->selected_connection) == bus_external ) {
557 return 0 ;
558 }
559
560 /* cache from Server if this is a remote bus */
561 if (BusIsServer(pn_alarm_directory->selected_connection)) {
562 return ServerDir(dirfunc, v, pn_alarm_directory, &ignoreflag);
563 }
564
565 /* Certain buses are not real bus masters (like usb-monitor and w1-monitor) */
566 if ( pn_alarm_directory->selected_connection->iroutines.flags & ADAP_FLAG_sham ) {
567 return 0 ;
568 }
569
570 /* STATISCTICS */
571 STAT_ADD1(dir_main.calls);
572
573 ret = PossiblyLockedBusCall( BUS_first_alarm, &ds, pn_alarm_directory) ;
574
575 while ( ret == search_good ) {
576 char dev[PROPERTY_LENGTH_ALIAS + 1];
577 STAT_ADD1(dir_main.entries);
578 FS_devicename(dev, PROPERTY_LENGTH_ALIAS, ds.sn, pn_alarm_directory);
579 FS_dir_plus(dirfunc, v, &ignoreflag, pn_alarm_directory, dev);
580
581 ret = PossiblyLockedBusCall( BUS_next, &ds, pn_alarm_directory) ;
582 }
583
584 switch ( ret ) {
585 case search_good:
586 // include fo completeness -- can't actually be a value.
587 case search_done:
588 return 0 ;
589 case search_error:
590 default:
591 return -EIO;
592 }
593 }
594
PossiblyLockedBusCall(enum search_status (* first_next)(struct device_search *,const struct parsedname *),struct device_search * ds,const struct parsedname * pn)595 static enum search_status PossiblyLockedBusCall( enum search_status (* first_next)(struct device_search *, const struct parsedname *), struct device_search * ds, const struct parsedname * pn )
596 {
597 enum search_status ret;
598
599 // This is also called from the reconnection routine -- we use a flag to avoid mutex doubling and deadlock
600 if ( NotReconnect(pn) ) {
601 BUSLOCK(pn);
602 ret = first_next(ds, pn) ;
603 BUSUNLOCK(pn);
604 } else {
605 ret = first_next(ds, pn) ;
606 }
607 return ret ;
608 }
609
610 /* A directory of devices -- either main or branch */
611 /* not within a device, nor alarm state */
612 /* Also, adapters and stats handled elsewhere */
613 /* Scan the directory from the BUS and add to cache */
FS_realdir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_whole_directory,uint32_t * flags)614 static ZERO_OR_ERROR FS_realdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_whole_directory, uint32_t * flags)
615 {
616 struct device_search ds;
617 size_t devices = 0;
618 struct dirblob db;
619 enum search_status ret;
620
621 /* cache from Server if this is a remote bus */
622 if (BusIsServer(pn_whole_directory->selected_connection)) {
623 return ServerDir(dirfunc, v, pn_whole_directory, flags);
624 }
625
626 /* Certain buses are not real bus masters (like usb-monitor and w1-monitor) */
627 if ( pn_whole_directory->selected_connection->iroutines.flags & ADAP_FLAG_sham ) {
628 return 0 ;
629 }
630
631 /* STATISTICS */
632 STAT_ADD1(dir_main.calls);
633
634 DirblobInit(&db); // set up a fresh dirblob
635
636 ret = PossiblyLockedBusCall( BUS_first, &ds, pn_whole_directory) ;
637
638 if (RootNotBranch(pn_whole_directory)) {
639 db.allocated = pn_whole_directory->selected_connection->last_root_devs; // root dir estimated length
640 }
641 while ( ret == search_good ) {
642 char dev[PROPERTY_LENGTH_ALIAS + 1];
643
644 /* Add to device cache */
645 Cache_Add_Device(pn_whole_directory->selected_connection->index,ds.sn) ;
646
647 /* Get proper device name (including alias subst) */
648 FS_devicename(dev, PROPERTY_LENGTH_ALIAS, ds.sn, pn_whole_directory);
649
650 /* Execute callback function */
651 if ( FS_dir_plus(dirfunc, v, flags, pn_whole_directory, dev) != 0 ) {
652 DirblobPoison(&db);
653 break ;
654 }
655 DirblobAdd(ds.sn, &db);
656 ++devices;
657
658 ret = PossiblyLockedBusCall( BUS_next, &ds, pn_whole_directory) ;
659 }
660
661 STATLOCK;
662 dir_main.entries += devices;
663 STATUNLOCK;
664
665 switch ( ret ) {
666 case search_done:
667 if ( RootNotBranch(pn_whole_directory) ) {
668 pn_whole_directory->selected_connection->last_root_devs = devices; // root dir estimated length
669 }
670 /* Add to the cache (full list as a single element */
671 if (DirblobPure(&db) && (ret == search_done) ) {
672 Cache_Add_Dir(&db, pn_whole_directory);
673 }
674 DirblobClear(&db);
675 return 0 ;
676 case search_good:
677 case search_error:
678 default:
679 DirblobClear(&db);
680 return -EIO ;
681 }
682 }
683
684 /* points "serial number" to directory
685 -- 0 for root
686 -- DS2409/main|aux for branch
687 -- DS2409 needs only the last element since each DS2409 is unique
688 */
FS_LoadDirectoryOnly(struct parsedname * pn_directory,const struct parsedname * pn_original)689 void FS_LoadDirectoryOnly(struct parsedname *pn_directory, const struct parsedname *pn_original)
690 {
691 memmove( pn_directory, pn_original, sizeof(struct parsedname)) ; // shallow copy
692 if (RootNotBranch(pn_directory)) {
693 memset(pn_directory->sn, 0, SERIAL_NUMBER_SIZE);
694 } else {
695 // Stuff the branch into the checksum slot
696 // Makes the branch address unique (DS2409 id + branch)
697 --pn_directory->ds2409_depth;
698 memcpy(pn_directory->sn, pn_directory->bp[pn_directory->ds2409_depth].sn, SERIAL_NUMBER_SIZE-1);
699 pn_directory->sn[SERIAL_NUMBER_SIZE-1] = pn_directory->bp[pn_directory->ds2409_depth].branch;
700 }
701 pn_directory->selected_device = NO_DEVICE;
702 }
703
704 /* A directory of devices -- either main or branch */
705 /* not within a device, nor alarm state */
706 /* Also, adapters and stats handled elsewhere */
707 /* Cache2Real try the cache first, else get directory from bus (and add to cache) */
FS_cache_or_real(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_real_directory,uint32_t * flags)708 static ZERO_OR_ERROR FS_cache_or_real(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_real_directory, uint32_t * flags)
709 {
710 size_t dindex;
711 struct dirblob db;
712 BYTE sn[SERIAL_NUMBER_SIZE];
713
714 /* Special handling for External directory -- just walk tree */
715 if ( get_busmode(pn_real_directory->selected_connection) == bus_external ) {
716 return FS_externaldir(dirfunc, v, pn_real_directory) ;
717 }
718
719 /* Test to see whether we should get the directory "directly" */
720 if (
721 SpecifiedBus(pn_real_directory)
722 || IsUncachedDir(pn_real_directory) // asking for uncached
723 || BAD( Cache_Get_Dir(&db, pn_real_directory)) // cache'd version isn't available (or old)
724 ) {
725 // directly
726 return FS_realdir(dirfunc, v, pn_real_directory, flags);
727 }
728
729 // Use cached version of directory
730
731 /* STATISTICS */
732 STAT_ADD1(dir_main.calls);
733
734 /* Get directory from the cache */
735 for (dindex = 0; DirblobGet(dindex, sn, &db) == 0; ++dindex) {
736 char dev[PROPERTY_LENGTH_ALIAS + 1];
737
738 FS_devicename(dev, PROPERTY_LENGTH_ALIAS, sn, pn_real_directory);
739 FS_dir_plus(dirfunc, v, flags, pn_real_directory, dev);
740 }
741 DirblobClear(&db); /* allocated in Cache_Get_Dir */
742
743 STATLOCK;
744
745 dir_main.entries += dindex;
746
747 STATUNLOCK;
748 return 0;
749 }
750
751 // must lock a global struct for walking through tree -- limitation of "twalk"
752 // struct for walking through tree -- cannot send data except globally
753 struct {
754 void (*dirfunc) (void *, const struct parsedname *);
755 void *v;
756 struct parsedname *pn_directory;
757 } typedir_action_struct;
758
Typediraction(const void * t,const VISIT which,const int depth)759 static void Typediraction(const void *t, const VISIT which, const int depth)
760 {
761 uint32_t ignoreflag = 0;
762 (void) depth;
763 switch (which) {
764 case leaf:
765 case postorder:
766 FS_dir_plus(typedir_action_struct.dirfunc, typedir_action_struct.v, &ignoreflag, typedir_action_struct.pn_directory,
767 ((const struct device_opaque *) t)->key->family_code);
768 default:
769 break;
770 }
771 }
772
773 /* Show the pn_directory->type (statistics, system, ...) entries */
774 /* Only the top levels, the rest will be shown by FS_devdir */
FS_typedir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_type_directory)775 static ZERO_OR_ERROR FS_typedir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_type_directory)
776 {
777 struct parsedname s_pn_type_device;
778 struct parsedname *pn_type_device = &s_pn_type_device;
779
780
781 memcpy(pn_type_device, pn_type_directory, sizeof(struct parsedname)); // shallow copy
782
783 LEVEL_DEBUG("called on %s", pn_type_directory->path);
784
785 TYPEDIRLOCK;
786
787 typedir_action_struct.dirfunc = dirfunc;
788 typedir_action_struct.v = v;
789 typedir_action_struct.pn_directory = pn_type_device;
790 twalk(Tree[pn_type_directory->type], Typediraction);
791
792 // Ignore dangling pointer warning of s_pn_type_device; typedir_action_struct not used outside of this fn
793 TYPEDIRUNLOCK;
794
795 return 0;
796 }
797
798 // must lock a global struct for walking through tree -- limitation of "twalk"
799 // struct for walking through tree -- cannot send data except globally
800 struct {
801 void (*dirfunc) (void *, const struct parsedname *);
802 void *v;
803 struct parsedname *pn_directory;
804 } externaldir_action_struct;
805
Externaldiraction(const void * nodep,const VISIT which,const int depth)806 static void Externaldiraction(const void *nodep, const VISIT which, const int depth)
807 {
808 const struct sensor_node *p = *(struct sensor_node * const *) nodep;
809 uint32_t ignoreflag = 0;
810 (void) depth;
811
812 switch (which) {
813 case leaf:
814 case postorder:
815 FS_dir_plus(externaldir_action_struct.dirfunc, externaldir_action_struct.v, &ignoreflag, externaldir_action_struct.pn_directory,p->name);
816 default:
817 break;
818 }
819 }
820
821 /* Show the external entries */
822 /* Only the sensors */
FS_externaldir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_external_directory)823 static ZERO_OR_ERROR FS_externaldir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_external_directory)
824 {
825 struct parsedname s_pn_external_device;
826 struct parsedname *pn_external_device = &s_pn_external_device;
827
828
829 memcpy(pn_external_device, pn_external_directory, sizeof(struct parsedname)); // shallow copy
830
831 LEVEL_DEBUG("called on %s", pn_external_directory->path);
832
833 EXTERNALDIRLOCK;
834
835 externaldir_action_struct.dirfunc = dirfunc;
836 externaldir_action_struct.v = v;
837 externaldir_action_struct.pn_directory = pn_external_device;
838 twalk( sensor_tree, Externaldiraction);
839 // Ignore dangling pointer warning of s_pn_external_device; externaldir_action_struct not used outside of this fn
840
841 EXTERNALDIRUNLOCK;
842
843 return 0;
844 }
845
846 /* Show the bus entries */
FS_busdir(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn_directory)847 static ZERO_OR_ERROR FS_busdir(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn_directory)
848 {
849 char bus[OW_FULLNAME_MAX];
850 struct port_in * pin ;
851 uint32_t ignoreflag = 0 ;
852
853 if (!RootNotBranch(pn_directory)) {
854 return 0;
855 }
856
857 for ( pin = Inbound_Control.head_port ; pin != NULL ; pin = pin->next ) {
858 struct connection_in * cin ;
859 for ( cin = pin->first ; cin != NO_CONNECTION ; cin = cin->next ) {
860 UCLIBCLOCK;
861 snprintf(bus, OW_FULLNAME_MAX, "bus.%d", cin->index);
862 UCLIBCUNLOCK;
863 FS_dir_plus(dirfunc, v, &ignoreflag, pn_directory, bus);
864 }
865 }
866
867 return 0;
868 }
869
870 /* Parse and show */
FS_dir_plus(void (* dirfunc)(void *,const struct parsedname *),void * v,uint32_t * flags,const struct parsedname * pn_directory,const char * file)871 static ZERO_OR_ERROR FS_dir_plus(void (*dirfunc) (void *, const struct parsedname *), void *v, uint32_t * flags, const struct parsedname *pn_directory, const char *file)
872 {
873 struct parsedname s_pn_plus_directory;
874 struct parsedname *pn_plus_directory = &s_pn_plus_directory;
875
876 if (FS_ParsedNamePlus(pn_directory->path, file, pn_plus_directory) == 0) {
877 switch ( FS_visible(pn_plus_directory) ) { // hide hidden properties
878 case visible_now :
879 case visible_always:
880 FS_dir_entry_aliased( dirfunc, v, pn_plus_directory) ;
881 if ( pn_plus_directory->selected_device ){
882 flags[0] |= pn_plus_directory->selected_device->flags;
883 }
884 break ;
885 default:
886 break ;
887 }
888 FS_ParsedName_destroy(pn_plus_directory) ;
889 return 0;
890 }
891 return -ENOENT;
892 }
893