Example #1
0
int main(int argc, char **argv) {
    int i, cleanupd_fd;
    struct tempfile *stdout_log, *stderr_log, *singularity_debug;
    struct image_object image;
    pid_t child;
    siginfo_t siginfo;
    struct stat filestat;

    singularity_config_init();

    singularity_suid_init();
    singularity_priv_init();

    singularity_registry_init();
    singularity_priv_drop();

    singularity_runtime_autofs();

    singularity_registry_set("UNSHARE_PID", "1");
    singularity_registry_set("UNSHARE_IPC", "1");

    if ( singularity_registry_get("INSTANCE_BOOT") != NULL ) {
        singularity_registry_set("CONTAIN", "1");
    }

    singularity_cleanupd();

    if ( singularity_registry_get("WRITABLE") != NULL ) {
        singularity_message(VERBOSE3, "Instantiating writable container image object\n");
        image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDWR);
    } else {
        singularity_message(VERBOSE3, "Instantiating read only container image object\n");
        image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDONLY);
    }

    singularity_runtime_ns(SR_NS_ALL);

    singularity_sessiondir();

    singularity_image_mount(&image, CONTAINER_MOUNTDIR);

    action_ready();

    singularity_runtime_overlayfs();
    singularity_runtime_mounts();
    singularity_runtime_files();

    /* After this point, we are running as PID 1 inside PID NS */
    singularity_message(DEBUG, "Preparing sinit daemon\n");
    singularity_registry_set("ROOTFS", CONTAINER_FINALDIR);
    singularity_daemon_init();

    singularity_message(DEBUG, "Entering chroot environment\n");

    singularity_runtime_enter();
    singularity_priv_drop_perm();

    if ( envclean() != 0 ) {
        singularity_message(ERROR, "Failed sanitizing the environment\n");
        ABORT(255);
    }

    if ( chdir("/") < 0 ) {
        singularity_message(ERROR, "Can't change directory to /\n");
    }
    setsid();
    umask(0);

    cleanupd_fd = atoi(singularity_registry_get("CLEANUPD_FD"));

    if ( singularity_registry_get("INSTANCE_BOOT") != NULL ) {
        int pipes[2];

        if ( pipe2(pipes, O_CLOEXEC) < 0 ) {
            singularity_signal_go_ahead(255);
            return(0);
        }

        if ( fork() == 0 ) {
            /* wait a broken pipe which mean exec success */
            struct pollfd pfd;
            pfd.fd = pipes[0];
            pfd.events = POLLRDHUP;

            close(pipes[1]);
            while( poll(&pfd, 1, 1000) >= 0 ) {
                if ( pfd.revents == POLLHUP ) break;
            }
            singularity_signal_go_ahead(0);

            /* wait /sbin/init install signal handler */
            usleep(20000);
            return(0);
        } else {
            close(pipes[0]);
            if ( is_exec("/sbin/init") == 0 ) {
                argv[1] = NULL;
                if ( execv("/sbin/init", argv) < 0 ) { // Flawfinder: ignore
                    singularity_message(ERROR, "Exec of /sbin/init failed\n");
                }
            } else {
                singularity_message(ERROR, "/sbin/init not present in container\n");
            }
            /* send exit status and implicitly kill polling child */
            singularity_signal_go_ahead(255);
            return(0);
        }
    }

    /* set program name */
    if ( prctl(PR_SET_NAME, "sinit", 0, 0, 0) < 0 ) {
        singularity_message(ERROR, "Failed to set program name\n");
        ABORT(255);
    }

    singularity_install_signal_handler();

    /* Close all open fd's that may be present besides daemon info file fd */
    singularity_message(DEBUG, "Closing open fd's\n");
    for( i = sysconf(_SC_OPEN_MAX); i > 2; i-- ) {        
        if ( i != cleanupd_fd ) {
            if ( fstat(i, &filestat) == 0 ) {
                if ( S_ISFIFO(filestat.st_mode) != 0 ) {
                    continue;
                }
            }
            close(i);
        }
    }

    singularity_debug = make_logfile("singularity-debug");
    stdout_log = make_logfile("stdout");
    stderr_log = make_logfile("stderr");
    
    for( i = 0; i <= 2; i++ ) {
        close(i);
    }

    if ( chdir("/") < 0 ) {
        singularity_message(ERROR, "Can't change directory to /\n");
    }
    setsid();
    umask(0);

    /* set program name */
    if ( prctl(PR_SET_NAME, "sinit", 0, 0, 0) < 0 ) {
        singularity_message(ERROR, "Failed to set program name\n");
        ABORT(255);
    }

    child = fork();
    
    if ( child == 0 ) {
        /* Make standard output and standard error files to log stdout & stderr into */
        if ( stdout_log != NULL ) {
            if ( -1 == dup2(stdout_log->fd, 1) ) {
                singularity_message(ERROR, "Unable to dup2(): %s\n", strerror(errno));
                ABORT(255);
            }
        }

        if ( stderr_log != NULL ) {
            if ( -1 == dup2(stderr_log->fd, 2) ) {
                singularity_message(ERROR, "Unable to dup2(): %s\n", strerror(errno));
                ABORT(255);
            }
        }

        /* Unblock signals and execute startscript */
        singularity_unblock_signals();
        if ( is_exec("/.singularity.d/actions/start") == 0 ) {
            singularity_message(DEBUG, "Exec'ing /.singularity.d/actions/start\n");

            if ( execv("/.singularity.d/actions/start", argv) < 0 ) { // Flawfinder: ignore
                singularity_message(ERROR, "Failed to execv() /.singularity.d/actions/start: %s\n", strerror(errno));
                ABORT(CHILD_FAILED);
            }
        } else {
            singularity_message(VERBOSE, "Instance start script not found\n");
            kill(1, SIGCONT);
        }
    } else if ( child > 0 ) {
        if ( singularity_debug != NULL ) {
            if ( -1 == dup2(singularity_debug->fd, 2) ) {
                singularity_message(ERROR, "Unable to dup2(): %s\n", strerror(errno));
                ABORT(255);
            }
        }

        singularity_message(DEBUG, "Waiting for signals\n");
        /* send a SIGALRM if start script doesn't send SIGCONT within 1 seconds */
        alarm(1);
        while (1) {
            if ( singularity_handle_signals(&siginfo) < 0 ) {
                singularity_signal_go_ahead(255);
                break;
            }
            if ( siginfo.si_signo == SIGCHLD ) {
                singularity_message(DEBUG, "Child exited\n");
                if ( siginfo.si_pid == 2 && siginfo.si_status == CHILD_FAILED ) {
                    singularity_signal_go_ahead(CHILD_FAILED);
                    break;
                }
            } else if ( siginfo.si_signo == SIGCONT && siginfo.si_pid == 2 ) {
                /* start script correctly exec */
                singularity_signal_go_ahead(0);
                started = 1;
            } else if ( siginfo.si_signo == SIGALRM && started == 0 ) {
                /* don't receive SIGCONT, start script modified/replaced ? */
                singularity_message(ERROR, "Start script doesn't send SIGCONT\n");
                singularity_signal_go_ahead(255);
                break;
            }
        }
    } else {
        singularity_message(ERROR, "Failed to execute start script\n");
        singularity_signal_go_ahead(255);
    }
    return(0);
}
Example #2
0
static int setup_container(spank_t spank)
{
    int rc;
    struct image_object image;
    char *command = NULL;

    if ((rc = setup_container_environment(spank)) != 0) { return rc; }

    /*
     * Ugg, singularity_* calls tend to call ABORT(255), which translates to
     * exit(255), all over the place.  The slurm SPANK hook API may not
     * expect such sudden death of the pending slurm task.  I've left
     * a bunch of following "return rc;" commented out, as the failure
     * conditions from singularity_* calls isn't clear to me.
     */

    // Before we do anything, check privileges and drop permission
    singularity_priv_init();
    singularity_priv_drop();

    singularity_message(VERBOSE, "Running Slurm/Singularity integration "
                        "plugin\n");

    if ((rc = singularity_config_init()) != 0) {
         return rc;
    }


    singularity_priv_init();
//TODO    singularity_suid_init(argv);

    singularity_registry_init();
    singularity_priv_userns();
    singularity_priv_drop();

    singularity_cleanupd();

    singularity_runtime_ns(SR_NS_ALL);

    singularity_sessiondir();

    image = singularity_image_init(singularity_registry_get("IMAGE")); 

    if ( singularity_registry_get("WRITABLE") == NULL ) {
        singularity_image_open(&image, O_RDONLY);
    } else {
        singularity_image_open(&image, O_RDWR);
    }  

    singularity_image_check(&image);
    singularity_image_bind(&image);
    singularity_image_mount(&image, singularity_runtime_rootfs(NULL));

    action_ready(singularity_runtime_rootfs(NULL));

    singularity_runtime_overlayfs();
    singularity_runtime_mounts();
    singularity_runtime_files();
    singularity_runtime_enter();

    singularity_runtime_environment();

    singularity_priv_drop_perm();

 
    if ((rc = setup_container_cwd()) < 0) { 
       singularity_message(ERROR, "Could not obtain current directory.\n");
       return rc; 
    }

    envar_set("SINGULARITY_CONTAINER", singularity_image_name(&image), 1); // Legacy PS1 support
    envar_set("SINGULARITY_NAME", singularity_image_name(&image), 1);
    envar_set("SINGULARITY_SHELL", singularity_registry_get("SHELL"), 1);

    command = singularity_registry_get("COMMAND");
    singularity_message(LOG, "USER=%s, IMAGE='%s', COMMAND='%s'\n", singularity_priv_getuser(), singularity_image_name(&image), singularity_registry_get("COMMAND"));

    // At this point, the current process is in the runtime container environment.
    // Return control flow back to Slurm: when execv is invoked, it'll be done from
    // within the container.

    return 0;
}