Create Service and ServiceManager classes
Change-Id: I363a5e4751ad83d2f4096882a6fbbeddca03acfe
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index d420351..3ed1d58 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -28,10 +28,11 @@
#include "action.h"
#include "init.h"
-#include "parser.h"
#include "init_parser.h"
#include "log.h"
+#include "parser.h"
#include "property_service.h"
+#include "service.h"
#include "util.h"
#include <base/stringprintf.h>
@@ -63,7 +64,7 @@
static struct {
const char *name;
int (*func)(const std::vector<std::string>& args);
- unsigned char nargs;
+ size_t nargs;
unsigned char flags;
} keyword_info[KEYWORD_COUNT] = {
[ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
@@ -77,23 +78,8 @@
#define kw_nargs(kw) (keyword_info[kw].nargs)
void dump_parser_state() {
- if (false) {
- struct listnode* node;
- list_for_each(node, &service_list) {
- service* svc = node_to_item(node, struct service, slist);
- INFO("service %s\n", svc->name);
- INFO(" class '%s'\n", svc->classname);
- INFO(" exec");
- for (int n = 0; n < svc->nargs; n++) {
- INFO(" '%s'", svc->args[n]);
- }
- INFO("\n");
- for (socketinfo* si = svc->sockets; si; si = si->next) {
- INFO(" socket %s %s 0%o\n", si->name, si->type, si->perm);
- }
- }
- ActionManager::GetInstance().DumpState();
- }
+ ServiceManager::GetInstance().DumpState();
+ ActionManager::GetInstance().DumpState();
}
static int lookup_keyword(const char *s)
@@ -419,363 +405,38 @@
return init_parse_config_file(path);
}
-static int valid_name(const char *name)
-{
- if (strlen(name) > 16) {
- return 0;
- }
- while (*name) {
- if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
- return 0;
- }
- name++;
- }
- return 1;
-}
-
-struct service *service_find_by_name(const char *name)
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (!strcmp(svc->name, name)) {
- return svc;
- }
- }
- return 0;
-}
-
-struct service *service_find_by_pid(pid_t pid)
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (svc->pid == pid) {
- return svc;
- }
- }
- return 0;
-}
-
-struct service *service_find_by_keychord(int keychord_id)
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (svc->keychord_id == keychord_id) {
- return svc;
- }
- }
- return 0;
-}
-
-void service_for_each(void (*func)(struct service *svc))
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- func(svc);
- }
-}
-
-void service_for_each_class(const char *classname,
- void (*func)(struct service *svc))
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (!strcmp(svc->classname, classname)) {
- func(svc);
- }
- }
-}
-
-void service_for_each_flags(unsigned matchflags,
- void (*func)(struct service *svc))
-{
- struct listnode *node;
- struct service *svc;
- list_for_each(node, &service_list) {
- svc = node_to_item(node, struct service, slist);
- if (svc->flags & matchflags) {
- func(svc);
- }
- }
-}
-
-service* make_exec_oneshot_service(int nargs, char** args) {
- // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
- // SECLABEL can be a - to denote default
- int command_arg = 1;
- for (int i = 1; i < nargs; ++i) {
- if (strcmp(args[i], "--") == 0) {
- command_arg = i + 1;
- break;
- }
- }
- if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
- ERROR("exec called with too many supplementary group ids\n");
- return NULL;
- }
-
- int argc = nargs - command_arg;
- char** argv = (args + command_arg);
- if (argc < 1) {
- ERROR("exec called without command\n");
- return NULL;
- }
-
- service* svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * argc);
- if (svc == NULL) {
- ERROR("Couldn't allocate service for exec of '%s': %s", argv[0], strerror(errno));
- return NULL;
- }
-
- if ((command_arg > 2) && strcmp(args[1], "-")) {
- svc->seclabel = args[1];
- }
- if (command_arg > 3) {
- svc->uid = decode_uid(args[2]);
- }
- if (command_arg > 4) {
- svc->gid = decode_uid(args[3]);
- svc->nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
- for (size_t i = 0; i < svc->nr_supp_gids; ++i) {
- svc->supp_gids[i] = decode_uid(args[4 + i]);
- }
- }
-
- static int exec_count; // Every service needs a unique name.
- char* name = NULL;
- asprintf(&name, "exec %d (%s)", exec_count++, argv[0]);
- if (name == NULL) {
- ERROR("Couldn't allocate name for exec service '%s'\n", argv[0]);
- free(svc);
- return NULL;
- }
- svc->name = name;
- svc->classname = "default";
- svc->flags = SVC_EXEC | SVC_ONESHOT;
- svc->nargs = argc;
- memcpy(svc->args, argv, sizeof(char*) * svc->nargs);
- svc->args[argc] = NULL;
- list_add_tail(&service_list, &svc->slist);
- return svc;
-}
-
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
if (nargs < 3) {
parse_error(state, "services must have a name and a program\n");
- return 0;
+ return nullptr;
}
- if (!valid_name(args[1])) {
- parse_error(state, "invalid service name '%s'\n", args[1]);
- return 0;
- }
+ std::vector<std::string> str_args(args + 2, args + nargs);
+ std::string ret_err;
+ Service* svc = ServiceManager::GetInstance().AddNewService(args[1], "default",
+ str_args, &ret_err);
- service* svc = (service*) service_find_by_name(args[1]);
- if (svc) {
- parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
- return 0;
- }
-
- nargs -= 2;
- svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
if (!svc) {
- parse_error(state, "out of memory\n");
- return 0;
+ parse_error(state, "%s\n", ret_err.c_str());
}
- svc->name = strdup(args[1]);
- svc->classname = "default";
- memcpy(svc->args, args + 2, sizeof(char*) * nargs);
- svc->args[nargs] = 0;
- svc->nargs = nargs;
- svc->onrestart = new Action();
- svc->onrestart->InitSingleTrigger("onrestart");
- list_add_tail(&service_list, &svc->slist);
+
return svc;
}
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
- struct service *svc = (service*) state->context;
- int i, kw, kw_nargs;
- std::vector<std::string> str_args;
-
if (nargs == 0) {
return;
}
- svc->ioprio_class = IoSchedClass_NONE;
+ Service* svc = static_cast<Service*>(state->context);
+ int kw = lookup_keyword(args[0]);
+ std::vector<std::string> str_args(args, args + nargs);
+ std::string ret_err;
+ bool ret = svc->HandleLine(kw, str_args, &ret_err);
- kw = lookup_keyword(args[0]);
- switch (kw) {
- case K_class:
- if (nargs != 2) {
- parse_error(state, "class option requires a classname\n");
- } else {
- svc->classname = args[1];
- }
- break;
- case K_console:
- svc->flags |= SVC_CONSOLE;
- break;
- case K_disabled:
- svc->flags |= SVC_DISABLED;
- svc->flags |= SVC_RC_DISABLED;
- break;
- case K_ioprio:
- if (nargs != 3) {
- parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
- } else {
- svc->ioprio_pri = strtoul(args[2], 0, 8);
-
- if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
- parse_error(state, "priority value must be range 0 - 7\n");
- break;
- }
-
- if (!strcmp(args[1], "rt")) {
- svc->ioprio_class = IoSchedClass_RT;
- } else if (!strcmp(args[1], "be")) {
- svc->ioprio_class = IoSchedClass_BE;
- } else if (!strcmp(args[1], "idle")) {
- svc->ioprio_class = IoSchedClass_IDLE;
- } else {
- parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
- }
- }
- break;
- case K_group:
- if (nargs < 2) {
- parse_error(state, "group option requires a group id\n");
- } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
- parse_error(state, "group option accepts at most %d supp. groups\n",
- NR_SVC_SUPP_GIDS);
- } else {
- int n;
- svc->gid = decode_uid(args[1]);
- for (n = 2; n < nargs; n++) {
- svc->supp_gids[n-2] = decode_uid(args[n]);
- }
- svc->nr_supp_gids = n - 2;
- }
- break;
- case K_keycodes:
- if (nargs < 2) {
- parse_error(state, "keycodes option requires atleast one keycode\n");
- } else {
- svc->keycodes = (int*) malloc((nargs - 1) * sizeof(svc->keycodes[0]));
- if (!svc->keycodes) {
- parse_error(state, "could not allocate keycodes\n");
- } else {
- svc->nkeycodes = nargs - 1;
- for (i = 1; i < nargs; i++) {
- svc->keycodes[i - 1] = atoi(args[i]);
- }
- }
- }
- break;
- case K_oneshot:
- svc->flags |= SVC_ONESHOT;
- break;
- case K_onrestart:
- nargs--;
- args++;
- kw = lookup_keyword(args[0]);
- if (!kw_is(kw, COMMAND)) {
- parse_error(state, "invalid command '%s'\n", args[0]);
- break;
- }
- kw_nargs = kw_nargs(kw);
- if (nargs < kw_nargs) {
- parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
- kw_nargs > 2 ? "arguments" : "argument");
- break;
- }
- str_args.assign(args, args + nargs);
- svc->onrestart->AddCommand(kw_func(kw), str_args);
- break;
- case K_critical:
- svc->flags |= SVC_CRITICAL;
- break;
- case K_setenv: { /* name value */
- if (nargs < 3) {
- parse_error(state, "setenv option requires name and value arguments\n");
- break;
- }
- svcenvinfo* ei = (svcenvinfo*) calloc(1, sizeof(*ei));
- if (!ei) {
- parse_error(state, "out of memory\n");
- break;
- }
- ei->name = args[1];
- ei->value = args[2];
- ei->next = svc->envvars;
- svc->envvars = ei;
- break;
- }
- case K_socket: {/* name type perm [ uid gid context ] */
- if (nargs < 4) {
- parse_error(state, "socket option requires name, type, perm arguments\n");
- break;
- }
- if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
- && strcmp(args[2],"seqpacket")) {
- parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
- break;
- }
- socketinfo* si = (socketinfo*) calloc(1, sizeof(*si));
- if (!si) {
- parse_error(state, "out of memory\n");
- break;
- }
- si->name = args[1];
- si->type = args[2];
- si->perm = strtoul(args[3], 0, 8);
- if (nargs > 4)
- si->uid = decode_uid(args[4]);
- if (nargs > 5)
- si->gid = decode_uid(args[5]);
- if (nargs > 6)
- si->socketcon = args[6];
- si->next = svc->sockets;
- svc->sockets = si;
- break;
- }
- case K_user:
- if (nargs != 2) {
- parse_error(state, "user option requires a user id\n");
- } else {
- svc->uid = decode_uid(args[1]);
- }
- break;
- case K_seclabel:
- if (nargs != 2) {
- parse_error(state, "seclabel option requires a label string\n");
- } else {
- svc->seclabel = args[1];
- }
- break;
- case K_writepid:
- if (nargs < 2) {
- parse_error(state, "writepid option requires at least one filename\n");
- break;
- }
- svc->writepid_files_ = new std::vector<std::string>;
- for (int i = 1; i < nargs; ++i) {
- svc->writepid_files_->push_back(args[i]);
- }
- break;
-
- default:
- parse_error(state, "invalid option '%s'\n", args[0]);
+ if (!ret) {
+ parse_error(state, "%s\n", ret_err.c_str());
}
}
@@ -792,28 +453,42 @@
return ret;
}
+bool add_command_to_action(Action* action, const std::vector<std::string>& args,
+ const std::string& filename, int line, std::string* err)
+{
+ int kw;
+ size_t n;
+
+ kw = lookup_keyword(args[0].c_str());
+ if (!kw_is(kw, COMMAND)) {
+ *err = android::base::StringPrintf("invalid command '%s'\n", args[0].c_str());
+ return false;
+ }
+
+ n = kw_nargs(kw);
+ if (args.size() < n) {
+ *err = android::base::StringPrintf("%s requires %zu %s\n",
+ args[0].c_str(), n - 1,
+ n > 2 ? "arguments" : "argument");
+ return false;
+ }
+
+ action->AddCommand(kw_func(kw), args, filename, line);
+ return true;
+}
+
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
- Action* act = (Action*) state->context;
- int kw, n;
-
if (nargs == 0) {
return;
}
- kw = lookup_keyword(args[0]);
- if (!kw_is(kw, COMMAND)) {
- parse_error(state, "invalid command '%s'\n", args[0]);
- return;
- }
-
- n = kw_nargs(kw);
- if (nargs < n) {
- parse_error(state, "%s requires %d %s\n", args[0], n - 1,
- n > 2 ? "arguments" : "argument");
- return;
- }
-
+ Action* action = static_cast<Action*>(state->context);
std::vector<std::string> str_args(args, args + nargs);
- act->AddCommand(kw_func(kw), str_args, state->filename, state->line);
+ std::string ret_err;
+ bool ret = add_command_to_action(action, str_args, state->filename,
+ state->line, &ret_err);
+ if (!ret) {
+ parse_error(state, "%s\n", ret_err.c_str());
+ }
}