Example #1
0
struct strlist *strlist_new(size_t reserve)
{
    struct strlist *list = strlist_alloc(NULL, reserve);
    list->capacity = reserve;
    list->size = 0;
    memset(list->items, 0, sizeof(struct string *) * list->capacity);
    return list;
}
Example #2
0
static struct strlist *strlist_ensure(struct strlist *list, size_t len)
{
    if (list->capacity < len) {
        list->capacity += len;
        list = strlist_alloc(list, list->capacity);
    }

    return list;
}
Example #3
0
static int do_strlist_add(struct strlist **strlist,
	const char *path, long flag, int sorted, int uniq)
{
	struct strlist *s=NULL;
	struct strlist *slast=NULL;
	struct strlist *slnew=NULL;

	if(!(slnew=strlist_alloc(path, flag))) return -1;

	// Insert into a sorted position in the list, or if the sorted flag
	// was zero, add to the end of the list.
	// FIX THIS: Unsorted means that it goes through the whole list to
	// find the last entry. Can this be made better?
	for(s=*strlist; s; s=s->next)
	{
		if(uniq && !pathcmp(path, s->path))
		{
			strlist_free(slnew);
			return 0;
		}
		if(sorted && pathcmp(path, s->path)<0) break;
		slast=s;
	}
	if(slast)
	{
		slnew->next=slast->next;
		slast->next=slnew;
	}
	else
	{
		*strlist=slnew;
		slnew->next=s;
	}

	return 0;
}
int
main(int argc, char *argv[])
{
    custr_t *execname = NULL;
    strlist_t *env = NULL;
    custr_t *workdir = NULL;

    /*
     * We write the log to stderr and expect cn-agent to log/parse the output.
     * It can know that dockerexec finished when it sees either a line that
     * starts with:
     *
     * <timestamp> FATAL
     *
     * or:
     *
     * <timestamp> EXEC
     *
     * the former indicating that we failed and the latter that the next action
     * will be execve().
     */
    log_stream = stderr;

    if (argc < 2) {
        fatal(ERR_NO_COMMAND, "no command specified on cmdline, argc: %d\n",
            argc);
    }

    if (strlist_alloc(&env, 0) != 0) {
        fatal(ERR_NO_MEMORY, "failed to allocate string lists: %s",
          strerror(errno));
    }

    /* NOTE: all of these will call fatal() if there's a problem */
    getUserGroupData();
    setupWorkdir(&workdir);

    if (buildCmdEnv(env) != 0) {
        fatal(ERR_UNEXPECTED, "buildCmdEnv() failed: %s\n", strerror(errno));
    }

    /* cleanup mess from mdata-client */
    close(4); /* /dev/urandom from mdata-client */
    close(5); /* event port from mdata-client */
    close(6); /* /native/.zonecontrol/metadata.sock from mdata-client */
    /* TODO: ensure we cleaned up everything else mdata created for us */

    // TODO: close any descriptors which are not to be attached to this
    //       exec cmd? Or let the zlogin caller deal with that?

    dlog("DROP PRIVS\n");

    if (grp != NULL) {
        if (setgid(grp->gr_gid) != 0) {
            fatal(ERR_SETGID, "setgid(%d): %s\n", grp->gr_gid, strerror(errno));
        }
    }
    if (pwd != NULL) {
        if (initgroups(pwd->pw_name, grp->gr_gid) != 0) {
            fatal(ERR_INITGROUPS, "initgroups(%s,%d): %s\n", pwd->pw_name,
                grp->gr_gid, strerror(errno));
        }
        if (setuid(pwd->pw_uid) != 0) {
            fatal(ERR_SETUID, "setuid(%d): %s\n", pwd->pw_uid, strerror(errno));
        }
    }

    /*
     * Find the executable path based on argv[1] and $PATH.  This routine
     * calls fatal() if it fails.
     */
    execname = execName(argv[1], env, custr_cstr(workdir));

    // Message for cn-agent that dockerexec is done and child should start
    // now.
    dlog("EXEC\n");

    execve(custr_cstr(execname), argv + 1, strlist_array(env));

    // If execve() has failed, this next message should go to the user since
    // stdout and stderr should now be connected to them.
    fatal(ERR_EXEC_FAILED, "execve(%s) failed: %s\n", argv[1],
        strerror(errno));

    /* NOTREACHED */
    abort();
}