Esempio n. 1
0
// This function should return number of bytes read... not status.
static SIZE_OR_ERROR FS_r_given_bus(struct one_wire_query *owq)
{
	// Device locking occurs here
	struct parsedname *pn = PN(owq);
	SIZE_OR_ERROR read_or_error = 0;

	LEVEL_DEBUG("About to read <%s> extension=%d size=%d offset=%d",SAFESTRING(pn->path),(int) pn->extension,(int) OWQ_size(owq),(int) OWQ_offset(owq));

	if (KnownBus(pn) && BusIsServer(pn->selected_connection)) {
		/* The bus is not local... use a network connection instead */
		LEVEL_DEBUG("pid=%ld call ServerRead", pthread_self());

		// Read afar -- returns already formatted in buffer
		read_or_error = ServerRead(owq);
		LEVEL_DEBUG("back from server");
		//printf("FS_r_given_bus pid=%ld r=%d\n",pthread_self(), read_or_error);
	} else {
		STAT_ADD1(read_calls);	/* statistics */
		if (DeviceLockGet(pn) == 0) {
			read_or_error = FS_r_local(owq);	// this returns status
			DeviceLockRelease(pn);
			LEVEL_DEBUG("return=%d", read_or_error);
			if (read_or_error >= 0) {
				// local success -- now format in buffer
				read_or_error = OWQ_parse_output(owq);	// this returns nr. bytes
			}
		} else {
			LEVEL_DEBUG("Cannot lock bus to perform read") ;
			read_or_error = -EADDRINUSE;
		}
	}
	LEVEL_DEBUG("After read is performed (bytes or error %d)", read_or_error);
	Debug_OWQ(owq);
	return read_or_error;
}
Esempio n. 2
0
/* Write now that connection is set */
static ZERO_OR_ERROR FS_w_given_bus(struct one_wire_query *owq)
{
	struct parsedname *pn = PN(owq);

	if ( BAD(TestConnection(pn)) ) {
		return -ECONNABORTED;
	} else if (KnownBus(pn) && BusIsServer(pn->selected_connection)) {
		return ServerWrite(owq);
	} else if (OWQ_pn(owq).type == ePN_real) {
		ZERO_OR_ERROR write_or_error = DeviceLockGet(pn);
		if (write_or_error == 0) {
			write_or_error = FS_w_local(owq);
			DeviceLockRelease(pn);
		} else {
			LEVEL_DEBUG("Cannot lock device for writing") ;
		}
		return write_or_error ;
	} else if ( IsInterfaceDir(pn) ) {
		ZERO_OR_ERROR write_or_error;
		BUSLOCK(pn);
		write_or_error = FS_w_local(owq);
		BUSUNLOCK(pn);
		return write_or_error ;
	} else {
		return FS_w_local(owq);
	}
}
Esempio n. 3
0
/* Read real device (Non-virtual). Will repeat 3 times if needed */
static SIZE_OR_ERROR FS_read_real(struct one_wire_query *owq)
{
	struct parsedname *pn = PN(owq);
	SIZE_OR_ERROR read_or_error;

	/* First try */
	/* in and bus_nr already set */
	read_or_error = FS_read_distribute(owq);

	/* Second Try */
	/* if not a specified bus, relook for chip location */
	if (read_or_error < 0) {	//error
		STAT_ADD1(read_tries[1]);
		if (SpecifiedBus(pn)) {	// this bus or bust!
			if ( BAD(TestConnection(pn)) ) {
				read_or_error = -ECONNABORTED;
			} else {
				read_or_error = FS_read_distribute(owq);	// 2nd try
				if (read_or_error < 0) {	// third try
					STAT_ADD1(read_tries[2]);
					read_or_error = FS_read_distribute(owq);
				}
			}
		} else if (BusIsServer(pn->selected_connection)) {
			int bus_nr = pn->selected_connection->index ; // current selected bus
			INDEX_OR_ERROR busloc_or_error = ReCheckPresence(pn) ;
			// special handling or remote
			// only repeat if the bus number is wrong
			// because the remote does the rereads
			if ( bus_nr != busloc_or_error ) {
				if (busloc_or_error < 0) {
					read_or_error = -ENOENT;
				} else {
					read_or_error = FS_read_distribute(owq);
					if (read_or_error < 0) {	// third try
						STAT_ADD1(read_tries[2]);
						read_or_error = FS_read_distribute(owq);
					}
				}
			}
		} else {
			INDEX_OR_ERROR busloc_or_error = ReCheckPresence(pn);	// search again
			if (busloc_or_error < 0) {
				read_or_error = -ENOENT;
			} else {
				read_or_error = FS_read_distribute(owq);
				if (read_or_error < 0) {	// third try
					STAT_ADD1(read_tries[2]);
					read_or_error = FS_read_distribute(owq);
				}
			}
		}
	}

	return read_or_error;
}
Esempio n. 4
0
static struct connection_in * NextServer( struct connection_in * in ) 
{
	do {
		if ( in == NO_CONNECTION ) {
			return NO_CONNECTION ;
		}
		if ( BusIsServer(in) ) {
			return in ;
		}
		in = in->next ;
	} while (1) ;
}
Esempio n. 5
0
/* Write to settings dir */
static ZERO_OR_ERROR FS_w_settings(struct one_wire_query *owq)
{
	struct parsedname *pn = PN(owq);

	if ( BAD(TestConnection(pn)) ) {
		// safe for connection_in == NULL
		return -ECONNABORTED;
	} else if (KnownBus(pn) && BusIsServer(pn->selected_connection)) {
		return ServerWrite(owq);
	} else if ( pn->selected_connection != NO_CONNECTION ) {
		LEVEL_DEBUG("Attempt to write to local bus for /settings");
		return -ENODEV ;
	} else {
		return FS_w_local(owq);
	}
}
Esempio n. 6
0
// Look on a given connection for the device
static INDEX_OR_ERROR CheckThisConnection(int bus_nr, struct parsedname *pn)
{
	struct parsedname s_pn_copy;
	struct parsedname * pn_copy = &s_pn_copy ;
	struct connection_in * in = find_connection_in(bus_nr) ;
	INDEX_OR_ERROR connection_result = INDEX_BAD ;

	if ( in == NO_CONNECTION ) {
		return INDEX_BAD ;
	}
	
	memcpy(pn_copy, pn, sizeof(struct parsedname));	// shallow copy
	pn_copy->selected_connection = in;
	
	if ( BAD( TestConnection(pn_copy) ) ) {
		// Connection currently disconnected
		return INDEX_BAD;
	} else if (BusIsServer(in)) {
		// Server
		if ( INDEX_VALID( ServerPresence(pn_copy) ) ) {
			connection_result =  in->index;
		}
	} else if ( in->iroutines.flags & ADAP_FLAG_sham ) {
		return INDEX_BAD ;
	} else if ( in->iroutines.flags & ADAP_FLAG_presence_from_dirblob ) {
		// local connection with a dirblob (like fake, mock, ...)
		if ( GOOD( PresenceFromDirblob( pn_copy ) ) ) {
			connection_result =  in->index ;
		}
	} else {
		// local connection but need to ask directly
		struct transaction_log t[] = {
			TRXN_NVERIFY,
			TRXN_END,
		};
		if ( GOOD( BUS_transaction(t, pn_copy) ) ) {
			connection_result =  in->index ;
		}
	}
	if ( connection_result == INDEX_BAD ) {
		LEVEL_DEBUG("Presence of "SNformat" NOT found on bus %s",SNvar(pn_copy->sn),SAFESTRING(DEVICENAME(in))) ;
	} else {
		LEVEL_DEBUG("Presence of "SNformat" FOUND on bus %s",SNvar(pn_copy->sn),SAFESTRING(DEVICENAME(in))) ;
		Cache_Add_Device(in->index,pn_copy->sn) ; // add or update cache */
	}
	return connection_result ;
}
Esempio n. 7
0
/* 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;
}
Esempio n. 8
0
/* After parsing, but before sending to various devices. Will repeat 3 times if needed */
SIZE_OR_ERROR FS_read_postparse(struct one_wire_query *owq)
{
	struct parsedname *pn = PN(owq);
	SIZE_OR_ERROR read_or_error;

	/* Normal read. Try three times */
	LEVEL_DEBUG("%s", pn->path);
	STATLOCK;
	AVERAGE_IN(&read_avg);
	AVERAGE_IN(&all_avg);
	STATUNLOCK;

	/* First try */
	STAT_ADD1(read_tries[0]);

	/* Check file type. */
	if (pn->selected_device == NO_DEVICE || pn->selected_filetype == NO_FILETYPE) {
		if (KnownBus(pn) && BusIsServer(pn->selected_connection)) {
			/* Pass unknown remote filetype to remote owserver. */
			read_or_error = FS_r_given_bus(owq);
		} else {
			/* Local unknown filetypes are directories. */
			return -EISDIR;
		}	
	} else {
		/* Local known filetypes are handled here. */
		read_or_error = (pn->type == ePN_real) ? FS_read_real(owq) : FS_r_virtual(owq);
	}

	STATLOCK;
	if (read_or_error >= 0) {
		++read_success;			/* statistics */
		read_bytes += read_or_error;	/* statistics */
	}
	AVERAGE_OUT(&read_avg);
	AVERAGE_OUT(&all_avg);
	STATUNLOCK;
	LEVEL_DEBUG("%s return %d", pn->path, read_or_error);
	return read_or_error;
}
Esempio n. 9
0
/* If error, try twice more */
static ZERO_OR_ERROR FS_write_real(int depth, struct one_wire_query *owq)
{
	ZERO_OR_ERROR write_or_error;
	struct parsedname *pn = PN(owq);
	struct filetype * ft = pn->selected_filetype ;
	INDEX_OR_ERROR initial_bus = pn->selected_connection->index ; // current selected bus
	INDEX_OR_ERROR rechecked_bus ;

	if ( depth > 1 ) {
		LEVEL_DEBUG("Too many bus changes for write");
		return -ENODEV ;
	}

	if ( ft->write == FS_w_alias ) {
		// Special check for alias
		// it's ok for fake and tester and mock as well
		// so do this before the fake test
		// also no need to three-peat.
		return FS_write_owq(owq) ;
	}

	/* Special case for "fake" adapter */
	switch (get_busmode(pn->selected_connection)) {
		case bus_mock:
			// Mock -- write even "unwritable" to the cache for testing
			OWQ_Cache_Add(owq) ;
			// fall through
		case bus_fake:
		case bus_tester:
			return ( ft->write == NO_WRITE_FUNCTION ) ? -ENOTSUP : 0 ;
		default:
			// non-virtual devices get handled below
			break ;
	}

	/* First try */
	/* in and bus_nr already set */
	STAT_ADD1(write_tries[0]);
	write_or_error = FS_w_given_bus(owq);
	if ( write_or_error ==0 ) {
		return 0 ;
	}

	/* Second Try */
	STAT_ADD1(write_tries[1]);
	if (SpecifiedBus(pn)) {
		// The bus number casn't be changed -- it was specified in the path
		write_or_error = FS_w_given_bus(owq);
		if ( write_or_error == 0 ) {
			return 0 ;
		}

		// The bus number casn't be changed -- it was specified in the path
		STAT_ADD1(write_tries[2]);
		return FS_w_given_bus(owq);
	}

	/* Recheck location */
	/* if not a specified bus, relook for chip location */
	rechecked_bus = ReCheckPresence(pn) ;
	if ( rechecked_bus < 0 ) {
		// can't find the location
		return -ENOENT ;
	}

	if ( initial_bus == rechecked_bus ) {
		// special handling for remote
		// only repeat if the bus number is wrong
		// because the remote does the rewrites
		if (BusIsServer(pn->selected_connection)) {
			return write_or_error ;
		}
		// try again
		STAT_ADD1(write_tries[1]);
		write_or_error = FS_w_given_bus(owq);
		if ( write_or_error == 0 ) {
			return 0 ;
		}
		// third try
		STAT_ADD1(write_tries[2]);
		return FS_w_given_bus(owq);
	}		

	// Changed location retry everything
	LEVEL_DEBUG("Bus location changed from %d to %d\n",initial_bus,rechecked_bus);
	return FS_write_real(depth+1,owq);
}