/* Used for virtual directories like settings and statistics * If local, applies to all local (this program) and not a * specific local bus. * If remote, pass it on for the remote to handle * */ static enum parse_enum set_type( enum ePN_type epntype, struct parsedname * pn ) { if (SpecifiedLocalBus(pn)) { return parse_error; } else if ( ! SpecifiedRemoteBus(pn) ) { pn->type |= ePS_busanylocal; } pn->type = epntype; return parse_nonreal; }
/* We've reached a /bus.n entry */ static enum parse_enum Parse_Bus( INDEX_OR_ERROR bus_number, struct parsedname *pn) { static regex_t rx_p_bus ; struct ow_regmatch orm ; ow_regcomp( &rx_p_bus, "^/bus\\.[[:digit:]]+/?", REG_ICASE ) ; orm.number = 0 ; /* Processing for bus.X directories -- eventually will make this more generic */ if ( INDEX_NOT_VALID(bus_number) ) { return parse_error; } /* Should make a presence check on remote buses here, but * it's not a major problem if people use bad paths since * they will just end up with empty directory listings. */ if (SpecifiedLocalBus(pn)) { /* already specified a "bus." */ /* too many levels of bus for a non-remote adapter */ return parse_error; } else if (SpecifiedRemoteBus(pn)) { /* already specified a "bus." */ /* Let the remote bus do the heavy lifting */ pn->state |= ePS_busveryremote; return parse_first; } /* Since we are going to use a specific in-device now, set * pn->selected_connection to point at that device at once. */ if ( SetKnownBus(bus_number, pn) ) { return parse_error ; // bus doesn't exist } pn->state |= BusIsServer((pn)->selected_connection) ? ePS_busremote : ePS_buslocal ; if (SpecifiedLocalBus(pn)) { /* don't return bus-list for local paths. */ pn->control_flags &= (~SHOULD_RETURN_BUS_LIST); } /* Create the path without the "bus.x" part in pn->path_to_server */ if ( ow_regexec( &rx_p_bus, pn->path, &orm ) == 0 ) { strcpy( pn->path_to_server, orm.pre[0] ) ; strcat( pn->path_to_server, "/" ) ; strcat( pn->path_to_server, orm.post[0] ) ; ow_regexec_free( &orm ) ; } return parse_first; }
// This function should return number of bytes read... not status. // Works for all the virtual directories, like statistics, interface, ... // Doesn't need three-peat and bus was already set or not needed. static SIZE_OR_ERROR FS_r_virtual(struct one_wire_query *owq) { struct parsedname *pn = PN(owq); SIZE_OR_ERROR read_status = 0; if (SpecifiedRemoteBus(pn)) { /* The bus is not local... use a network connection instead */ // Read afar -- returns already formatted in buffer read_status = ServerRead(owq); LEVEL_DEBUG("back from server"); Debug_OWQ(owq); } else { /* local bus -- any special locking needs? */ STAT_ADD1(read_calls); /* statistics */ switch (pn->type) { case ePN_structure: read_status = FS_structure(owq); break; case ePN_interface: BUSLOCK(pn); read_status = FS_r_local(owq); // this returns status BUSUNLOCK(pn); break; case ePN_statistics: // reading /statistics/read/tries.ALL // will cause a deadlock since it calls STAT_ADD1(read_array); // Should perhaps create a new mutex for this. // Comment out this STATLOCK until it's solved. // STATLOCK now done at time of actual read in ow_stats.c read_status = FS_r_local(owq); // this returns status break; default: read_status = FS_r_local(owq); // this returns status } if (read_status >= 0) { // local success -- now format in buffer read_status = OWQ_parse_output(owq); // this returns nr. bytes } } LEVEL_DEBUG("return %d", read_status); return read_status; }
/* Parse off starting "mode" directory (uncached, alarm...) */ static ZERO_OR_ERROR FS_ParsedName_anywhere(const char *path, enum parse_pass remote_status, struct parsedname *pn) { struct parsedname_pointers s_pp; struct parsedname_pointers *pp = &s_pp; ZERO_OR_ERROR parse_error_status = 0; enum parse_enum pe = parse_first; // To make the debug output useful it's cleared here. // Even on normal glibc, errno isn't cleared on good system calls errno = 0; LEVEL_CALL("path=[%s]", SAFESTRING(path)); RETURN_CODE_ERROR_RETURN( FS_ParsedName_setup(pp, path, pn) ); if (path == NO_PATH) { RETURN_CODE_RETURN( 0 ) ; // success (by default) } while (1) { // Check for extreme conditions (done, error) switch (pe) { case parse_done: // the only exit! //LEVEL_DEBUG("PARSENAME parse_done") ; //printf("PARSENAME end parse_error_status=%d\n",parse_error_status) ; if (parse_error_status) { FS_ParsedName_destroy(pn); return parse_error_status ; } if ( pp->pathnext != NULL ) { // extra text -- make this an error RETURN_CODE_SET_SCALAR( parse_error_status, 77 ) ; // extra text in path pe = parse_done; continue; } //printf("%s: Parse %s before corrections: %.4X -- state = %d\n",(back_from_remote)?"BACK":"FORE",pn->path,pn->state,pn->type) ; // Play with remote levels switch ( pn->type ) { case ePN_interface: // /interface is interesting -- it's actually a property of the calling server if ( SpecifiedVeryRemoteBus(pn) ) { // veryremote -> remote pn->state &= ~ePS_busveryremote ; } else if ( SpecifiedRemoteBus(pn) ) { // remote -> local pn->state &= ~ePS_busremote ; pn->state |= ePS_buslocal ; } break ; case ePN_root: // root buses are considered "real" pn->type = ePN_real; // default state break ; default: // everything else gets promoted so directories aren't added on if ( SpecifiedRemoteBus(pn) ) { // very remote pn->state |= ePS_busveryremote; } break ; } //printf("%s: Parse %s after corrections: %.4X -- state = %d\n\n",(back_from_remote)?"BACK":"FORE",pn->path,pn->state,pn->type) ; // set up detail debugging Detail_Test( pn ) ; // turns on debug mode only during this device's query return 0; case parse_error: RETURN_CODE_SET_SCALAR( parse_error_status, 27 ) ; // bad path syntax pe = parse_done; continue; default: break; } // break out next name in path if ( pp->pathnext == NULL ) { // make sure pp->pathnext isn't NULL. (SIGSEGV in uClibc) pp->pathnow = NULL ; } else { pp->pathnow = strsep(&(pp->pathnext), "/") ; } //LEVEL_DEBUG("PARSENAME pathnow=[%s] rest=[%s]",pp->pathnow,pp->pathnext) ; // test next path segment for existence if (pp->pathnow == NULL || pp->pathnow[0] == '\0') { // done parsing pe = parse_done; } // rest of state machine on parsename switch (pe) { case parse_done: // nothing left to process -- will be handled in next loop pass break ; case parse_first: //LEVEL_DEBUG("PARSENAME parse_first") ; pe = Parse_Unspecified(pp->pathnow, remote_status, pn); break; case parse_real: //LEVEL_DEBUG("PARSENAME parse_real") ; pe = Parse_Real(pp->pathnow, remote_status, pn); break; case parse_branch: //LEVEL_DEBUG("PARSENAME parse_branch") ; pe = Parse_Branch(pp->pathnow, remote_status, pn); break; case parse_nonreal: //LEVEL_DEBUG("PARSENAME parse_nonreal\n") ; pe = Parse_NonReal(pp->pathnow, pn); break; case parse_prop: //LEVEL_DEBUG("PARSENAME parse_prop") ; pn->dirlength = pp->pathnow - pp->pathcpy + 1 ; //LEVEL_DEBUG("Dirlength=%d <%*s>",pn->dirlength,pn->dirlength,pn->path) ; //printf("dirlength = %d which makes the path <%s> <%.*s>\n",pn->dirlength,pn->path,pn->dirlength,pn->path); pp->pathlast = pp->pathnow; /* Save for concatination if subdirectory later wanted */ pe = Parse_Property(pp->pathnow, pn); break; case parse_subprop: //LEVEL_DEBUG("PARSENAME parse_subprop") ; pp->pathnow[-1] = '/'; pe = Parse_Property(pp->pathlast, pn); break; default: pe = parse_error; // unknown state break; } //printf("PARSENAME pe=%d\n",pe) ; } }