/* All ow library closeup */
void LibClose(void)
{
	LEVEL_CALL("Starting Library cleanup");
	LibStop();
	PIDstop();
	DeviceDestroy();
	Detail_Close() ;

	_MUTEX_ATTR_DESTROY(Mutex.mattr);

#if OW_ZERO
	// Used by browse and announce
	OW_Free_dnssd_library();
	OW_Free_avahi_library();
#endif

	LEVEL_CALL("Finished Library cleanup");
	if (log_available) {
		closelog();
		log_available = 0;
	}
	SAFEFREE(Globals.announce_name) ;
	SAFEFREE(Globals.progname) ;
	SAFEFREE(Globals.fatal_debug_file) ;
	LEVEL_DEBUG("Libraries closed");
}
Exemple #2
0
/* Top level detect routine */
GOOD_OR_BAD DS2482_detect(struct port_in *pin)
{
    struct address_pair ap ;
    GOOD_OR_BAD gbResult ;
    enum ds2482_address chip_num ;

    Parse_Address( pin->init_data, &ap ) ;

    switch ( ap.second.type ) {
    case address_numeric:
        if ( ap.second.number < ds2482_18 || ap.second.number >= ds2482_too_far ) {
            LEVEL_CALL("DS2482 bus address <%s> invalid. Will search.", ap.second.alpha) ;
            chip_num = ds2482_any ;
        } else {
            chip_num = ap.second.number ;
        }
        break ;
    case address_all:
    case address_asterix:
        chip_num = ds2482_all ;
        break ;
    case address_none:
        chip_num = ds2482_any ;
        break ;
    default:
        LEVEL_CALL("DS2482 bus address <%s> invalid. Will scan.", ap.second.alpha) ;
        chip_num = ds2482_any ;
        break ;
    }

    switch ( ap.first.type ) {
    case address_all:
    case address_asterix:
        // All adapters
        gbResult = DS2482_detect_sys( 0, chip_num, pin ) ;
        break ;
    case address_none:
        // Any adapter -- first one found
        gbResult = DS2482_detect_sys( 1, chip_num, pin ) ;
        break ;
    default:
        // traditional, actual bus specified
        gbResult = DS2482_detect_bus( chip_num, ap.first.alpha, pin ) ;
        break ;
    }

    Free_Address( &ap ) ;
    return gbResult ;
}
Exemple #3
0
/* Just close in/out devices and clear cache. Just enough to make it possible
   to call LibStart() again. This is called from swig/ow.i to when script
   wants to initialize a new server-connection. */
void LibStop(void)
{
	char *argv[1] = { NULL };
	LEVEL_CALL("Clear Cache");
	Cache_Clear();
	LEVEL_CALL("Closing input devices");
	FreeInAll();
	LEVEL_CALL("Closing outout devices");
	FreeOutAll();

	/* Have to reset more internal variables, and this should be fixed
	 * by setting optind = 0 and call getopt()
	 * (first_nonopt = last_nonopt = 1;)
	 */
	optind = 0;
	(void) getopt_long(1, argv, " ", NULL, NULL);

	optarg = NULL;
	optind = 1;
	opterr = 1;
	optopt = '?';
}
Exemple #4
0
ZERO_OR_ERROR FS_fstat(const char *path, struct stat *stbuf)
{
	struct parsedname pn;
	ZERO_OR_ERROR ret = 0;

	LEVEL_CALL("path=%s", SAFESTRING(path));

	/* Bad path */
	if (FS_ParsedName(path, &pn) != 0 ) {
		return -ENOENT;
	}

	ret = FS_fstat_postparse(stbuf, &pn);
	FS_ParsedName_destroy(&pn);
	return ret;
}
Exemple #5
0
/* return size if ok, else negative */
SIZE_OR_ERROR FS_write(const char *path, const char *buf, const size_t size, const off_t offset)
{
	ZERO_OR_ERROR write_return;
	OWQ_allocate_struct_and_pointer(owq);

	LEVEL_CALL("path=%s size=%d offset=%d", SAFESTRING(path), (int) size, (int) offset);

	// parsable path?
	if ( OWQ_create(path, owq) != 0 ) { // for write
		return -ENOENT;
	}
	OWQ_assign_write_buffer(buf, size, offset, owq) ;
	write_return = FS_write_postparse(owq);
	OWQ_destroy(owq);
	return write_return;		/* here's where the size is used! */
}
Exemple #6
0
SIZE_OR_ERROR FS_read(const char *path, char *buf, const size_t size, const off_t offset)
{
	SIZE_OR_ERROR read_or_error;
	OWQ_allocate_struct_and_pointer(owq);

	LEVEL_CALL("path=%s size=%d offset=%d", SAFESTRING(path), (int) size, (int) offset);
	// Parseable path?
	if ( BAD( OWQ_create(path, owq) ) ) { // for read
		return -ENOENT;
	}
	OWQ_assign_read_buffer( buf, size, offset, owq) ;
	read_or_error = FS_read_postparse(owq);
	OWQ_destroy(owq);

	return read_or_error;
}
Exemple #7
0
/* Fstat with parsedname already done */
ZERO_OR_ERROR FS_fstat_postparse(struct stat *stbuf, const struct parsedname *pn)
{
	memset(stbuf, 0, sizeof(struct stat));

	LEVEL_CALL("ATTRIBUTES path=%s", SAFESTRING(pn->path));
	if (KnownBus(pn) && pn->known_bus == NULL) {
		/* check for presence of first in-device at least since FS_ParsedName
		 * doesn't do it yet. */
		return -ENOENT;
	} else if (pn->selected_device == NO_DEVICE) {	/* root directory */
		int nr = 0;
		//printf("FS_fstat root\n");
		stbuf->st_mode = S_IFDIR | 0755;
		stbuf->st_nlink = 2;	// plus number of sub-directories
		nr = -1;				// make it 1
		/*
		   If calculating NSUB is hard, the filesystem can set st_nlink of
		   directories to 1, and find will still work.  This is not documented
		   behavior of find, and it's not clear whether this is intended or just
		   by accident.  But for example the NTFS filesysem relies on this, so
		   it's unlikely that this "feature" will go away.
		 */
		stbuf->st_nlink += nr;
		FSTATLOCK;
		stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = StateInfo.start_time;
		FSTATUNLOCK;
		stbuf->st_size = 4096 ; // Common directory size
		return 0;
	} else if (pn->selected_filetype == NO_FILETYPE) {
		int nr = 0;
		//printf("FS_fstat pn.selected_filetype == NULL  (1-wire device)\n");
		stbuf->st_mode = S_IFDIR | 0777;
		stbuf->st_nlink = 2;	// plus number of sub-directories

		nr = -1;				// make it 1
		//printf("FS_fstat seem to be %d entries (%d dirs) in device\n", pn.selected_device->nft, nr);
		stbuf->st_nlink += nr;
		FSTATLOCK;
		stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = StateInfo.dir_time;
		FSTATUNLOCK;
		stbuf->st_size = 4096 ; // Common directory size
		return 0;
	} else if (pn->selected_filetype->format == ft_directory || pn->selected_filetype->format == ft_subdir) {	/* other directory */
		int nr = 0;
		stbuf->st_mode = S_IFDIR | 0777;
		stbuf->st_nlink = 2;	// plus number of sub-directories
		nr = -1;				// make it 1
		stbuf->st_nlink += nr;

		FSTATLOCK;
		stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = StateInfo.dir_time;
		FSTATUNLOCK;
		stbuf->st_size = 4096 ; // Common directory size
		return 0;
	} else {					/* known 1-wire filetype */
		stbuf->st_mode = S_IFREG;
        if (pn->selected_filetype->read != NO_READ_FUNCTION) {
			stbuf->st_mode |= 0444;
		}
		if (!Globals.readonly && (pn->selected_filetype->write != NO_WRITE_FUNCTION)) {
			stbuf->st_mode |= 0222;
        }
		stbuf->st_nlink = 1;

		switch (pn->selected_filetype->change) {
		case fc_volatile:
		case fc_second:
		case fc_statistic:
			stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = NOW_TIME;
			break;
		case fc_stable:
			FSTATLOCK;
			stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = StateInfo.dir_time;
			FSTATUNLOCK;
			break;
		default:
			stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = StateInfo.start_time;
			break;
		}
		stbuf->st_size = FullFileLength(pn);
		return 0;
	}
}
Exemple #8
0
/* 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) ;
	}
}
Exemple #9
0
/*
  This is a test to implement daemon()
*/
static int my_daemon(int nochdir, int noclose)
{
	struct sigaction act;
	int pid;
	FILE_DESCRIPTOR_OR_ERROR file_descriptor;

	signal(SIGCHLD, SIG_DFL);

#if defined(__UCLIBC__)
	pid = vfork();
#else							/* __UCLIBC__ */
	pid = fork();
#endif							/* __UCLIBC__ */
	switch (pid) {
	case -1:
		memset(&act, 0, sizeof(act));
		act.sa_handler = catchchild;
		act.sa_flags = SA_RESTART;
		sigaction(SIGCHLD, &act, NULL);
//printf("owlib: my_daemon: pid=%d fork error\n", getpid());
		LEVEL_CALL("Libsetup ok");

		return (-1);
	case 0:
		break;
	default:
		//signal(SIGCHLD, SIG_DFL);
//printf("owlib: my_daemon: pid=%d exit parent\n", getpid());
		_exit(0);
	}

	if (setsid() < 0) {
		perror("setsid:");
		return -1;
	}

	/* Make certain we are not a session leader, or else we
	 * might reacquire a controlling terminal */
#ifdef __UCLIBC__
	pid = vfork();
#else							/* __UCLIBC__ */
	pid = fork();
#endif							/* __UCLIBC__ */
	if (pid) {
		//printf("owlib: my_daemon: _exit() pid=%d\n", getpid());
		_exit(0);
	}

	memset(&act, 0, sizeof(act));
	act.sa_handler = catchchild;
	act.sa_flags = SA_RESTART;
	sigaction(SIGCHLD, &act, NULL);

	if (!nochdir) {
		chdir("/");
	}

	if (!noclose) {
		close(STDIN_FILENO);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);
		if (dup(dup(open("/dev/null", O_APPEND))) == -1) {
			perror("dup:");
			return -1;
		}
	}
	return 0;
}
Exemple #10
0
/*
 * lower level routine for actually handling a request
 * deals with data (ping is handled higher)
 */
void *DataHandler(void *v)
{
	struct handlerdata *hd = v;
	char *retbuffer = NULL;
	struct client_msg cm; // the return message

#if OW_CYGWIN
	/* Random generator seem to need initialization for each new thread
	 * If not, seed will be reset and rand() will return 0 the first call.
	 */
	{
		struct timeval tv;
		gettimeofday(&tv, NULL);
		srand((unsigned int) tv.tv_usec);
	}
#endif

	memset(&cm, 0, sizeof(struct client_msg));
	cm.version = MakeServerprotocol(OWSERVER_PROTOCOL_VERSION);
	cm.control_flags = hd->sm.control_flags;			// default flag return -- includes persistence state

	/* Pre-handling for special testing mode to exclude certain messages */
	switch ((enum msg_classification) hd->sm.type) {
	case msg_dirall:
	case msg_dirallslash:
		if (Globals.no_dirall) {
			LEVEL_DEBUG("DIRALL message rejected.") ;
			hd->sm.type = msg_error;
		}
		break;
	case msg_get:
	case msg_getslash:
		if (Globals.no_get) {
			LEVEL_DEBUG("GET message rejected.") ;
			hd->sm.type = msg_error;
		}
		break;
	default:
		break;
	}

	/* Now Check message types and only parse valid messages */
	switch ((enum msg_classification) hd->sm.type) {	// outer switch
	case msg_read:				// good message
	case msg_write:				// good message
	case msg_dir:				// good message
	case msg_presence:			// good message
	case msg_dirall:			// good message
	case msg_dirallslash:			// good message
	case msg_get:				// good message
	case msg_getslash:			// good message
		if (hd->sm.payload == 0) {	/* Bad query -- no data after header */
			LEVEL_DEBUG("No payload -- ignore.") ;
			cm.ret = -EBADMSG;
		} else {
			struct parsedname *pn;
			OWQ_allocate_struct_and_pointer(owq);
			pn = PN(owq);

			/* Parse the path string and crete  query object */
			LEVEL_CALL("DataHandler: parse path=%s", hd->sp.path);
			cm.ret = BAD( OWQ_create(hd->sp.path, owq) ) ? -1 : 0 ;
			if ( cm.ret != 0 ) {
				LEVEL_DEBUG("DataHandler: OWQ_create failed cm.ret=%d", cm.ret);
				break;
			}

			/* Use client persistent settings (temp scale, display mode ...) */
			pn->control_flags = hd->sm.control_flags;
			/* Override some settings from control flags */
			if ( (pn->control_flags & UNCACHED) != 0 ) {
				// client wants uncached
				pn->state |= ePS_uncached;
			}
			if ( (pn->control_flags & ALIAS_REQUEST) == 0 ) {
				// client wants unaliased
				pn->state |= ePS_unaliased;
			}
			

			/* Antilooping tags */
			pn->tokens = hd->sp.tokens;
			pn->tokenstring = hd->sp.tokenstring;
			//printf("Handler: sm.sg=%X pn.state=%X\n", sm.sg, pn.state);
			//printf("Scale=%s\n", TemperatureScaleName(SGTemperatureScale(sm.sg)));

			switch ((enum msg_classification) hd->sm.type) {
			case msg_presence:
				LEVEL_CALL("Presence message for %s", SAFESTRING(pn->path));
				// Basically, if we were able to ParsedName it's here!
				cm.size = 0;
				retbuffer = owmalloc( SERIAL_NUMBER_SIZE ) ;
				if ( retbuffer ) {
					memcpy( retbuffer, pn->sn, SERIAL_NUMBER_SIZE ) ;
					cm.payload = SERIAL_NUMBER_SIZE ;
				} else {
					cm.payload = 0 ;
				}
				cm.ret = 0;		// good answer
				break;
			case msg_read:
				LEVEL_CALL("Read message");
				retbuffer = ReadHandler(hd, &cm, owq);
				LEVEL_DEBUG("Read message done value=%p", retbuffer);
				break;
			case msg_write:
				LEVEL_CALL("Write message");
				if ( (int) hd->sp.datasize < hd->sm.size ) {
					cm.ret = -EMSGSIZE;
				} else {
					/* set buffer (size already set) */
					OWQ_assign_write_buffer( (ASCII *) hd->sp.data, hd->sm.size, hd->sm.offset, owq) ;
					WriteHandler(hd, &cm, owq);
				}
				break;
			case msg_dir:
				LEVEL_CALL("Directory message (one at a time)");
				DirHandler(hd, &cm, pn);
				break;
			case msg_dirall:
				LEVEL_CALL("Directory message (all at once)");
				retbuffer = DirallHandler(hd, &cm, pn);
				break;
			case msg_dirallslash:
				LEVEL_CALL("Directory message (all at once, with directory /)");
				retbuffer = DirallslashHandler(hd, &cm, pn);
				break;
			case msg_get:
				if (IsDir(pn)) {
					LEVEL_CALL("Get -> Directory message (all at once)");
					retbuffer = DirallHandler(hd, &cm, pn);
				} else {
					LEVEL_CALL("Get -> Read message");
					retbuffer = ReadHandler(hd, &cm, owq);
				}
				break;
			case msg_getslash:
				if (IsDir(pn)) {
					LEVEL_CALL("Get -> Directory message (all at once)");
					retbuffer = DirallslashHandler(hd, &cm, pn);
				} else {
					LEVEL_CALL("Get -> Read message");
					retbuffer = ReadHandler(hd, &cm, owq);
				}
				break;
			default:			// never reached
				LEVEL_CALL("Error: unknown message %d", (int) hd->sm.type);
				break;
			}
			OWQ_destroy(owq);
			LEVEL_DEBUG("DataHandler: FS_ParsedName_destroy done");
		}
		break;
	case msg_nop:				// "bad" message
		LEVEL_CALL("NOP message");
		cm.ret = 0;
		break;
	case msg_size:				// no longer used
	case msg_error:
	default:					// "bad" message
		cm.ret = -ENOMSG;
		LEVEL_CALL("No message");
		break;
	}
	LEVEL_DEBUG("DataHandler: cm.ret=%d", cm.ret);

	TOCLIENTLOCK(hd);
	if (cm.ret != -EIO) {
		ToClient(hd->file_descriptor, &cm, retbuffer);
	} else {
		ErrorToClient(hd, &cm) ;
	}

	// Signal to PingLoop that we're done.
	hd->toclient = toclient_complete ;
	if ( hd->ping_pipe[fd_pipe_write] != FILE_DESCRIPTOR_BAD ) {
		ignore_result = write( hd->ping_pipe[fd_pipe_write],"X",1) ; //dummy payload
	}
	TOCLIENTUNLOCK(hd);

	if (retbuffer) {
		owfree(retbuffer);
	}
	LEVEL_DEBUG("Finished with client request");
	return VOID_RETURN;
}