コード例 #1
0
static int replay(const char *root) {
        _cleanup_close_ int inotify_fd = -1;
        _cleanup_free_ char *pack_fn = NULL;
        _cleanup_fclose_ FILE *pack = NULL;
        bool on_ssd, ready = false;
        char line[LINE_MAX];
        int prio, c;

        assert(root);

        if (asprintf(&pack_fn, "%s/.readahead", root) < 0)
                return log_oom();

        pack = fopen(pack_fn, "re");
        if (!pack) {
                if (errno == ENOENT) {
                        log_debug("No pack file found.");
                        return 0;
                }

                log_error("Failed to open pack file: %m");
                return -errno;
        }

        posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);

        inotify_fd = open_inotify();
        if (inotify_fd < 0)
                return inotify_fd;

        if (!fgets(line, sizeof(line), pack)) {
                log_error("Premature end of pack file.");
                return -EIO;
        }

        char_array_0(line);

        if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
                log_debug("Pack file host or version type mismatch.");
                goto done;
        }

        c = getc(pack);
        if (c == EOF) {
                log_debug("Premature end of pack file.");
                return -EIO;
        }

        /* We do not retest SSD here, so that we can start replaying
         * before udev is up.*/
        on_ssd = c == 'S';
        log_debug("On SSD: %s", yes_no(on_ssd));

        if (on_ssd)
                prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
        else
                /* We are not using RT here, since we'd starve IO that
                we didn't record (which is for example blkid, since
                its disk accesses go directly to the block device and
                are thus not visible in fallocate) to death. However,
                we do ask for an IO prio that is slightly higher than
                the default (which is BE. 4) */
                prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);

        if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
                log_warning("Failed to set IDLE IO priority class: %m");

        sd_notify(0, "STATUS=Replaying readahead data");

        log_debug("Replaying...");

        if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
                log_debug("Got termination request");
                goto done;
        }

        while (!feof(pack) && !ferror(pack)) {
                uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
                int k;
                ssize_t n;

                n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer));
                if (n < 0) {
                        if (errno != EINTR && errno != EAGAIN) {
                                log_error("Failed to read inotify event: %m");
                                return -errno;
                        }
                } else {
                        struct inotify_event *e = (struct inotify_event*) inotify_buffer;

                        while (n > 0) {
                                size_t step;

                                if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
                                        log_debug("Got termination request");
                                        goto done;
                                }

                                step = sizeof(struct inotify_event) + e->len;
                                assert(step <= (size_t) n);

                                e = (struct inotify_event*) ((uint8_t*) e + step);
                                n -= step;
                        }
                }

                k = unpack_file(pack);
                if (k < 0)
                        return k;

                if (!ready) {
                        /* We delay the ready notification until we
                         * queued at least one read */
                        sd_notify(0, "READY=1");
                        ready = true;
                }
        }

done:
        if (ferror(pack)) {
                log_error("Failed to read pack file.");
                return -EIO;
        }

        if (!ready)
                sd_notify(0, "READY=1");

        log_debug("Done.");
        return 0;
}
コード例 #2
0
ファイル: lsyncd.c プロジェクト: aking666/lsyncd
/*
| The effective main for one run.
|
| HUP signals may cause several runs of the one main.
*/
int
main1( int argc, char *argv[] )
{
	// the Lua interpreter
	lua_State * L;

	// the runner file
	char * lsyncd_runner_file = NULL;

	int argp = 1;

	// load Lua
	L = luaL_newstate( );

	luaL_openlibs( L );
	{
		// checks the lua version
		const char * version;
		int major, minor;
		lua_getglobal( L, "_VERSION" );
		version = luaL_checkstring( L, -1 );

		if(
			sscanf(
				version,
				"Lua %d.%d",
				&major, &minor
			) != 2
		)
		{
			fprintf(
				stderr,
				"cannot parse lua library version!\n"
			);
			exit (-1 );
		}

		if(
			major < 5 ||
			(major == 5 && minor < 1)
		) {
			fprintf(
				stderr,
				"Lua library is too old. Needs 5.1 at least"
			);
			exit( -1 );
		}

		lua_pop( L, 1 );
	}

	{
		// logging is prepared quite early
		int i = 1;
		add_logcat( "Normal", LOG_NOTICE  );
		add_logcat( "Warn",   LOG_WARNING );
		add_logcat( "Error",  LOG_ERR     );

		while( i < argc )
		{
			if(
				strcmp( argv[ i ], "-log"  ) &&
				strcmp( argv[ i ], "--log" )
			)
			{
				// arg is neither -log or --log
				i++;
				continue;
			}

			if( ++i >= argc )
			{
				// -(-)log was last argument
				break;
			}

			if( !add_logcat( argv[ i ], LOG_NOTICE ) )
			{
				printlogf(
					L, "Error",
					"'%s' is not a valid logging category",
					argv[ i ]
				);
				exit( -1 );
			}
		}
	}

	// registers Lsycnd's core library
	register_lsyncd( L );

	if( check_logcat( "Debug" ) <= settings.log_level )
	{
		// printlogf doesnt support %ld :-(
		printf(
			"kernels clocks_per_sec=%ld\n",
			clocks_per_sec
		);
	}

	// checks if the user overrode the default runner file
	if(
		argp < argc &&
		!strcmp( argv[ argp ], "--runner" )
	)
	{
		if (argp + 1 >= argc)
		{
			logstring(
				"Error",
				"Lsyncd Lua-runner file missing after --runner "
			);

			exit( -1 );
		}

		lsyncd_runner_file = argv[ argp + 1 ];
		argp += 2;
	}

	if( lsyncd_runner_file )
	{
		// checks if the runner file exists
		struct stat st;

		if( stat( lsyncd_runner_file, &st ) )
		{
			printlogf(
				L, "Error",
				"Cannot see a runner at '%s'.",
				lsyncd_runner_file
			);
			exit( -1 );
		}

		// loads the runner file
		if( luaL_loadfile(L, lsyncd_runner_file ) )
		{
			printlogf(
				L, "Error",
				"error loading '%s': %s",
				lsyncd_runner_file,
				lua_tostring( L, -1 )
			);

			exit( -1 );
		}

	}
	else
	{
		// loads the runner from binary
		if( luaL_loadbuffer( L, runner_out, runner_size, "runner" ) )
		{
			printlogf(
				L, "Error",
				"error loading precompiled runner: %s",
				lua_tostring( L, -1 )
			);

			exit( -1 );
		}
	}

	// prepares the runner executing the script
	{
		if( lua_pcall( L, 0, LUA_MULTRET, 0 ) )
		{
			printlogf(
				L, "Error",
				"preparing runner: %s",
				lua_tostring( L, -1 )
			);

			exit( -1 );
		}

		lua_pushlightuserdata( L, (void *) & runner );

		// switches the value ( result of preparing ) and the key &runner
		lua_insert( L, 1 );

		// saves the table of the runners functions in the lua registry
		lua_settable( L, LUA_REGISTRYINDEX );

		// saves the error function extras

		// &callError is the key
		lua_pushlightuserdata ( L, (void *) &callError );

		// &runner[ callError ] the value
		lua_pushlightuserdata ( L, (void *) &runner    );
		lua_gettable          ( L, LUA_REGISTRYINDEX   );
		lua_pushstring        ( L, "callError"         );
		lua_gettable          ( L, -2                  );
		lua_remove            ( L, -2                  );

		lua_settable          ( L, LUA_REGISTRYINDEX   );
	}

	// asserts the Lsyncd's version matches
	// between runner and core
	{
		const char *lversion;

		lua_getglobal( L, "lsyncd_version" );
		lversion = luaL_checkstring( L, -1 );

		if( strcmp( lversion, PACKAGE_VERSION ) )
		{
			printlogf(
				L, "Error",
				"Version mismatch '%s' is '%s', but core is '%s'",
				lsyncd_runner_file ? lsyncd_runner_file : "( internal runner )",
				lversion, PACKAGE_VERSION
			);

			exit( -1 );
		}

		lua_pop( L, 1 );
	}

	// loads the defaults from binary
	{
		if( luaL_loadbuffer( L, defaults_out, defaults_size, "defaults" ) )
		{
			printlogf(
				L, "Error",
				"loading defaults: %s",
				lua_tostring( L, -1 )
			);

			exit( -1 );
		}

		// prepares the defaults
		if( lua_pcall( L, 0, 0, 0 ) )
		{
			printlogf(
				L, "Error",
				"preparing defaults: %s",
				lua_tostring( L, -1 )
			);
			exit( -1 );
		}
	}

	// checks if there is a "-help" or "--help"
	{
		int i;
		for( i = argp; i < argc; i++ )
		{
			if (
				!strcmp( argv[ i ],  "-help" ) ||
				!strcmp( argv[ i ], "--help" )
			)
			{
				load_runner_func( L, "help" );

				if( lua_pcall( L, 0, 0, -2 ) )
				{
					exit( -1 );
				}

				lua_pop( L, 1 );
				exit( 0 );
			}
		}
	}

	// starts the option parser in Lua script
	{
		int idx = 1;
		const char *s;

		// creates a table with all remaining argv option arguments
		load_runner_func( L, "configure" );
		lua_newtable( L );

		while( argp < argc )
		{
			lua_pushnumber ( L, idx++          );
			lua_pushstring ( L, argv[ argp++ ] );
			lua_settable   ( L, -3             );
		}

		// creates a table with the cores event monitor interfaces
		idx = 0;
		lua_newtable( L );

		while( monitors[ idx ] )
		{
			lua_pushnumber ( L, idx + 1           );
			lua_pushstring ( L, monitors[ idx++ ] );
			lua_settable   ( L, -3                );
		}

		if( lua_pcall( L, 2, 1, -4 ) )
		{
			exit( -1 );
		}

		if( first_time )
		{
			// If not first time, simply retains the config file given
			s = lua_tostring(L, -1);
			if( s )
			{
				lsyncd_config_file = s_strdup( s );
			}
		}
		lua_pop( L, 2 );
	}

	// checks existence of the config file
	if( lsyncd_config_file )
	{
		struct stat st;

		// gets the absolute path to the config file
		// so in case of HUPing the daemon, it finds it again
		char * apath = get_realpath( lsyncd_config_file );
		if( !apath )
		{
			printlogf(
				L, "Error",
				"Cannot find config file at '%s'.",
				lsyncd_config_file
			);

			exit( -1 );
		}

		free( lsyncd_config_file );
		lsyncd_config_file = apath;

		if( stat( lsyncd_config_file, &st ) )
		{
			printlogf(
				L, "Error",
				"Cannot find config file at '%s'.",
				lsyncd_config_file
			);

			exit( -1 );
		}

		// loads and executes the config file
		if( luaL_loadfile( L, lsyncd_config_file ) )
		{
			printlogf(
				L, "Error",
				"error loading %s: %s",
				lsyncd_config_file,
				lua_tostring( L, -1 )
			);

			exit( -1 );
		}

		if( lua_pcall( L, 0, LUA_MULTRET, 0) )
		{
			printlogf(
				L, "Error",
				"error preparing %s: %s",
				lsyncd_config_file,
				lua_tostring( L, -1 )
			);

			exit( -1 );
		}
	}

#ifdef WITH_INOTIFY
	open_inotify( L );
#endif

#ifdef WITH_FSEVENTS
	open_fsevents( L );
#endif

	// adds signal handlers
	// listens to SIGCHLD, but blocks it until pselect( )
	// opens the signal handler up
	{
		sigset_t set;
		sigemptyset( &set );
		sigaddset( &set, SIGCHLD );
		signal( SIGCHLD, sig_child );
		sigprocmask( SIG_BLOCK, &set, NULL );

		signal( SIGHUP,  sig_handler );
		signal( SIGTERM, sig_handler );
		signal( SIGINT,  sig_handler );
	}

	// runs initializations from runner
	// it will set the configuration and add watches
	{
		load_runner_func( L, "initialize" );
		lua_pushboolean( L, first_time );

		if( lua_pcall( L, 1, 0, -3 ) )
		{
			exit( -1 );
		}

		lua_pop( L, 1 );
	}

	//
	// enters the master loop
	//
	masterloop( L );

	//
	// cleanup
	//

	// tidies up all observances
	{
		int i;
		for( i = 0; i < observances_len; i++ )
		{
			struct observance *obs = observances + i;
			obs->tidy( obs );
		}

		observances_len    = 0;
		nonobservances_len = 0;
	}

	// frees logging categories
	{
		int ci;
		struct logcat *lc;
		for( ci = 'A'; ci <= 'Z'; ci++ )
		{
			for( lc = logcats[ ci - 'A' ]; lc && lc->name; lc++)
			{
				free( lc->name );
				lc->name = NULL;
			}

			if( logcats[ci - 'A' ] )
			{
				free( logcats[ ci - 'A' ] );
				logcats[ ci - 'A' ] = NULL;
			}
		}
	}

	lua_close( L );
	return 0;
}