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; }
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; }
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(); }