static int ulapi_load(rtapi_switch_t **ulapi_switch)
{
    int retval;
    const char *errmsg;
    rtapi_get_handle_t rtapi_get_handle;
    char ulapi_lib_fname[PATH_MAX];
    char *instance = getenv("INSTANCE");
    char *debug_env = getenv("ULAPI_DEBUG");
    int size = 0;
    int globalkey;

    // set the rtapi_instance global for this hal library instance
    if (instance != NULL)
	rtapi_instance = atoi(instance);

    if (debug_env)
	ulapi_debug = atoi(debug_env);

    rtapi_set_msg_level(ulapi_debug);

    // tag message origin field
    rtapi_set_logtag("ulapi");

    // first thing is to attach the global segment, based on
    // the RTAPI instance id. This will contain the flavor
    // this ULAPI HAL instance is to run with.

    // Also, it's the prerequisite for common error message
    // handling through the message ringbuffer; unless then
    // error messages will go to stderr.

    // the global segment is attached once here per ULAPI instance;
    // it's address is passed to the ulapi-<flavor>.so module once loaded.

    // init the common shared memory driver APU
    shm_common_init();

    globalkey = OS_KEY(GLOBAL_KEY, rtapi_instance);
    retval = shm_common_new(globalkey, &size,
			    rtapi_instance, (void **) &global_data, 0);

    if (retval == -ENOENT) {
	// the global_data segment does not exist. Happens if the realtime
	// script was not started
	rtapi_print_msg(RTAPI_MSG_ERR,
			"ULAPI:%d ERROR: realtime not started\n",
			rtapi_instance);
	return retval;
    }

    if (retval < 0) {
	// some other error attaching global
	rtapi_print_msg(RTAPI_MSG_ERR,
			"ULAPI:%d ERROR: shm_common_new() failed key=0x%x %s\n",
			rtapi_instance, globalkey, strerror(-retval));
	return retval;
    }

    if (size != sizeof(global_data_t)) {
	rtapi_print_msg(RTAPI_MSG_ERR,
			"ULAPI:%d ERROR: global segment size mismatch,"
			" expected: %zd, actual:%d\n",
		 rtapi_instance, sizeof(global_data_t), size);
	return -EINVAL;
    }

    if (global_data->magic != GLOBAL_READY) {
	rtapi_print_msg(RTAPI_MSG_ERR,
			"ULAPI:%d ERROR: global segment invalid magic:"
			" expected: 0x%x, actual: 0x%x\n",
			rtapi_instance, GLOBAL_READY,
			global_data->magic);
	return -EINVAL;
    }

    // global data set up ok

    // obtain handle on flavor descriptor as detected by rtapi_msgd
    flavor = flavor_byid(global_data->rtapi_thread_flavor);
    if (flavor == NULL) {
	rtapi_print_msg(RTAPI_MSG_ERR,
			"HAL_LIB:%d BUG - invalid flavor id: %d\n",
			rtapi_instance, global_data->rtapi_thread_flavor);
	return -EINVAL;
    }

    snprintf(ulapi_lib_fname,PATH_MAX,"%s/%s-%s%s",
	     EMC2_RTLIB_DIR, ulapi_lib, flavor->name, flavor->so_ext);

    // dynload the proper ulapi.so:
    if ((ulapi_so = dlopen(ulapi_lib_fname, RTLD_GLOBAL|RTLD_NOW))  == NULL) {
	errmsg = dlerror();
	rtapi_print_msg(RTAPI_MSG_ERR,
			"HAL_LIB:%d FATAL - dlopen(%s) failed: %s\n",
			rtapi_instance, ulapi_lib_fname,
			errmsg ? errmsg : "NULL");
	return -ENOENT;
    }

    // resolve rtapi_switch getter function
    dlerror();
    if ((rtapi_get_handle = (rtapi_get_handle_t)
	 dlsym(ulapi_so, "rtapi_get_handle")) == NULL) {
	errmsg = dlerror();
	rtapi_print_msg(RTAPI_MSG_ERR,
			"HAL_LIB:%d FATAL - resolving %s: cant"
			" dlsym(rtapi_get_handle): %s\n",
			rtapi_instance, ulapi_lib, errmsg ? errmsg : "NULL");
	return -ENOENT;
    }

    assert(rtapi_get_handle != NULL);

    // this redirects calls to rtapi through the just-loaded ulapi
    *ulapi_switch = rtapi_get_handle();

    // from here on it is safe to call all RTAPI functions (i.e. including those
    // which go through rtapi_switch)

    // resolve main function
    dlerror();
    if ((ulapi_main_ref = (ulapi_main_t)
	 dlsym(ulapi_so, "ulapi_main")) == NULL) {
	errmsg = dlerror();
	rtapi_print_msg(RTAPI_MSG_ERR,
			"HAL_LIB:%d FATAL - resolving %s: "
			"cant dlsym(ulapi_main): %s\n",
			rtapi_instance, ulapi_lib, errmsg ? errmsg : "NULL");
	return -ENOENT;
    }
    // resolve exit function
    dlerror();
    if ((ulapi_exit_ref = (ulapi_exit_t)
	 dlsym(ulapi_so, "ulapi_exit")) == NULL) {
	errmsg = dlerror();
	rtapi_print_msg(RTAPI_MSG_ERR,
			"HAL_LIB: FATAL - resolving %s:"
			" cant dlsym(ulapi_exit): %s\n",
		ulapi_lib, errmsg ? errmsg : "NULL");
	return -ENOENT;
    }

    assert(ulapi_main_ref != NULL);
    assert(ulapi_exit_ref != NULL);

    // call the ulapi init method, passing in the global segment
    if ((retval = ulapi_main_ref(rtapi_instance,
				 flavor->id, global_data)) < 0) {
	// check shmdrv, permissions
	rtapi_print_msg(RTAPI_MSG_ERR,
		"HAL_LIB: FATAL - cannot attach to instance %d"
			" - realtime not started?\n",
		rtapi_instance);
	return -ENOENT;
    }

    // pretty bad - we loaded the wrong ulapi.so
    if (flavor->id != rtapi_switch->thread_flavor_id) {
	rtapi_print_msg(RTAPI_MSG_ERR, "HAL_LIB: BUG: thread flavors disagree:"
			" hal_lib.c=%d rtapi=%d\n",
		flavor->id, rtapi_switch->thread_flavor_id);
    }

    // sanity check - may be harmless
    if (strcmp(GIT_VERSION, rtapi_switch->git_version)) {
	rtapi_print_msg(RTAPI_MSG_WARN,
			"HAL_LIB: UP API warning - git versions disagree:"
			" hal_lib.c=%s %s=%s\n",
			GIT_VERSION, ulapi_lib, rtapi_switch->git_version);
    }

    // declare victory
    return 0;
}
Beispiel #2
0
int main(int argc, char **argv)
{
    int c, i, retval;
    int option = LOG_NDELAY;
    pid_t pid, sid;
    size_t argv0_len, procname_len, max_procname_len;

    progname = argv[0];
    shm_common_init();

    while (1) {
	int option_index = 0;
	int curind = optind;
	c = getopt_long (argc, argv, "hI:sFf:i:S",
			 long_options, &option_index);
	if (c == -1)
	    break;
	switch (c)	{
	case 'F':
	    foreground++;
	    break;
	case 'I':
	    rtapi_instance = atoi(optarg);
	    break;
	case 'R':
	    hal_thread_stack_size = atoi(optarg);
	    break;
	case 'i':
	    instance_name = optarg;
	    break;
	case 'f':
	    if ((flavor = flavor_byname(optarg)) == NULL) {
		fprintf(stderr, "no such flavor: '%s' -- valid flavors are:\n", optarg);
		flavor_ptr f = flavors;
		while (f->name) {
		    fprintf(stderr, "\t%s\n", f->name);
		    f++;
		}
		exit(1);
	    }
	    break;
	case 'u':
	    usr_msglevel = atoi(optarg);
	    break;
     	case 'r':
	    rt_msglevel = atoi(optarg);
	    break;
	case 'H':
	    halsize = atoi(optarg);
	    break;
	case 'S':
	    use_shmdrv++;
	    break;
	case 's':
	    log_stderr++;
	    option |= LOG_PERROR;
	    break;
	case '?':
	    if (optopt)  fprintf(stderr, "bad short opt '%c'\n", optopt);
	    else  fprintf(stderr, "bad long opt \"%s\"\n", argv[curind]);
	    exit(1);
	    break;
	default:
	    usage(argc, argv);
	    exit(0);
	}
    }

    // sanity
    if (getuid() == 0) {
	fprintf(stderr, "%s: FATAL - will not run as root\n", progname);
	exit(EXIT_FAILURE);
    }
    if (geteuid() == 0) {
	fprintf(stderr, "%s: FATAL - will not run as setuid root\n", progname);
	exit(EXIT_FAILURE);
    }

    if (flavor == NULL)
	flavor = default_flavor();

    if (flavor == NULL) {
	fprintf(stderr, "%s: FATAL - failed to detect thread flavor\n", progname);
	exit(EXIT_FAILURE);
    }

    // can we actually run what's being suggested?
    if (!flavor_and_kernel_compatible(flavor)) {
	fprintf(stderr, "%s: FATAL - cant run the %s flavor on this kernel\n",
		progname, flavor->name);
	exit(EXIT_FAILURE);
    }

    // catch installation error: user not in xenomai group
    if (flavor->id == RTAPI_XENOMAI_ID) {
	int retval = user_in_xenomai_group();

	switch (retval) {
	case 1:  // yes
	    break;
	case 0:
	    fprintf(stderr, "this user is not member of group xenomai\n");
	    fprintf(stderr, "please 'sudo adduser <username>  xenomai',"
		    " logout and login again\n");
	    exit(EXIT_FAILURE);

	default:
	    fprintf(stderr, "cannot determine if this user "
		    "is a member of group xenomai: %s\n",
		    strerror(-retval));
	    exit(EXIT_FAILURE);
	}
    }

    // do we need the shmdrv module?
    if (((flavor->flags & FLAVOR_KERNEL_BUILD) ||
	 use_shmdrv) &&
	!shmdrv_available()) {
	fprintf(stderr, "%s: FATAL - %s requires the shmdrv module loaded\n",
		progname, use_shmdrv ? "--shmdrv" : flavor->name);
	exit(EXIT_FAILURE);
    }

    // the global segment every entity in HAL/RTAPI land attaches to
    if ((retval = create_global_segment()) != 1) // must be a new shm segment
	exit(retval);

    // good to go
    if (!foreground) {
        pid = fork();
        if (pid < 0) {
	    exit(EXIT_FAILURE);
        }
        if (pid > 0) {
	    exit(EXIT_SUCCESS);
        }
        umask(0);
        sid = setsid();
        if (sid < 0) {
	    exit(EXIT_FAILURE);
        }
#if 0
        if ((chdir("/")) < 0) {
	    exit(EXIT_FAILURE);
        }
#endif
    }

    snprintf(proctitle, sizeof(proctitle), "msgd:%d",rtapi_instance);

    openlog_async(proctitle, option , SYSLOG_FACILITY);

    // set new process name
    argv0_len = strlen(argv[0]);
    procname_len = strlen(proctitle);
    max_procname_len = (argv0_len > procname_len) ? (procname_len) : (argv0_len);

    strncpy(argv[0], proctitle, max_procname_len);
    memset(&argv[0][max_procname_len], '\0', argv0_len - max_procname_len);

    for (i = 1; i < argc; i++)
	memset(argv[i], '\0', strlen(argv[i]));


    // this is the single place in all of linuxCNC where the global segment
    // gets initialized - no reinitialization from elsewhere
    init_global_data(global_data, flavor->id, rtapi_instance,
    		     halsize, rt_msglevel, usr_msglevel,
		     instance_name,hal_thread_stack_size);

    syslog_async(LOG_INFO,
		 "startup instance=%s pid=%d flavor=%s "
		 "rtlevel=%d usrlevel=%d halsize=%d shm=%s gcc=%s version=%s",
		 global_data->instance_name, getpid(),
		 flavor->name,
		 global_data->rt_msg_level,
		 global_data->user_msg_level,
		 global_data->hal_size,
		 shmdrv_loaded ? "shmdrv" : "Posix",
		 __VERSION__,
		 GIT_VERSION);

    syslog_async(LOG_INFO,"configured: %s sha=%s", CONFIG_DATE, GIT_CONFIG_SHA);
    syslog_async(LOG_INFO,"built:      %s %s sha=%s",  __DATE__, __TIME__, GIT_BUILD_SHA);
    if (strcmp(GIT_CONFIG_SHA,GIT_BUILD_SHA))
	syslog_async(LOG_WARNING, "WARNING: git SHA's for configure and build do not match!");


    if ((global_data->rtapi_msgd_pid != 0) &&
	kill(global_data->rtapi_msgd_pid, 0) == 0) {
	fprintf(stderr,"%s: another rtapi_msgd is already running (pid %d), exiting\n",
		progname, global_data->rtapi_msgd_pid);
	exit(EXIT_FAILURE);
    } else {
	global_data->rtapi_msgd_pid = getpid();
    }

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    if (!log_stderr)
	close(STDERR_FILENO);

    message_thread();

    // signal received - check if rtapi_app running, and shut it down
    cleanup_actions();
    closelog_async();
    exit(exit_code);
}